Compare commits

..

80 Commits

Author SHA1 Message Date
Alex Forencich
1fe508a6bf Update readme
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-04-06 23:59:16 -07:00
Alex Forencich
2ae6e22c2c cndm: Add support for Napatech NT200A01/NT200A02
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-04-06 23:58:50 -07:00
Alex Forencich
cf9c5d5ff3 eth: Fix NT200A01/NT200A02 XDC
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-04-06 19:31:04 -07:00
Alex Forencich
fb9757106d cndm: Clean up multiple quad handling
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-04-05 18:36:55 -07:00
Alex Forencich
bbe4353c3a eth: Fix Alveo example design UART handling
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-04-05 18:26:53 -07:00
Alex Forencich
9e39b00d51 eth: Clean up multiple quad handling in Ethernet example designs
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-04-05 17:35:38 -07:00
Alex Forencich
293932b1c5 eth: Add Ethernet example design for Napatech NT200A01/NT200A02
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-04-05 17:28:07 -07:00
Alex Forencich
4f0c8e74fa eth: Add Ethernet example design for Napatech NT20E3/NT40E3
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-04-03 17:23:54 -07:00
Alex Forencich
32ed8d68a3 Update readme
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-04-02 23:13:26 -07:00
Alex Forencich
5a066e87b8 cndm: Initial commit of DPDK PMD
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-04-02 23:03:07 -07:00
Alex Forencich
ae69d16b93 cndm: Fix some allocation failure handling paths
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-31 20:27:27 -07:00
Alex Forencich
924f41c0ff cndm: Fix bug in datapath manager state progression
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-31 20:25:36 -07:00
Alex Forencich
5b14329483 axi: Clean up user signal width handling in AXI RAM IF modules
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-20 00:06:23 -07:00
Alex Forencich
a94460c7a7 cndm: Add missing file
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-19 23:26:57 -07:00
Alex Forencich
7440fb9446 cndm: Add ifdefs for NAPI
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-19 23:25:43 -07:00
Alex Forencich
7d4f66b2ec cndm: Add missing include
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-19 23:25:03 -07:00
Alex Forencich
81e91a95e5 apb: Update APB interconnect to support arbitration between multiple upstream devices
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-19 22:05:27 -07:00
Alex Forencich
fa66a26636 apb: Fix parameter comments
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-19 20:34:47 -07:00
Alex Forencich
7ad7cf6878 axi: Fix parameter comments
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-19 20:34:27 -07:00
Alex Forencich
2cf9112092 cndm: Use APB 1S interconnect
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-19 19:17:16 -07:00
Alex Forencich
c51d3999ab pyrite: Use APB 1S interconnect
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-19 19:15:14 -07:00
Alex Forencich
00a0f56c56 eth: Use APB 1S interconnect
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-19 19:12:52 -07:00
Alex Forencich
933ebcadb3 apb: Copy APB interconnect as APB interconnect 1S
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-19 19:09:38 -07:00
Alex Forencich
5652bb0016 axi: Add AXI RAM interface and AXI dual port RAM
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-19 18:12:37 -07:00
Alex Forencich
9a352ae302 eth: Update XDC
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 21:27:08 -07:00
Alex Forencich
93fd966e6e cndm_proto: Update XDC
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 21:26:56 -07:00
Alex Forencich
1d0b06e7f7 cndm: Add board control logic to AS02MC04
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 21:25:44 -07:00
Alex Forencich
6883aa4956 cndm: Add support for writing board EEPROM from ethtool
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 20:19:34 -07:00
Alex Forencich
c40d4c8e16 cndm: Do not print empty serial number
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 20:18:51 -07:00
Alex Forencich
9bcaa2a9d3 cndm: Strip non-printable characters from serial number
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 18:45:49 -07:00
Alex Forencich
1e4e71bcc3 cndm: Do not change select lines while I2C master is running
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 16:59:27 -07:00
Alex Forencich
17e61c06f6 cndm: Update testbench parameters
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 16:58:49 -07:00
Alex Forencich
72b0521147 cndm: I2C IO constraints on RK-XCKU5P-F
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 13:44:43 -07:00
Alex Forencich
b8afd7ae90 cndm: Add support for reading device EEPROM and optical module EEPROMs via ethtool
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 13:33:46 -07:00
Alex Forencich
76f23fe9d1 cndm: Add support for reading hardware IDs
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 13:32:42 -07:00
Alex Forencich
378f1d34ec cndm: Do not report timestamping support when PTP clock is not present
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 13:31:46 -07:00
Alex Forencich
cb2a7af632 cndm: Add page select delay to board control logic
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 13:25:19 -07:00
Alex Forencich
bc3d0f0825 cndm: Add board control logic to RK-XCKU5P-F
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 12:39:48 -07:00
Alex Forencich
d3f6e4e76c cndm: Set TBUF_CYC in board control logic
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 12:33:33 -07:00
Alex Forencich
4b90b35b4c lss: Add tBUF setting to I2C master to insert bus idle time before starts and repeated starts
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 12:30:11 -07:00
Alex Forencich
d268e6d27a cndm: Send I2C stop instead of repeated start after setting bank and page registers
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 00:51:07 -07:00
Alex Forencich
582daf7da0 cndm: Fix device select handling
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 00:50:02 -07:00
Alex Forencich
d34fc20870 cndm: Fix parametrization when DEV_CNT is 1
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-18 00:49:40 -07:00
Alex Forencich
b3f9b899cb cndm: Add board control logic to KCU105
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-17 17:49:47 -07:00
Alex Forencich
f69e6a8c12 cndm: Implement command status codes and error handling
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-17 17:41:08 -07:00
Alex Forencich
5e63669ba1 axi: Fix typo
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-17 15:17:07 -07:00
Alex Forencich
249cfaa1ea cndm: Update boards
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-17 15:00:47 -07:00
Alex Forencich
cc888b2cca cndm: Add support to core logic for board control logic
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-17 14:32:15 -07:00
Alex Forencich
d9cf440351 cndm: Initial commit of board control I2C logic
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-17 14:06:55 -07:00
Alex Forencich
033d961906 cndm: Report firmware information via devlink APIs
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-17 11:07:00 -07:00
Alex Forencich
33170b2bb1 cndm: Report firmware version via ethtool APIs
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-17 10:57:38 -07:00
Alex Forencich
1825650f96 cndm: Add missing parameter connection
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-16 17:14:33 -07:00
Alex Forencich
fd9cb00a9d lss: Fix I2C master clock period
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-16 17:13:44 -07:00
Alex Forencich
89b47d0659 axi: When tying AXI interfaces, permit widening the ID signals
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-15 16:13:08 -07:00
Alex Forencich
87bc96e3fd apb: Add APB tie module
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-15 16:02:34 -07:00
Alex Forencich
446dc19fc6 axi: When tying AXI interfaces, permit narrowing the address bus
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-15 16:01:53 -07:00
Alex Forencich
7a9e9f3370 eth: Update KC705 pins
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-13 19:51:27 -07:00
Alex Forencich
29fadb6b16 cndm: Update KCU105 pins
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-13 19:47:00 -07:00
Alex Forencich
c280dd3da3 eth: Update KCU105 pins
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-13 19:44:48 -07:00
Alex Forencich
8bc90d0627 eth: Remove extra APB idle cycles
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-13 01:24:06 -07:00
Alex Forencich
dc262cc4c4 xfcp: Fix APB implementation
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-13 01:23:31 -07:00
Alex Forencich
23279469c9 cndm: Add support for DNPCIe-40G-KU-LL-2QSFP
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-13 00:21:58 -07:00
Alex Forencich
0364fce4f9 cndm: Add PTP TD leaf clocks to testbenches to provide MAC models with time reference
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-12 22:27:53 -07:00
Alex Forencich
0d48b71c26 cndm: Improve parametrization
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-12 21:48:05 -07:00
Alex Forencich
57fbdd39ba cndm: Support multiple slots for parallel descriptor reads
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-12 20:23:56 -07:00
Alex Forencich
c68bb2d38f cndm: Remove extra APB idle cycles
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-12 16:59:01 -07:00
Alex Forencich
615e90e16d ptp: Remove extra APB idle cycles
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-12 16:57:34 -07:00
Alex Forencich
72d8f1219e pcie: Remove extra APB idle cycles
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-12 16:57:22 -07:00
Alex Forencich
d1b5b4444a axi: Fix AXI lite to APB adapter
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-12 16:43:02 -07:00
Alex Forencich
f5b7eb272d apb: Remove extra idle cycles
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-12 15:35:03 -07:00
Alex Forencich
d799cddaa5 ci: Update cocotbext-axi
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-12 15:31:08 -07:00
Alex Forencich
5c2069bbe4 axi: Run stress tests with idles and backpressure
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-12 14:48:04 -07:00
Alex Forencich
960ba06652 apb: Run stress tests with idles and backpressure
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-12 14:43:59 -07:00
Alex Forencich
51e731da30 ci: Update actions
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-12 13:11:00 -07:00
Alex Forencich
cd5da36581 lss: Fix some handshaking bugs in I2C master module
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-12 01:08:02 -07:00
Alex Forencich
7a12540f26 cndm: Use AXIL crossbar in cndm-lite
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-11 13:43:23 -07:00
Alex Forencich
bb9d4b90ec cndm: Add support for KCU105
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-11 02:29:32 -07:00
Alex Forencich
155fac5e07 cndm: Add register to RC path from PCIe HIP to improve timing performance
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-11 02:23:13 -07:00
Alex Forencich
dda53624b5 cndm: Fix CQ deinit ordering
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-11 01:53:05 -07:00
Alex Forencich
6e640c71b9 cndm: Use state machine in queue state module to improve timing performance
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-11 01:50:54 -07:00
257 changed files with 33296 additions and 1017 deletions

View File

@@ -16,7 +16,7 @@ jobs:
run: df -h run: df -h
- name: Check out repository - name: Check out repository
uses: actions/checkout@v3 uses: actions/checkout@v6
- name: Install Verilator - name: Install Verilator
uses: v0xnihili/install-verilator-action@main uses: v0xnihili/install-verilator-action@main

View File

@@ -24,7 +24,7 @@ To facilitate the dual-license model, contributions to the project can only be a
## Corundum NIC ## Corundum NIC
Corundum is an open-source, high-performance FPGA-based NIC and platform for in-network compute. Features include a high performance datapath, 10G/25G/100G Ethernet, PCI express gen 3+, a custom, high performance, tightly-integrated PCIe DMA engine, many (1000+) transmit, receive, completion, and event queues, scatter/gather DMA, MSI/MSI-X interrupts, per-port transmit scheduling, flow hashing, RSS, checksum offloading, and native IEEE 1588 PTP timestamping. A Linux driver is included that integrates with the Linux networking stack. Development and debugging is facilitated by an extensive simulation framework that covers the entire system from a simulation model of the driver and PCI express interface on the host side and Ethernet interfaces on the network side. Corundum is an open-source, high-performance FPGA-based NIC and platform for in-network compute. Features include a high performance datapath, 10G/25G/100G Ethernet, PCI express gen 3+, a custom, high performance, tightly-integrated PCIe DMA engine, many (1000+) transmit, receive, completion, and event queues, scatter/gather DMA, MSI/MSI-X interrupts, per-port transmit scheduling, flow hashing, RSS, checksum offloading, and native IEEE 1588 PTP timestamping. A Linux driver is included that integrates with the Linux networking stack, as well as a DPDK PMD. Development and debugging is facilitated by an extensive simulation framework that covers the entire system from a simulation model of the driver and PCI express interface on the host side and Ethernet interfaces on the network side.
Several variants of Corundum are planned, sharing the same host interface and device driver but targeting different optimization points: Several variants of Corundum are planned, sharing the same host interface and device driver but targeting different optimization points:
@@ -33,7 +33,7 @@ Several variants of Corundum are planned, sharing the same host interface and de
* corundum-ng: intended for high-performance packet processing with deep pipelines and segmented internal interfaces, supporting operation at up to 400 Gbps aggregate * corundum-ng: intended for high-performance packet processing with deep pipelines and segmented internal interfaces, supporting operation at up to 400 Gbps aggregate
* corundum-proto: simplified design with simplified driver, intended for educational purposes only * corundum-proto: simplified design with simplified driver, intended for educational purposes only
Planned features include a DPDK driver, SR-IOV, AF_XDP, white rabbit/IEEE 1588 HA, and Zircon stack integration. Planned features include SR-IOV, AF_XDP, white rabbit/IEEE 1588 HA, and Zircon stack integration.
Note that Corundum is still under active development and may not ready for production use; additional functionality and improvements to performance and flexibility will be made over time. Note that Corundum is still under active development and may not ready for production use; additional functionality and improvements to performance and flexibility will be made over time.
@@ -91,6 +91,8 @@ The Taxi transport library contains many smaller components that can be composed
* Width converter * Width converter
* Synchronous FIFO * Synchronous FIFO
* Single-port RAM * Single-port RAM
* Dual-port RAM
* RAM interface
* AXI lite * AXI lite
* SV interface for AXI lite * SV interface for AXI lite
* AXI lite to AXI adapter * AXI lite to AXI adapter
@@ -230,6 +232,10 @@ Example designs are provided for several different FPGA boards, showcasing many
* HiTech Global HTG-ZRF8-R2 (Xilinx Zynq UltraScale+ RFSoC XCZU28DR/XCZU48DR) * HiTech Global HTG-ZRF8-R2 (Xilinx Zynq UltraScale+ RFSoC XCZU28DR/XCZU48DR)
* HiTech Global HTG-ZRF8-EM (Xilinx Zynq UltraScale+ RFSoC XCZU28DR/XCZU48DR) * HiTech Global HTG-ZRF8-EM (Xilinx Zynq UltraScale+ RFSoC XCZU28DR/XCZU48DR)
* Opal Kelley XEM8320 (Xilinx Artix UltraScale+ XCAU25P) * Opal Kelley XEM8320 (Xilinx Artix UltraScale+ XCAU25P)
* Napatech NT20E3 (Xilinx Virtex 7 XC7V330T)
* Napatech NT40E3 (Xilinx Virtex 7 XC7V330T)
* Napatech NT200A01 (Xilinx Virtex UltraScale XCVU095)
* Napatech NT200A02 (Xilinx Virtex UltraScale+ XCVU5P)
* Silicom fb2CG@KU15P (Xilinx Kintex UltraScale+ XCKU15P) * Silicom fb2CG@KU15P (Xilinx Kintex UltraScale+ XCKU15P)
* Xilinx Alveo U45N/SN1000 (Xilinx Virtex UltraScale+ XCU26) * Xilinx Alveo U45N/SN1000 (Xilinx Virtex UltraScale+ XCU26)
* Xilinx Alveo U50 (Xilinx Virtex UltraScale+ XCU50) * Xilinx Alveo U50 (Xilinx Virtex UltraScale+ XCU50)

View File

@@ -162,7 +162,7 @@ end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize
m_apb_pauser_next = s_apb.pauser; m_apb_pauser_next = s_apb.pauser;
m_apb_pwuser_next = s_apb.pwuser; m_apb_pwuser_next = s_apb.pwuser;
if (s_apb.psel && s_apb.penable && !s_apb.pready) begin if (s_apb.psel && !s_apb.pready) begin
m_apb_psel_next = 1'b1; m_apb_psel_next = 1'b1;
state_next = STATE_DATA; state_next = STATE_DATA;
end else begin end else begin
@@ -317,7 +317,7 @@ end else begin : downsize
s_apb_pslverr_next = 1'b0; s_apb_pslverr_next = 1'b0;
if (s_apb.psel && s_apb.penable && !s_apb.pready) begin if (s_apb.psel && !s_apb.pready) begin
m_apb_psel_next = 1'b1; m_apb_psel_next = 1'b1;
state_next = STATE_DATA; state_next = STATE_DATA;
end else begin end else begin

View File

@@ -168,7 +168,7 @@ if (AXIL_BYTE_LANES == APB_BYTE_LANES) begin : bypass
m_axil_auser_next = s_apb.pauser; m_axil_auser_next = s_apb.pauser;
m_axil_wuser_next = s_apb.pwuser; m_axil_wuser_next = s_apb.pwuser;
if (s_apb.psel && s_apb.penable && !s_apb.pready) begin if (s_apb.psel && !s_apb.pready) begin
if (s_apb.pwrite) begin if (s_apb.pwrite) begin
m_axil_awvalid_next = 1'b1; m_axil_awvalid_next = 1'b1;
m_axil_wvalid_next = 1'b1; m_axil_wvalid_next = 1'b1;
@@ -322,7 +322,7 @@ end else if (AXIL_BYTE_LANES > APB_BYTE_LANES) begin : upsize
m_axil_auser_next = s_apb.pauser; m_axil_auser_next = s_apb.pauser;
m_axil_wuser_next = s_apb.pwuser; m_axil_wuser_next = s_apb.pwuser;
if (s_apb.psel && s_apb.penable && !s_apb.pready) begin if (s_apb.psel && !s_apb.pready) begin
if (s_apb.pwrite) begin if (s_apb.pwrite) begin
m_axil_awvalid_next = 1'b1; m_axil_awvalid_next = 1'b1;
m_axil_wvalid_next = 1'b1; m_axil_wvalid_next = 1'b1;
@@ -501,7 +501,7 @@ end else begin : downsize
s_apb_pslverr_next = 1'b0; s_apb_pslverr_next = 1'b0;
if (s_apb.psel && s_apb.penable && !s_apb.pready) begin if (s_apb.psel && !s_apb.pready) begin
if (s_apb.pwrite) begin if (s_apb.pwrite) begin
m_axil_awvalid_next = 1'b1; m_axil_awvalid_next = 1'b1;
m_axil_wvalid_next = 1'b1; m_axil_wvalid_next = 1'b1;

View File

@@ -101,7 +101,7 @@ always_comb begin
s_apb_a_pready_next = 1'b0; s_apb_a_pready_next = 1'b0;
if (s_apb_a.psel && s_apb_a.penable && (!s_apb_a_pready_reg && (PIPELINE_OUTPUT || !s_apb_a_pready_pipe_reg))) begin if (s_apb_a.psel && (!s_apb_a_pready_reg && (PIPELINE_OUTPUT || !s_apb_a_pready_pipe_reg))) begin
s_apb_a_pready_next = 1'b1; s_apb_a_pready_next = 1'b1;
if (s_apb_a.pwrite) begin if (s_apb_a.pwrite) begin
@@ -139,7 +139,7 @@ always_comb begin
s_apb_b_pready_next = 1'b0; s_apb_b_pready_next = 1'b0;
if (s_apb_b.psel && s_apb_b.penable && (!s_apb_b_pready_reg && (PIPELINE_OUTPUT || !s_apb_b_pready_pipe_reg))) begin if (s_apb_b.psel && (!s_apb_b_pready_reg && (PIPELINE_OUTPUT || !s_apb_b_pready_pipe_reg))) begin
s_apb_b_pready_next = 1'b1; s_apb_b_pready_next = 1'b1;
if (s_apb_b.pwrite) begin if (s_apb_b.pwrite) begin

View File

@@ -0,0 +1,4 @@
taxi_apb_interconnect.sv
taxi_apb_if.sv
../lib/taxi/src/prim/rtl/taxi_arbiter.sv
../lib/taxi/src/prim/rtl/taxi_penc.sv

View File

@@ -17,6 +17,8 @@ Authors:
*/ */
module taxi_apb_interconnect # module taxi_apb_interconnect #
( (
// Number of upstream APB interfaces
parameter S_CNT = 4,
// Number of downstream APB interfaces // Number of downstream APB interfaces
parameter M_CNT = 4, parameter M_CNT = 4,
// Width of address decoder in bits // Width of address decoder in bits
@@ -31,7 +33,13 @@ module taxi_apb_interconnect #
// Master interface address widths // Master interface address widths
// M_CNT concatenated fields of M_REGIONS concatenated fields of 32 bits // M_CNT concatenated fields of M_REGIONS concatenated fields of 32 bits
parameter M_ADDR_W = {M_CNT{{M_REGIONS{32'd24}}}}, parameter M_ADDR_W = {M_CNT{{M_REGIONS{32'd24}}}},
// Secure master (fail operations based on awprot/arprot) // Read connections between interfaces
// M_CNT concatenated fields of S_CNT bits
parameter M_CONNECT_RD = {M_CNT{{S_CNT{1'b1}}}},
// Write connections between interfaces
// M_CNT concatenated fields of S_CNT bits
parameter M_CONNECT_WR = {M_CNT{{S_CNT{1'b1}}}},
// Secure master (fail operations based on pprot)
// M_CNT bits // M_CNT bits
parameter M_SECURE = {M_CNT{1'b0}} parameter M_SECURE = {M_CNT{1'b0}}
) )
@@ -42,7 +50,7 @@ module taxi_apb_interconnect #
/* /*
* APB slave interface * APB slave interface
*/ */
taxi_apb_if.slv s_apb, taxi_apb_if.slv s_apb[S_CNT],
/* /*
* APB master interface * APB master interface
@@ -51,24 +59,29 @@ module taxi_apb_interconnect #
); );
// extract parameters // extract parameters
localparam DATA_W = s_apb.DATA_W; localparam DATA_W = s_apb[0].DATA_W;
localparam S_ADDR_W = s_apb.ADDR_W; localparam S_ADDR_W = s_apb[0].ADDR_W;
localparam STRB_W = s_apb.STRB_W; localparam STRB_W = s_apb[0].STRB_W;
localparam logic PAUSER_EN = s_apb.PAUSER_EN && m_apb[0].PAUSER_EN; localparam logic PAUSER_EN = s_apb[0].PAUSER_EN && m_apb[0].PAUSER_EN;
localparam PAUSER_W = s_apb.PAUSER_W; localparam PAUSER_W = s_apb[0].PAUSER_W;
localparam logic PWUSER_EN = s_apb.PWUSER_EN && m_apb[0].PWUSER_EN; localparam logic PWUSER_EN = s_apb[0].PWUSER_EN && m_apb[0].PWUSER_EN;
localparam PWUSER_W = s_apb.PWUSER_W; localparam PWUSER_W = s_apb[0].PWUSER_W;
localparam logic PRUSER_EN = s_apb.PRUSER_EN && m_apb[0].PRUSER_EN; localparam logic PRUSER_EN = s_apb[0].PRUSER_EN && m_apb[0].PRUSER_EN;
localparam PRUSER_W = s_apb.PRUSER_W; localparam PRUSER_W = s_apb[0].PRUSER_W;
localparam logic PBUSER_EN = s_apb.PBUSER_EN && m_apb[0].PBUSER_EN; localparam logic PBUSER_EN = s_apb[0].PBUSER_EN && m_apb[0].PBUSER_EN;
localparam PBUSER_W = s_apb.PBUSER_W; localparam PBUSER_W = s_apb[0].PBUSER_W;
localparam APB_M_ADDR_W = m_apb[0].ADDR_W; localparam APB_M_ADDR_W = m_apb[0].ADDR_W;
localparam CL_S_CNT = $clog2(S_CNT);
localparam CL_S_CNT_INT = CL_S_CNT > 0 ? CL_S_CNT : 1;
localparam CL_M_CNT = $clog2(M_CNT); localparam CL_M_CNT = $clog2(M_CNT);
localparam CL_M_CNT_INT = CL_M_CNT > 0 ? CL_M_CNT : 1; localparam CL_M_CNT_INT = CL_M_CNT > 0 ? CL_M_CNT : 1;
localparam [M_CNT*M_REGIONS-1:0][31:0] M_ADDR_W_INT = M_ADDR_W; localparam [M_CNT*M_REGIONS-1:0][31:0] M_ADDR_W_INT = M_ADDR_W;
localparam [M_CNT-1:0][S_CNT-1:0] M_CONNECT_RD_INT = M_CONNECT_RD;
localparam [M_CNT-1:0][S_CNT-1:0] M_CONNECT_WR_INT = M_CONNECT_WR;
localparam [M_CNT-1:0] M_SECURE_INT = M_SECURE; localparam [M_CNT-1:0] M_SECURE_INT = M_SECURE;
// default address computation // default address computation
@@ -98,7 +111,7 @@ endfunction
localparam [M_CNT*M_REGIONS-1:0][ADDR_W-1:0] M_BASE_ADDR_INT = M_BASE_ADDR != 0 ? (M_CNT*M_REGIONS*ADDR_W)'(M_BASE_ADDR) : calcBaseAddrs(0); localparam [M_CNT*M_REGIONS-1:0][ADDR_W-1:0] M_BASE_ADDR_INT = M_BASE_ADDR != 0 ? (M_CNT*M_REGIONS*ADDR_W)'(M_BASE_ADDR) : calcBaseAddrs(0);
// check configuration // check configuration
if (s_apb.ADDR_W != ADDR_W) if (s_apb[0].ADDR_W != ADDR_W)
$fatal(0, "Error: Interface ADDR_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface ADDR_W parameter mismatch (instance %m)");
if (m_apb[0].DATA_W != DATA_W) if (m_apb[0].DATA_W != DATA_W)
@@ -173,24 +186,44 @@ initial begin
end end
end end
logic [CL_M_CNT_INT-1:0] sel_reg = '0; typedef enum logic [1:0] {
logic act_reg = 1'b0; STATE_IDLE,
STATE_DECODE,
STATE_READ
} state_t;
logic s_apb_pready_reg = 1'b0; state_t state_reg = STATE_IDLE, state_next;
logic [DATA_W-1:0] s_apb_prdata_reg = '0;
logic s_apb_pslverr_reg = 1'b0;
logic [PRUSER_W-1:0] s_apb_pruser_reg = '0;
logic [PBUSER_W-1:0] s_apb_pbuser_reg = '0;
logic [ADDR_W-1:0] m_apb_paddr_reg = '0; logic match;
logic [2:0] m_apb_pprot_reg = '0;
logic [M_CNT-1:0] m_apb_psel_reg = '0; logic [CL_M_CNT_INT-1:0] m_sel_reg = '0, m_sel_next;
logic m_apb_penable_reg = 1'b0;
logic m_apb_pwrite_reg = 1'b0; logic [S_CNT-1:0] s_apb_pready_reg = '0, s_apb_pready_next;
logic [DATA_W-1:0] m_apb_pwdata_reg = '0; logic [DATA_W-1:0] s_apb_prdata_reg = '0, s_apb_prdata_next;
logic [STRB_W-1:0] m_apb_pstrb_reg = '0; logic s_apb_pslverr_reg = 1'b0, s_apb_pslverr_next;
logic [PAUSER_W-1:0] m_apb_pauser_reg = '0; logic [PRUSER_W-1:0] s_apb_pruser_reg = '0, s_apb_pruser_next;
logic [PWUSER_W-1:0] m_apb_pwuser_reg = '0; logic [PBUSER_W-1:0] s_apb_pbuser_reg = '0, s_apb_pbuser_next;
logic [ADDR_W-1:0] m_apb_paddr_reg = '0, m_apb_paddr_next;
logic [2:0] m_apb_pprot_reg = '0, m_apb_pprot_next;
logic [M_CNT-1:0] m_apb_psel_reg = '0, m_apb_psel_next;
logic m_apb_penable_reg = 1'b0, m_apb_penable_next;
logic m_apb_pwrite_reg = 1'b0, m_apb_pwrite_next;
logic [DATA_W-1:0] m_apb_pwdata_reg = '0, m_apb_pwdata_next;
logic [STRB_W-1:0] m_apb_pstrb_reg = '0, m_apb_pstrb_next;
logic [PAUSER_W-1:0] m_apb_pauser_reg = '0, m_apb_pauser_next;
logic [PWUSER_W-1:0] m_apb_pwuser_reg = '0, m_apb_pwuser_next;
// unpack interface array
wire [ADDR_W-1:0] s_apb_paddr[S_CNT];
wire [2:0] s_apb_pprot[S_CNT];
wire [S_CNT-1:0] s_apb_psel;
wire s_apb_penable[S_CNT];
wire s_apb_pwrite[S_CNT];
wire [DATA_W-1:0] s_apb_pwdata[S_CNT];
wire [STRB_W-1:0] s_apb_pstrb[S_CNT];
wire [PAUSER_W-1:0] s_apb_pauser[S_CNT];
wire [PWUSER_W-1:0] s_apb_pwuser[S_CNT];
wire [M_CNT-1:0] m_apb_pready; wire [M_CNT-1:0] m_apb_pready;
wire [DATA_W-1:0] m_apb_prdata[M_CNT]; wire [DATA_W-1:0] m_apb_prdata[M_CNT];
@@ -198,13 +231,24 @@ wire m_apb_pslverr[M_CNT];
wire [PRUSER_W-1:0] m_apb_pruser[M_CNT]; wire [PRUSER_W-1:0] m_apb_pruser[M_CNT];
wire [PBUSER_W-1:0] m_apb_pbuser[M_CNT]; wire [PBUSER_W-1:0] m_apb_pbuser[M_CNT];
assign s_apb.pready = s_apb_pready_reg; for (genvar n = 0; n < S_CNT; n = n + 1) begin
assign s_apb.prdata = s_apb_prdata_reg; assign s_apb_paddr[n] = s_apb[n].paddr;
assign s_apb.pslverr = s_apb_pslverr_reg; assign s_apb_pprot[n] = s_apb[n].pprot;
assign s_apb.pruser = PRUSER_EN ? s_apb_pruser_reg : '0; assign s_apb_psel[n] = s_apb[n].psel;
assign s_apb.pbuser = PBUSER_EN ? s_apb_pbuser_reg : '0; assign s_apb_penable[n] = s_apb[n].penable;
assign s_apb_pwrite[n] = s_apb[n].pwrite;
assign s_apb_pwdata[n] = s_apb[n].pwdata;
assign s_apb_pstrb[n] = s_apb[n].pstrb;
assign s_apb[n].pready = s_apb_pready_reg[n];
assign s_apb[n].prdata = s_apb_prdata_reg;
assign s_apb[n].pslverr = s_apb_pslverr_reg;
assign s_apb_pauser[n] = s_apb[n].pauser;
assign s_apb_pwuser[n] = s_apb[n].pwuser;
assign s_apb[n].pruser = PRUSER_EN ? s_apb_pruser_reg : '0;
assign s_apb[n].pbuser = PBUSER_EN ? s_apb_pbuser_reg : '0;
end
for (genvar n = 0; n < M_CNT; n += 1) begin for (genvar n = 0; n < M_CNT; n = n + 1) begin
assign m_apb[n].paddr = APB_M_ADDR_W'(m_apb_paddr_reg); assign m_apb[n].paddr = APB_M_ADDR_W'(m_apb_paddr_reg);
assign m_apb[n].pprot = m_apb_pprot_reg; assign m_apb[n].pprot = m_apb_pprot_reg;
assign m_apb[n].psel = m_apb_psel_reg[n]; assign m_apb[n].psel = m_apb_psel_reg[n];
@@ -221,50 +265,195 @@ for (genvar n = 0; n < M_CNT; n += 1) begin
assign m_apb_pbuser[n] = m_apb[n].pbuser; assign m_apb_pbuser[n] = m_apb[n].pbuser;
end end
always_ff @(posedge clk) begin // slave side mux
s_apb_pready_reg <= 1'b0; wire [CL_S_CNT_INT-1:0] s_sel;
m_apb_penable_reg <= act_reg && s_apb.penable;
s_apb_prdata_reg <= m_apb_prdata[sel_reg]; wire [ADDR_W-1:0] cur_s_apb_paddr = s_apb_paddr[s_sel];
s_apb_pslverr_reg <= m_apb_pslverr[sel_reg] | (m_apb_psel_reg == 0); wire [2:0] cur_s_apb_pprot = s_apb_pprot[s_sel];
s_apb_pruser_reg <= m_apb_pruser[sel_reg]; wire cur_s_apb_psel = s_apb_psel[s_sel];
s_apb_pbuser_reg <= m_apb_pbuser[sel_reg]; wire cur_s_apb_penable = s_apb_penable[s_sel];
wire cur_s_apb_pwrite = s_apb_pwrite[s_sel];
wire [DATA_W-1:0] cur_s_apb_pwdata = s_apb_pwdata[s_sel];
wire [STRB_W-1:0] cur_s_apb_pstrb = s_apb_pstrb[s_sel];
wire [PAUSER_W-1:0] cur_s_apb_pauser = s_apb_pauser[s_sel];
wire [PWUSER_W-1:0] cur_s_apb_pwuser = s_apb_pwuser[s_sel];
if ((m_apb_psel_reg & ~m_apb_pready) == 0) begin // master side mux
m_apb_psel_reg <= '0; wire cur_m_apb_pready = m_apb_pready[m_sel_reg];
m_apb_penable_reg <= 1'b0; wire [DATA_W-1:0] cur_m_apb_prdata = m_apb_prdata[m_sel_reg];
s_apb_pready_reg <= act_reg; wire cur_m_apb_pslverr = m_apb_pslverr[m_sel_reg];
act_reg <= 1'b0; wire [PRUSER_W-1:0] cur_m_apb_pruser = m_apb_pruser[m_sel_reg];
end wire [PBUSER_W-1:0] cur_m_apb_pbuser = m_apb_pbuser[m_sel_reg];
if (!act_reg) begin // arbiter instance
m_apb_paddr_reg <= s_apb.paddr; wire [S_CNT-1:0] req;
m_apb_pprot_reg <= s_apb.pprot; wire [S_CNT-1:0] ack;
m_apb_pwrite_reg <= s_apb.pwrite; wire [S_CNT-1:0] grant;
m_apb_pwdata_reg <= s_apb.pwdata; wire grant_valid;
m_apb_pstrb_reg <= s_apb.pstrb; wire [CL_S_CNT_INT-1:0] grant_index;
m_apb_pauser_reg <= s_apb.pauser;
m_apb_pwuser_reg <= s_apb.pwuser;
m_apb_psel_reg <= '0; assign s_sel = grant_index;
m_apb_penable_reg <= 1'b0;
if (s_apb.psel && s_apb.penable && !s_apb_pready_reg) begin if (S_CNT > 1) begin : arb
act_reg <= 1'b1;
for (integer i = 0; i < M_CNT; i = i + 1) begin taxi_arbiter #(
for (integer j = 0; j < M_REGIONS; j = j + 1) begin .PORTS(S_CNT),
if (M_ADDR_W_INT[i*M_REGIONS+j] != 0 && (!M_SECURE_INT[i] || !s_apb.pprot[1]) && (s_apb.paddr >> M_ADDR_W_INT[i*M_REGIONS+j]) == (M_BASE_ADDR_INT[i*M_REGIONS+j] >> M_ADDR_W_INT[i*M_REGIONS+j])) begin .ARB_ROUND_ROBIN(1),
sel_reg <= CL_M_CNT_INT'(i); .ARB_BLOCK(1),
m_apb_psel_reg[i] <= 1'b1; .ARB_BLOCK_ACK(1),
end .LSB_HIGH_PRIO(1)
end )
end arb_inst (
.clk(clk),
.rst(rst),
.req(req),
.ack(ack),
.grant(grant),
.grant_valid(grant_valid),
.grant_index(grant_index)
);
end else begin
logic grant_valid_reg = 1'b0;
always @(posedge clk) begin
if (req) begin
grant_valid_reg <= 1'b1;
end
if (ack || rst) begin
grant_valid_reg <= 1'b0;
end end
end end
assign grant_valid = grant_valid_reg;
assign grant = grant_valid_reg;
assign grant_index = '0;
end
// req generation
assign req = s_apb_psel & ~grant;
assign ack = s_apb_pready_reg;
always_comb begin
state_next = STATE_IDLE;
match = 1'b0;
m_sel_next = m_sel_reg;
s_apb_pready_next = '0;
s_apb_prdata_next = cur_m_apb_prdata;
s_apb_pslverr_next = cur_m_apb_pslverr;
s_apb_pruser_next = cur_m_apb_pruser;
s_apb_pbuser_next = cur_m_apb_pbuser;
m_apb_paddr_next = cur_s_apb_paddr;
m_apb_pprot_next = cur_s_apb_pprot;
m_apb_psel_next = '0;
m_apb_penable_next = 1'b0;
m_apb_pwrite_next = cur_s_apb_pwrite;
m_apb_pwdata_next = cur_s_apb_pwdata;
m_apb_pstrb_next = cur_s_apb_pstrb;
m_apb_pauser_next = cur_s_apb_pauser;
m_apb_pwuser_next = cur_s_apb_pwuser;
case (state_reg)
STATE_IDLE: begin
// idle state; wait for arbitration
m_apb_paddr_next = cur_s_apb_paddr;
m_apb_pprot_next = cur_s_apb_pprot;
m_apb_pwrite_next = cur_s_apb_pwrite;
m_apb_pwdata_next = cur_s_apb_pwdata;
m_apb_pstrb_next = cur_s_apb_pstrb;
m_apb_pauser_next = cur_s_apb_pauser;
m_apb_pwuser_next = cur_s_apb_pwuser;
if (grant_valid && s_apb_pready_reg == 0) begin
state_next = STATE_DECODE;
end else begin
state_next = STATE_IDLE;
end
end
STATE_DECODE: begin
// decode state; determine master interface
match = 1'b0;
for (integer i = 0; i < M_CNT; i = i + 1) begin
for (integer j = 0; j < M_REGIONS; j = j + 1) begin
if (M_ADDR_W_INT[i*M_REGIONS+j] != 0 && (!M_SECURE_INT[i] || !m_apb_pprot_reg[1]) && (m_apb_pwrite_reg ? M_CONNECT_WR_INT[i][s_sel] : M_CONNECT_RD_INT[i][s_sel]) && (m_apb_paddr_reg >> M_ADDR_W_INT[i*M_REGIONS+j]) == (M_BASE_ADDR_INT[i*M_REGIONS+j] >> M_ADDR_W_INT[i*M_REGIONS+j])) begin
m_sel_next = CL_M_CNT_INT'(i);
match = 1'b1;
end
end
end
s_apb_prdata_next = '0;
s_apb_pslverr_next = 1'b1;
if (match) begin
m_apb_psel_next[m_sel_next] = 1'b1;
state_next = STATE_READ;
end else begin
// no match; return decode error
s_apb_pready_next[s_sel] = 1'b1;
state_next = STATE_IDLE;
end
end
STATE_READ: begin
// read state; store and forward read response
m_apb_psel_next[m_sel_reg] = 1'b1;
m_apb_penable_next = 1'b1;
s_apb_pready_next[s_sel] = cur_m_apb_pready;
s_apb_prdata_next = cur_m_apb_prdata;
s_apb_pslverr_next = cur_m_apb_pslverr;
s_apb_pruser_next = cur_m_apb_pruser;
s_apb_pbuser_next = cur_m_apb_pbuser;
if (cur_m_apb_pready) begin
m_apb_psel_next[m_sel_reg] = 1'b0;
m_apb_penable_next = 1'b0;
state_next = STATE_IDLE;
end else begin
state_next = STATE_READ;
end
end
default: begin
// invalid state
state_next = STATE_IDLE;
end
endcase
end
always_ff @(posedge clk) begin
state_reg <= state_next;
m_sel_reg <= m_sel_next;
s_apb_pready_reg <= s_apb_pready_next;
s_apb_prdata_reg <= s_apb_prdata_next;
s_apb_pslverr_reg <= s_apb_pslverr_next;
s_apb_pruser_reg <= s_apb_pruser_next;
s_apb_pbuser_reg <= s_apb_pbuser_next;
m_apb_paddr_reg <= m_apb_paddr_next;
m_apb_pprot_reg <= m_apb_pprot_next;
m_apb_psel_reg <= m_apb_psel_next;
m_apb_penable_reg <= m_apb_penable_next;
m_apb_pwrite_reg <= m_apb_pwrite_next;
m_apb_pwdata_reg <= m_apb_pwdata_next;
m_apb_pstrb_reg <= m_apb_pstrb_next;
m_apb_pauser_reg <= m_apb_pauser_next;
m_apb_pwuser_reg <= m_apb_pwuser_next;
if (rst) begin if (rst) begin
act_reg <= 1'b0; state_reg <= STATE_IDLE;
s_apb_pready_reg <= 1'b0;
s_apb_pready_reg <= '0;
m_apb_psel_reg <= '0; m_apb_psel_reg <= '0;
m_apb_penable_reg <= 1'b0; m_apb_penable_reg <= 1'b0;
end end

View File

@@ -0,0 +1,275 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2025 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* APB interconnect
*/
module taxi_apb_interconnect_1s #
(
// Number of downstream APB interfaces
parameter M_CNT = 4,
// Width of address decoder in bits
parameter ADDR_W = 16,
// Number of regions per master interface
parameter M_REGIONS = 1,
// TODO fix parametrization once verilator issue 5890 is fixed
// Master interface base addresses
// M_CNT concatenated fields of M_REGIONS concatenated fields of ADDR_W bits
// set to zero for default addressing based on M_ADDR_W
parameter M_BASE_ADDR = '0,
// Master interface address widths
// M_CNT concatenated fields of M_REGIONS concatenated fields of 32 bits
parameter M_ADDR_W = {M_CNT{{M_REGIONS{32'd24}}}},
// Secure master (fail operations based on pprot)
// M_CNT bits
parameter M_SECURE = {M_CNT{1'b0}}
)
(
input wire logic clk,
input wire logic rst,
/*
* APB slave interface
*/
taxi_apb_if.slv s_apb,
/*
* APB master interface
*/
taxi_apb_if.mst m_apb[M_CNT]
);
// extract parameters
localparam DATA_W = s_apb.DATA_W;
localparam S_ADDR_W = s_apb.ADDR_W;
localparam STRB_W = s_apb.STRB_W;
localparam logic PAUSER_EN = s_apb.PAUSER_EN && m_apb[0].PAUSER_EN;
localparam PAUSER_W = s_apb.PAUSER_W;
localparam logic PWUSER_EN = s_apb.PWUSER_EN && m_apb[0].PWUSER_EN;
localparam PWUSER_W = s_apb.PWUSER_W;
localparam logic PRUSER_EN = s_apb.PRUSER_EN && m_apb[0].PRUSER_EN;
localparam PRUSER_W = s_apb.PRUSER_W;
localparam logic PBUSER_EN = s_apb.PBUSER_EN && m_apb[0].PBUSER_EN;
localparam PBUSER_W = s_apb.PBUSER_W;
localparam APB_M_ADDR_W = m_apb[0].ADDR_W;
localparam CL_M_CNT = $clog2(M_CNT);
localparam CL_M_CNT_INT = CL_M_CNT > 0 ? CL_M_CNT : 1;
localparam [M_CNT*M_REGIONS-1:0][31:0] M_ADDR_W_INT = M_ADDR_W;
localparam [M_CNT-1:0] M_SECURE_INT = M_SECURE;
// default address computation
function [M_CNT*M_REGIONS-1:0][ADDR_W-1:0] calcBaseAddrs(input [31:0] dummy);
logic [ADDR_W-1:0] base;
integer width;
logic [ADDR_W-1:0] size;
logic [ADDR_W-1:0] mask;
begin
calcBaseAddrs = '0;
base = '0;
for (integer i = 0; i < M_CNT*M_REGIONS; i = i + 1) begin
width = M_ADDR_W_INT[i];
mask = {ADDR_W{1'b1}} >> (ADDR_W - width);
size = mask + 1;
if (width > 0) begin
if ((base & mask) != 0) begin
base = base + size - (base & mask); // align
end
calcBaseAddrs[i] = base;
base = base + size; // increment
end
end
end
endfunction
localparam [M_CNT*M_REGIONS-1:0][ADDR_W-1:0] M_BASE_ADDR_INT = M_BASE_ADDR != 0 ? (M_CNT*M_REGIONS*ADDR_W)'(M_BASE_ADDR) : calcBaseAddrs(0);
// check configuration
if (s_apb.ADDR_W != ADDR_W)
$fatal(0, "Error: Interface ADDR_W parameter mismatch (instance %m)");
if (m_apb[0].DATA_W != DATA_W)
$fatal(0, "Error: Interface DATA_W parameter mismatch (instance %m)");
if (m_apb[0].STRB_W != STRB_W)
$fatal(0, "Error: Interface STRB_W parameter mismatch (instance %m)");
initial begin
for (integer i = 0; i < M_CNT*M_REGIONS; i = i + 1) begin
/* verilator lint_off UNSIGNED */
if (M_ADDR_W_INT[i] != 0 && (M_ADDR_W_INT[i] < $clog2(STRB_W) || M_ADDR_W_INT[i] > ADDR_W)) begin
$error("Error: address width out of range (instance %m)");
$finish;
end
/* verilator lint_on UNSIGNED */
end
$display("Addressing configuration for apb_interconnect instance %m");
for (integer i = 0; i < M_CNT*M_REGIONS; i = i + 1) begin
if (M_ADDR_W_INT[i] != 0) begin
$display("%2d (%2d): %x / %02d -- %x-%x",
i/M_REGIONS, i%M_REGIONS,
M_BASE_ADDR_INT[i],
M_ADDR_W_INT[i],
M_BASE_ADDR_INT[i] & ({ADDR_W{1'b1}} << M_ADDR_W_INT[i]),
M_BASE_ADDR_INT[i] | ({ADDR_W{1'b1}} >> (ADDR_W - M_ADDR_W_INT[i]))
);
end
end
for (integer i = 0; i < M_CNT*M_REGIONS; i = i + 1) begin
if ((M_BASE_ADDR_INT[i] & (2**M_ADDR_W_INT[i]-1)) != 0) begin
$display("Region not aligned:");
$display("%2d (%2d): %x / %2d -- %x-%x",
i/M_REGIONS, i%M_REGIONS,
M_BASE_ADDR_INT[i],
M_ADDR_W_INT[i],
M_BASE_ADDR_INT[i] & ({ADDR_W{1'b1}} << M_ADDR_W_INT[i]),
M_BASE_ADDR_INT[i] | ({ADDR_W{1'b1}} >> (ADDR_W - M_ADDR_W_INT[i]))
);
$error("Error: address range not aligned (instance %m)");
$finish;
end
end
for (integer i = 0; i < M_CNT*M_REGIONS; i = i + 1) begin
for (integer j = i+1; j < M_CNT*M_REGIONS; j = j + 1) begin
if (M_ADDR_W_INT[i] != 0 && M_ADDR_W_INT[j] != 0) begin
if (((M_BASE_ADDR_INT[i] & ({ADDR_W{1'b1}} << M_ADDR_W_INT[i])) <= (M_BASE_ADDR_INT[j] | ({ADDR_W{1'b1}} >> (ADDR_W - M_ADDR_W_INT[j]))))
&& ((M_BASE_ADDR_INT[j] & ({ADDR_W{1'b1}} << M_ADDR_W_INT[j])) <= (M_BASE_ADDR_INT[i] | ({ADDR_W{1'b1}} >> (ADDR_W - M_ADDR_W_INT[i]))))) begin
$display("Overlapping regions:");
$display("%2d (%2d): %x / %2d -- %x-%x",
i/M_REGIONS, i%M_REGIONS,
M_BASE_ADDR_INT[i],
M_ADDR_W_INT[i],
M_BASE_ADDR_INT[i] & ({ADDR_W{1'b1}} << M_ADDR_W_INT[i]),
M_BASE_ADDR_INT[i] | ({ADDR_W{1'b1}} >> (ADDR_W - M_ADDR_W_INT[i]))
);
$display("%2d (%2d): %x / %2d -- %x-%x",
j/M_REGIONS, j%M_REGIONS,
M_BASE_ADDR_INT[j],
M_ADDR_W_INT[j],
M_BASE_ADDR_INT[j] & ({ADDR_W{1'b1}} << M_ADDR_W_INT[j]),
M_BASE_ADDR_INT[j] | ({ADDR_W{1'b1}} >> (ADDR_W - M_ADDR_W_INT[j]))
);
$error("Error: address ranges overlap (instance %m)");
$finish;
end
end
end
end
end
logic [CL_M_CNT_INT-1:0] sel_reg = '0;
logic act_reg = 1'b0;
logic s_apb_pready_reg = 1'b0;
logic [DATA_W-1:0] s_apb_prdata_reg = '0;
logic s_apb_pslverr_reg = 1'b0;
logic [PRUSER_W-1:0] s_apb_pruser_reg = '0;
logic [PBUSER_W-1:0] s_apb_pbuser_reg = '0;
logic [ADDR_W-1:0] m_apb_paddr_reg = '0;
logic [2:0] m_apb_pprot_reg = '0;
logic [M_CNT-1:0] m_apb_psel_reg = '0;
logic m_apb_penable_reg = 1'b0;
logic m_apb_pwrite_reg = 1'b0;
logic [DATA_W-1:0] m_apb_pwdata_reg = '0;
logic [STRB_W-1:0] m_apb_pstrb_reg = '0;
logic [PAUSER_W-1:0] m_apb_pauser_reg = '0;
logic [PWUSER_W-1:0] m_apb_pwuser_reg = '0;
wire [M_CNT-1:0] m_apb_pready;
wire [DATA_W-1:0] m_apb_prdata[M_CNT];
wire m_apb_pslverr[M_CNT];
wire [PRUSER_W-1:0] m_apb_pruser[M_CNT];
wire [PBUSER_W-1:0] m_apb_pbuser[M_CNT];
assign s_apb.pready = s_apb_pready_reg;
assign s_apb.prdata = s_apb_prdata_reg;
assign s_apb.pslverr = s_apb_pslverr_reg;
assign s_apb.pruser = PRUSER_EN ? s_apb_pruser_reg : '0;
assign s_apb.pbuser = PBUSER_EN ? s_apb_pbuser_reg : '0;
for (genvar n = 0; n < M_CNT; n += 1) begin
assign m_apb[n].paddr = APB_M_ADDR_W'(m_apb_paddr_reg);
assign m_apb[n].pprot = m_apb_pprot_reg;
assign m_apb[n].psel = m_apb_psel_reg[n];
assign m_apb[n].penable = m_apb_penable_reg;
assign m_apb[n].pwrite = m_apb_pwrite_reg;
assign m_apb[n].pwdata = m_apb_pwdata_reg;
assign m_apb[n].pstrb = m_apb_pstrb_reg;
assign m_apb_pready[n] = m_apb[n].pready;
assign m_apb_prdata[n] = m_apb[n].prdata;
assign m_apb_pslverr[n] = m_apb[n].pslverr;
assign m_apb[n].pauser = PAUSER_EN ? m_apb_pauser_reg : '0;
assign m_apb[n].pwuser = PWUSER_EN ? m_apb_pwuser_reg : '0;
assign m_apb_pruser[n] = m_apb[n].pruser;
assign m_apb_pbuser[n] = m_apb[n].pbuser;
end
always_ff @(posedge clk) begin
s_apb_pready_reg <= 1'b0;
m_apb_penable_reg <= act_reg && s_apb.penable;
s_apb_prdata_reg <= m_apb_prdata[sel_reg];
s_apb_pslverr_reg <= m_apb_pslverr[sel_reg] | (m_apb_psel_reg == 0);
s_apb_pruser_reg <= m_apb_pruser[sel_reg];
s_apb_pbuser_reg <= m_apb_pbuser[sel_reg];
if ((m_apb_psel_reg & ~m_apb_pready) == 0) begin
m_apb_psel_reg <= '0;
m_apb_penable_reg <= 1'b0;
s_apb_pready_reg <= act_reg;
act_reg <= 1'b0;
end
if (!act_reg) begin
m_apb_paddr_reg <= s_apb.paddr;
m_apb_pprot_reg <= s_apb.pprot;
m_apb_pwrite_reg <= s_apb.pwrite;
m_apb_pwdata_reg <= s_apb.pwdata;
m_apb_pstrb_reg <= s_apb.pstrb;
m_apb_pauser_reg <= s_apb.pauser;
m_apb_pwuser_reg <= s_apb.pwuser;
m_apb_psel_reg <= '0;
m_apb_penable_reg <= 1'b0;
if (s_apb.psel && !s_apb_pready_reg) begin
act_reg <= 1'b1;
for (integer i = 0; i < M_CNT; i = i + 1) begin
for (integer j = 0; j < M_REGIONS; j = j + 1) begin
if (M_ADDR_W_INT[i*M_REGIONS+j] != 0 && (!M_SECURE_INT[i] || !s_apb.pprot[1]) && (s_apb.paddr >> M_ADDR_W_INT[i*M_REGIONS+j]) == (M_BASE_ADDR_INT[i*M_REGIONS+j] >> M_ADDR_W_INT[i*M_REGIONS+j])) begin
sel_reg <= CL_M_CNT_INT'(i);
m_apb_psel_reg[i] <= 1'b1;
end
end
end
end
end
if (rst) begin
act_reg <= 1'b0;
s_apb_pready_reg <= 1'b0;
m_apb_psel_reg <= '0;
m_apb_penable_reg <= 1'b0;
end
end
endmodule
`resetall

View File

@@ -75,7 +75,7 @@ always_comb begin
s_apb_pready_next = 1'b0; s_apb_pready_next = 1'b0;
if (s_apb.psel && s_apb.penable && (!s_apb_pready_reg && (PIPELINE_OUTPUT || !s_apb_pready_pipe_reg))) begin if (s_apb.psel && (!s_apb_pready_reg && (PIPELINE_OUTPUT || !s_apb_pready_pipe_reg))) begin
s_apb_pready_next = 1'b1; s_apb_pready_next = 1'b1;
if (s_apb.pwrite) begin if (s_apb.pwrite) begin

View File

@@ -0,0 +1,71 @@
// SPDX-License-Identifier: MIT
/*
Copyright (c) 2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* APB tie
*/
module taxi_apb_tie
(
/*
* APB slave interface
*/
taxi_apb_if.slv s_apb,
/*
* APB master interface
*/
taxi_apb_if.mst m_apb
);
// extract parameters
localparam DATA_W = s_apb.DATA_W;
localparam ADDR_W = s_apb.ADDR_W;
localparam STRB_W = s_apb.STRB_W;
localparam logic PAUSER_EN = s_apb.PAUSER_EN && m_apb.PAUSER_EN;
localparam PAUSER_W = s_apb.PAUSER_W;
localparam logic PWUSER_EN = s_apb.PWUSER_EN && m_apb.PWUSER_EN;
localparam PWUSER_W = s_apb.PWUSER_W;
localparam logic PRUSER_EN = s_apb.PRUSER_EN && m_apb.PRUSER_EN;
localparam PRUSER_W = s_apb.PRUSER_W;
localparam logic PBUSER_EN = s_apb.PBUSER_EN && m_apb.PBUSER_EN;
localparam PBUSER_W = s_apb.PBUSER_W;
// check configuration
if (m_apb.ADDR_W > ADDR_W)
$fatal(0, "Error: Output ADDR_W is wider than input ADDR_W, cannot access entire address space (instance %m)");
if (m_apb.DATA_W != DATA_W)
$fatal(0, "Error: Interface DATA_W parameter mismatch (instance %m)");
if (m_apb.STRB_W != STRB_W)
$fatal(0, "Error: Interface STRB_W parameter mismatch (instance %m)");
assign m_apb.paddr = m_apb.ADDR_W'(s_apb.paddr);
assign m_apb.pprot = s_apb.pprot;
assign m_apb.psel = s_apb.psel;
assign m_apb.penable = s_apb.penable;
assign m_apb.pwrite = s_apb.pwrite;
assign m_apb.pwdata = s_apb.pwdata;
assign m_apb.pstrb = s_apb.pstrb;
assign s_apb.pready = m_apb.pready;
assign s_apb.prdata = m_apb.prdata;
assign s_apb.pslverr = m_apb.pslverr;
assign m_apb.pauser = PAUSER_EN ? s_apb.pauser : '0;
assign m_apb.pwuser = PWUSER_EN ? s_apb.pwuser : '0;
assign s_apb.pruser = PRUSER_EN ? m_apb.pruser : '0;
assign s_apb.pbuser = PBUSER_EN ? m_apb.pbuser : '0;
endmodule
`resetall

View File

@@ -157,16 +157,13 @@ def cycle_pause():
if getattr(cocotb, 'top', None) is not None: if getattr(cocotb, 'top', None) is not None:
for test in [run_test_write, run_test_read]: for test in [run_test_write, run_test_read, run_stress_test]:
factory = TestFactory(test) factory = TestFactory(test)
factory.add_option("idle_inserter", [None, cycle_pause]) factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause]) factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests() factory.generate_tests()
factory = TestFactory(run_stress_test)
factory.generate_tests()
# cocotb-test # cocotb-test

View File

@@ -161,16 +161,13 @@ def cycle_pause():
if getattr(cocotb, 'top', None) is not None: if getattr(cocotb, 'top', None) is not None:
for test in [run_test_write, run_test_read]: for test in [run_test_write, run_test_read, run_stress_test]:
factory = TestFactory(test) factory = TestFactory(test)
factory.add_option("idle_inserter", [None, cycle_pause]) factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause]) factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests() factory.generate_tests()
factory = TestFactory(run_stress_test)
factory.generate_tests()
# cocotb-test # cocotb-test

View File

@@ -23,8 +23,7 @@ COCOTB_TOPLEVEL = test_$(DUT)
MODULE = $(COCOTB_TEST_MODULES) MODULE = $(COCOTB_TEST_MODULES)
TOPLEVEL = $(COCOTB_TOPLEVEL) TOPLEVEL = $(COCOTB_TOPLEVEL)
VERILOG_SOURCES += $(COCOTB_TOPLEVEL).sv VERILOG_SOURCES += $(COCOTB_TOPLEVEL).sv
VERILOG_SOURCES += $(RTL_DIR)/$(DUT).sv VERILOG_SOURCES += $(RTL_DIR)/$(DUT).f
VERILOG_SOURCES += $(RTL_DIR)/taxi_apb_if.sv
# handle file list files # handle file list files
process_f_file = $(call process_f_files,$(addprefix $(dir $1),$(shell cat $1))) process_f_file = $(call process_f_files,$(addprefix $(dir $1),$(shell cat $1)))
@@ -33,6 +32,7 @@ uniq_base = $(if $1,$(call uniq_base,$(foreach f,$1,$(if $(filter-out $(notdir $
VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES))) VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES)))
# module parameters # module parameters
export PARAM_S_CNT := 4
export PARAM_M_CNT := 4 export PARAM_M_CNT := 4
export PARAM_DATA_W := 32 export PARAM_DATA_W := 32
export PARAM_ADDR_W := 32 export PARAM_ADDR_W := 32

View File

@@ -32,7 +32,10 @@ class TB(object):
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start()) cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
self.apb_master = ApbMaster(ApbBus.from_entity(dut.s_apb), dut.clk, dut.rst) self.apb_master = [
ApbMaster(ApbBus.from_entity(ch), dut.clk, dut.rst)
for ch in dut.s_apb
]
self.apb_ram = [ self.apb_ram = [
ApbRam(ApbBus.from_entity(ch), dut.clk, dut.rst, size=2**16) ApbRam(ApbBus.from_entity(ch), dut.clk, dut.rst, size=2**16)
for ch in dut.m_apb for ch in dut.m_apb
@@ -40,7 +43,8 @@ class TB(object):
def set_idle_generator(self, generator=None): def set_idle_generator(self, generator=None):
if generator: if generator:
self.apb_master.set_pause_generator(generator()) for master in self.apb_master:
master.set_pause_generator(generator())
def set_backpressure_generator(self, generator=None): def set_backpressure_generator(self, generator=None):
if generator: if generator:
@@ -60,11 +64,11 @@ class TB(object):
async def run_test_write( async def run_test_write(
dut, data_in=None, idle_inserter=None, backpressure_inserter=None, m=0 dut, data_in=None, idle_inserter=None, backpressure_inserter=None, s=0, m=0
): ):
tb = TB(dut) tb = TB(dut)
byte_lanes = tb.apb_master.byte_lanes byte_lanes = tb.apb_master[s].byte_lanes
await tb.cycle_reset() await tb.cycle_reset()
@@ -80,7 +84,7 @@ async def run_test_write(
tb.apb_ram[m].write(ram_addr - 128, b"\xaa" * (length + 256)) tb.apb_ram[m].write(ram_addr - 128, b"\xaa" * (length + 256))
await tb.apb_master.write(addr, test_data) await tb.apb_master[s].write(addr, test_data)
tb.log.debug( tb.log.debug(
"%s", "%s",
@@ -99,11 +103,11 @@ async def run_test_write(
async def run_test_read( async def run_test_read(
dut, data_in=None, idle_inserter=None, backpressure_inserter=None, m=0 dut, data_in=None, idle_inserter=None, backpressure_inserter=None, s=0, m=0
): ):
tb = TB(dut) tb = TB(dut)
byte_lanes = tb.apb_master.byte_lanes byte_lanes = tb.apb_master[s].byte_lanes
await tb.cycle_reset() await tb.cycle_reset()
@@ -119,7 +123,7 @@ async def run_test_read(
tb.apb_ram[m].write(ram_addr, test_data) tb.apb_ram[m].write(ram_addr, test_data)
data = await tb.apb_master.read(addr, length) data = await tb.apb_master[s].read(addr, length)
assert data.data == test_data assert data.data == test_data
@@ -157,7 +161,7 @@ async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None):
workers.append( workers.append(
cocotb.start_soon( cocotb.start_soon(
worker( worker(
tb.apb_master, tb.apb_master[k % len(tb.apb_master)],
k * 0x1000, k * 0x1000,
0x1000, 0x1000,
count=16, count=16,
@@ -177,16 +181,20 @@ def cycle_pause():
if getattr(cocotb, "top", None) is not None: if getattr(cocotb, "top", None) is not None:
s_cnt = len(cocotb.top.s_apb)
m_cnt = len(cocotb.top.m_apb) m_cnt = len(cocotb.top.m_apb)
for test in [run_test_write, run_test_read]: for test in [run_test_write, run_test_read]:
factory = TestFactory(test) factory = TestFactory(test)
factory.add_option("idle_inserter", [None, cycle_pause]) factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause]) factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.add_option("s", range(min(s_cnt, 2)))
factory.add_option("m", range(min(m_cnt, 2))) factory.add_option("m", range(min(m_cnt, 2)))
factory.generate_tests() factory.generate_tests()
factory = TestFactory(run_stress_test) factory = TestFactory(run_stress_test)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests() factory.generate_tests()
@@ -213,15 +221,15 @@ def process_f_files(files):
@pytest.mark.parametrize("data_w", [8, 16, 32]) @pytest.mark.parametrize("data_w", [8, 16, 32])
@pytest.mark.parametrize("m_cnt", [1, 4]) @pytest.mark.parametrize("m_cnt", [1, 4])
def test_taxi_apb_interconnect(request, m_cnt, data_w): @pytest.mark.parametrize("s_cnt", [1, 4])
def test_taxi_apb_interconnect(request, s_cnt, m_cnt, data_w):
dut = "taxi_apb_interconnect" dut = "taxi_apb_interconnect"
module = os.path.splitext(os.path.basename(__file__))[0] module = os.path.splitext(os.path.basename(__file__))[0]
toplevel = module toplevel = module
verilog_sources = [ verilog_sources = [
os.path.join(tests_dir, f"{toplevel}.sv"), os.path.join(tests_dir, f"{toplevel}.sv"),
os.path.join(rtl_dir, f"{dut}.sv"), os.path.join(rtl_dir, f"{dut}.f"),
os.path.join(rtl_dir, "taxi_apb_if.sv"),
] ]
verilog_sources = process_f_files(verilog_sources) verilog_sources = process_f_files(verilog_sources)
@@ -229,6 +237,7 @@ def test_taxi_apb_interconnect(request, m_cnt, data_w):
parameters = {} parameters = {}
parameters["M_CNT"] = m_cnt parameters["M_CNT"] = m_cnt
parameters["S_CNT"] = s_cnt
parameters["DATA_W"] = data_w parameters["DATA_W"] = data_w
parameters["ADDR_W"] = 32 parameters["ADDR_W"] = 32
parameters["STRB_W"] = parameters["DATA_W"] // 8 parameters["STRB_W"] = parameters["DATA_W"] // 8

View File

@@ -18,6 +18,7 @@ Authors:
module test_taxi_apb_interconnect # module test_taxi_apb_interconnect #
( (
/* verilator lint_off WIDTHTRUNC */ /* verilator lint_off WIDTHTRUNC */
parameter S_CNT = 4,
parameter M_CNT = 4, parameter M_CNT = 4,
parameter DATA_W = 32, parameter DATA_W = 32,
parameter ADDR_W = 32, parameter ADDR_W = 32,
@@ -33,6 +34,8 @@ module test_taxi_apb_interconnect #
parameter M_REGIONS = 1, parameter M_REGIONS = 1,
parameter M_BASE_ADDR = '0, parameter M_BASE_ADDR = '0,
parameter M_ADDR_W = {M_CNT{{M_REGIONS{32'd24}}}}, parameter M_ADDR_W = {M_CNT{{M_REGIONS{32'd24}}}},
parameter M_CONNECT_RD = {M_CNT{{S_CNT{1'b1}}}},
parameter M_CONNECT_WR = {M_CNT{{S_CNT{1'b1}}}},
parameter M_SECURE = {M_CNT{1'b0}} parameter M_SECURE = {M_CNT{1'b0}}
/* verilator lint_on WIDTHTRUNC */ /* verilator lint_on WIDTHTRUNC */
) )
@@ -53,14 +56,17 @@ taxi_apb_if #(
.PRUSER_W(PRUSER_W), .PRUSER_W(PRUSER_W),
.PBUSER_EN(PBUSER_EN), .PBUSER_EN(PBUSER_EN),
.PBUSER_W(PBUSER_W) .PBUSER_W(PBUSER_W)
) s_apb(), m_apb[M_CNT](); ) s_apb[S_CNT](), m_apb[M_CNT]();
taxi_apb_interconnect #( taxi_apb_interconnect #(
.S_CNT(S_CNT),
.M_CNT(M_CNT), .M_CNT(M_CNT),
.ADDR_W(ADDR_W), .ADDR_W(ADDR_W),
.M_REGIONS(M_REGIONS), .M_REGIONS(M_REGIONS),
.M_BASE_ADDR(M_BASE_ADDR), .M_BASE_ADDR(M_BASE_ADDR),
.M_ADDR_W(M_ADDR_W), .M_ADDR_W(M_ADDR_W),
.M_CONNECT_RD(M_CONNECT_RD),
.M_CONNECT_WR(M_CONNECT_WR),
.M_SECURE(M_SECURE) .M_SECURE(M_SECURE)
) )
uut ( uut (

View File

@@ -0,0 +1,64 @@
# SPDX-License-Identifier: CERN-OHL-S-2.0
#
# Copyright (c) 2020-2025
#
# Authors:
# - Alex Forencich
TOPLEVEL_LANG = verilog
SIM ?= verilator
WAVES ?= 0
COCOTB_HDL_TIMEUNIT = 1ns
COCOTB_HDL_TIMEPRECISION = 1ps
RTL_DIR = ../../rtl
LIB_DIR = ../../lib
TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
DUT = taxi_apb_interconnect_1s
COCOTB_TEST_MODULES = test_$(DUT)
COCOTB_TOPLEVEL = test_$(DUT)
MODULE = $(COCOTB_TEST_MODULES)
TOPLEVEL = $(COCOTB_TOPLEVEL)
VERILOG_SOURCES += $(COCOTB_TOPLEVEL).sv
VERILOG_SOURCES += $(RTL_DIR)/$(DUT).sv
VERILOG_SOURCES += $(RTL_DIR)/taxi_apb_if.sv
# handle file list files
process_f_file = $(call process_f_files,$(addprefix $(dir $1),$(shell cat $1)))
process_f_files = $(foreach f,$1,$(if $(filter %.f,$f),$(call process_f_file,$f),$f))
uniq_base = $(if $1,$(call uniq_base,$(foreach f,$1,$(if $(filter-out $(notdir $(lastword $1)),$(notdir $f)),$f,))) $(lastword $1))
VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES)))
# module parameters
export PARAM_M_CNT := 4
export PARAM_DATA_W := 32
export PARAM_ADDR_W := 32
export PARAM_STRB_W := $(shell expr $(PARAM_DATA_W) / 8 )
export PARAM_PAUSER_EN := 0
export PARAM_PAUSER_W := 1
export PARAM_PWUSER_EN := 0
export PARAM_PWUSER_W := 1
export PARAM_PBUSER_EN := 0
export PARAM_PBUSER_W := 1
export PARAM_PRUSER_EN := 0
export PARAM_PRUSER_W := 1
ifeq ($(SIM), icarus)
PLUSARGS += -fst
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-P $(COCOTB_TOPLEVEL).$(subst PARAM_,,$(v))=$($(v)))
else ifeq ($(SIM), verilator)
COMPILE_ARGS += -Wno-WIDTH
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(v))=$($(v)))
ifeq ($(WAVES), 1)
COMPILE_ARGS += --trace-fst
VERILATOR_TRACE = 1
endif
endif
include $(shell cocotb-config --makefiles)/Makefile.sim

View File

@@ -0,0 +1,261 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: CERN-OHL-S-2.0
"""
Copyright (c) 2020-2025 FPGA Ninja, LLC
Authors:
- Alex Forencich
"""
import itertools
import logging
import os
import random
import cocotb
import cocotb_test.simulator
import pytest
from cocotb.clock import Clock
from cocotb.regression import TestFactory
from cocotb.triggers import RisingEdge, Timer
from cocotbext.axi import ApbBus, ApbMaster, ApbRam
class TB(object):
def __init__(self, dut):
self.dut = dut
self.log = logging.getLogger("cocotb.tb")
self.log.setLevel(logging.DEBUG)
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
self.apb_master = ApbMaster(ApbBus.from_entity(dut.s_apb), dut.clk, dut.rst)
self.apb_ram = [
ApbRam(ApbBus.from_entity(ch), dut.clk, dut.rst, size=2**16)
for ch in dut.m_apb
]
def set_idle_generator(self, generator=None):
if generator:
self.apb_master.set_pause_generator(generator())
def set_backpressure_generator(self, generator=None):
if generator:
for ram in self.apb_ram:
ram.set_pause_generator(generator())
async def cycle_reset(self):
self.dut.rst.setimmediatevalue(0)
await RisingEdge(self.dut.clk)
await RisingEdge(self.dut.clk)
self.dut.rst.value = 1
await RisingEdge(self.dut.clk)
await RisingEdge(self.dut.clk)
self.dut.rst.value = 0
await RisingEdge(self.dut.clk)
await RisingEdge(self.dut.clk)
async def run_test_write(
dut, data_in=None, idle_inserter=None, backpressure_inserter=None, m=0
):
tb = TB(dut)
byte_lanes = tb.apb_master.byte_lanes
await tb.cycle_reset()
tb.set_idle_generator(idle_inserter)
tb.set_backpressure_generator(backpressure_inserter)
for length in range(1, byte_lanes * 2):
for offset in range(byte_lanes):
tb.log.info("length %d, offset %d", length, offset)
ram_addr = offset + 0x1000
addr = ram_addr + m * 0x1000000
test_data = bytearray([x % 256 for x in range(length)])
tb.apb_ram[m].write(ram_addr - 128, b"\xaa" * (length + 256))
await tb.apb_master.write(addr, test_data)
tb.log.debug(
"%s",
tb.apb_ram[m].hexdump_str(
(ram_addr & ~0xF) - 16,
(((ram_addr & 0xF) + length - 1) & ~0xF) + 48,
),
)
assert tb.apb_ram[m].read(ram_addr, length) == test_data
assert tb.apb_ram[m].read(ram_addr - 1, 1) == b"\xaa"
assert tb.apb_ram[m].read(ram_addr + length, 1) == b"\xaa"
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
async def run_test_read(
dut, data_in=None, idle_inserter=None, backpressure_inserter=None, m=0
):
tb = TB(dut)
byte_lanes = tb.apb_master.byte_lanes
await tb.cycle_reset()
tb.set_idle_generator(idle_inserter)
tb.set_backpressure_generator(backpressure_inserter)
for length in range(1, byte_lanes * 2):
for offset in range(byte_lanes):
tb.log.info("length %d, offset %d", length, offset)
ram_addr = offset + 0x1000
addr = ram_addr + m * 0x1000000
test_data = bytearray([x % 256 for x in range(length)])
tb.apb_ram[m].write(ram_addr, test_data)
data = await tb.apb_master.read(addr, length)
assert data.data == test_data
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None):
tb = TB(dut)
await tb.cycle_reset()
tb.set_idle_generator(idle_inserter)
tb.set_backpressure_generator(backpressure_inserter)
async def worker(master, offset, aperture, count=16):
for k in range(count):
m = random.randrange(len(tb.apb_ram))
length = random.randint(1, min(32, aperture))
addr = offset + random.randint(0, aperture - length) + m * 0x1000000
test_data = bytearray([x % 256 for x in range(length)])
await Timer(random.randint(1, 100), "ns")
await master.write(addr, test_data)
await Timer(random.randint(1, 100), "ns")
data = await master.read(addr, length)
assert data.data == test_data
workers = []
for k in range(16):
workers.append(
cocotb.start_soon(
worker(
tb.apb_master,
k * 0x1000,
0x1000,
count=16,
)
)
)
while workers:
await workers.pop(0).join()
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
def cycle_pause():
return itertools.cycle([1, 1, 1, 0])
if getattr(cocotb, "top", None) is not None:
m_cnt = len(cocotb.top.m_apb)
for test in [run_test_write, run_test_read]:
factory = TestFactory(test)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.add_option("m", range(min(m_cnt, 2)))
factory.generate_tests()
factory = TestFactory(run_stress_test)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests()
# cocotb-test
tests_dir = os.path.abspath(os.path.dirname(__file__))
rtl_dir = os.path.abspath(os.path.join(tests_dir, "..", "..", "rtl"))
lib_dir = os.path.abspath(os.path.join(tests_dir, "..", "..", "lib"))
taxi_src_dir = os.path.abspath(os.path.join(lib_dir, "taxi", "src"))
def process_f_files(files):
lst = {}
for f in files:
if f[-2:].lower() == ".f":
with open(f, "r") as fp:
l = fp.read().split()
for f in process_f_files([os.path.join(os.path.dirname(f), x) for x in l]):
lst[os.path.basename(f)] = f
else:
lst[os.path.basename(f)] = f
return list(lst.values())
@pytest.mark.parametrize("data_w", [8, 16, 32])
@pytest.mark.parametrize("m_cnt", [1, 4])
def test_taxi_apb_interconnect_1s(request, m_cnt, data_w):
dut = "taxi_apb_interconnect_1s"
module = os.path.splitext(os.path.basename(__file__))[0]
toplevel = module
verilog_sources = [
os.path.join(tests_dir, f"{toplevel}.sv"),
os.path.join(rtl_dir, f"{dut}.sv"),
os.path.join(rtl_dir, "taxi_apb_if.sv"),
]
verilog_sources = process_f_files(verilog_sources)
parameters = {}
parameters["M_CNT"] = m_cnt
parameters["DATA_W"] = data_w
parameters["ADDR_W"] = 32
parameters["STRB_W"] = parameters["DATA_W"] // 8
parameters["PAUSER_EN"] = 0
parameters["PAUSER_W"] = 1
parameters["PWUSER_EN"] = 0
parameters["PWUSER_W"] = 1
parameters["PRUSER_EN"] = 0
parameters["PRUSER_W"] = 1
parameters["PBUSER_EN"] = 0
parameters["PBUSER_W"] = 1
extra_env = {f"PARAM_{k}": str(v) for k, v in parameters.items()}
sim_build = os.path.join(
tests_dir, "sim_build", request.node.name.replace("[", "-").replace("]", "")
)
cocotb_test.simulator.run(
simulator="verilator",
python_search=[tests_dir],
verilog_sources=verilog_sources,
toplevel=toplevel,
module=module,
parameters=parameters,
sim_build=sim_build,
extra_env=extra_env,
)

View File

@@ -0,0 +1,83 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2025 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* APB interconnect testbench
*/
module test_taxi_apb_interconnect_1s #
(
/* verilator lint_off WIDTHTRUNC */
parameter M_CNT = 4,
parameter DATA_W = 32,
parameter ADDR_W = 32,
parameter STRB_W = (DATA_W/8),
parameter logic PAUSER_EN = 1'b0,
parameter PAUSER_W = 1,
parameter logic PWUSER_EN = 1'b0,
parameter PWUSER_W = 1,
parameter logic PRUSER_EN = 1'b0,
parameter PRUSER_W = 1,
parameter logic PBUSER_EN = 1'b0,
parameter PBUSER_W = 1,
parameter M_REGIONS = 1,
parameter M_BASE_ADDR = '0,
parameter M_ADDR_W = {M_CNT{{M_REGIONS{32'd24}}}},
parameter M_SECURE = {M_CNT{1'b0}}
/* verilator lint_on WIDTHTRUNC */
)
();
logic clk;
logic rst;
taxi_apb_if #(
.DATA_W(DATA_W),
.ADDR_W(ADDR_W),
.STRB_W(STRB_W),
.PAUSER_EN(PAUSER_EN),
.PAUSER_W(PAUSER_W),
.PWUSER_EN(PWUSER_EN),
.PWUSER_W(PWUSER_W),
.PRUSER_EN(PRUSER_EN),
.PRUSER_W(PRUSER_W),
.PBUSER_EN(PBUSER_EN),
.PBUSER_W(PBUSER_W)
) s_apb(), m_apb[M_CNT]();
taxi_apb_interconnect_1s #(
.M_CNT(M_CNT),
.ADDR_W(ADDR_W),
.M_REGIONS(M_REGIONS),
.M_BASE_ADDR(M_BASE_ADDR),
.M_ADDR_W(M_ADDR_W),
.M_SECURE(M_SECURE)
)
uut (
.clk(clk),
.rst(rst),
/*
* APB slave interface
*/
.s_apb(s_apb),
/*
* APB master interface
*/
.m_apb(m_apb)
);
endmodule
`resetall

View File

@@ -0,0 +1,2 @@
taxi_axi_dp_ram.sv
taxi_axi_ram_if_rdwr.f

View File

@@ -0,0 +1,244 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2019-2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4 dual-port RAM
*/
module taxi_axi_dp_ram #
(
// Width of address bus in bits
parameter ADDR_W = 16,
// Extra pipeline register on output port A
parameter logic A_PIPELINE_OUTPUT = 1'b0,
// Extra pipeline register on output port B
parameter logic B_PIPELINE_OUTPUT = 1'b0,
// Interleave read and write burst cycles on port A
parameter logic A_INTERLEAVE = 1'b0,
// Interleave read and write burst cycles on port B
parameter logic B_INTERLEAVE = 1'b0
)
(
/*
* Port A
*/
input wire logic a_clk,
input wire logic a_rst,
taxi_axi_if.wr_slv s_axi_wr_a,
taxi_axi_if.rd_slv s_axi_rd_a,
/*
* Port B
*/
input wire logic b_clk,
input wire logic b_rst,
taxi_axi_if.wr_slv s_axi_wr_b,
taxi_axi_if.rd_slv s_axi_rd_b
);
// extract parameters
localparam DATA_W = s_axi_wr_a.DATA_W;
localparam STRB_W = s_axi_wr_a.STRB_W;
localparam A_ID_W = s_axi_wr_a.ID_W;
localparam B_ID_W = s_axi_wr_b.ID_W;
localparam VALID_ADDR_W = ADDR_W - $clog2(STRB_W);
localparam BYTE_LANES = STRB_W;
localparam BYTE_W = DATA_W/BYTE_LANES;
// check configuration
if (BYTE_W * STRB_W != DATA_W)
$fatal(0, "Error: AXI data width not evenly divisible (instance %m)");
if (2**$clog2(BYTE_LANES) != BYTE_LANES)
$fatal(0, "Error: AXI word width must be even power of two (instance %m)");
wire [A_ID_W-1:0] ram_a_cmd_id;
wire [ADDR_W-1:0] ram_a_cmd_addr;
wire [DATA_W-1:0] ram_a_cmd_wr_data;
wire [STRB_W-1:0] ram_a_cmd_wr_strb;
wire ram_a_cmd_wr_en;
wire ram_a_cmd_rd_en;
wire ram_a_cmd_last;
wire ram_a_cmd_ready;
logic [A_ID_W-1:0] ram_a_rd_resp_id_reg = 'd0;
logic [DATA_W-1:0] ram_a_rd_resp_data_reg = 'd0;
logic ram_a_rd_resp_last_reg = 1'b0;
logic ram_a_rd_resp_valid_reg = 1'b0;
wire ram_a_rd_resp_ready;
wire [B_ID_W-1:0] ram_b_cmd_id;
wire [ADDR_W-1:0] ram_b_cmd_addr;
wire [DATA_W-1:0] ram_b_cmd_wr_data;
wire [STRB_W-1:0] ram_b_cmd_wr_strb;
wire ram_b_cmd_wr_en;
wire ram_b_cmd_rd_en;
wire ram_b_cmd_last;
wire ram_b_cmd_ready;
logic [B_ID_W-1:0] ram_b_rd_resp_id_reg = 'd0;
logic [DATA_W-1:0] ram_b_rd_resp_data_reg = 'd0;
logic ram_b_rd_resp_last_reg = 1'b0;
logic ram_b_rd_resp_valid_reg = 1'b0;
wire ram_b_rd_resp_ready;
taxi_axi_ram_if_rdwr #(
.DATA_W(DATA_W),
.ADDR_W(ADDR_W),
.STRB_W(STRB_W),
.ID_W(A_ID_W),
.AUSER_W(s_axi_wr_a.AWUSER_W > s_axi_rd_a.ARUSER_W ? s_axi_wr_a.AWUSER_W : s_axi_rd_a.ARUSER_W),
.WUSER_W(s_axi_wr_a.WUSER_W),
.RUSER_W(s_axi_rd_a.RUSER_W),
.PIPELINE_OUTPUT(A_PIPELINE_OUTPUT),
.INTERLEAVE(A_INTERLEAVE)
)
a_if (
.clk(a_clk),
.rst(a_rst),
/*
* AXI4 slave interface
*/
.s_axi_wr(s_axi_wr_a),
.s_axi_rd(s_axi_rd_a),
/*
* RAM interface
*/
.ram_cmd_id(ram_a_cmd_id),
.ram_cmd_addr(ram_a_cmd_addr),
.ram_cmd_lock(),
.ram_cmd_cache(),
.ram_cmd_prot(),
.ram_cmd_qos(),
.ram_cmd_region(),
.ram_cmd_auser(),
.ram_cmd_wr_data(ram_a_cmd_wr_data),
.ram_cmd_wr_strb(ram_a_cmd_wr_strb),
.ram_cmd_wr_user(),
.ram_cmd_wr_en(ram_a_cmd_wr_en),
.ram_cmd_rd_en(ram_a_cmd_rd_en),
.ram_cmd_last(ram_a_cmd_last),
.ram_cmd_ready(ram_a_cmd_ready),
.ram_rd_resp_id(ram_a_rd_resp_id_reg),
.ram_rd_resp_data(ram_a_rd_resp_data_reg),
.ram_rd_resp_last(ram_a_rd_resp_last_reg),
.ram_rd_resp_user('0),
.ram_rd_resp_valid(ram_a_rd_resp_valid_reg),
.ram_rd_resp_ready(ram_a_rd_resp_ready)
);
taxi_axi_ram_if_rdwr #(
.DATA_W(DATA_W),
.ADDR_W(ADDR_W),
.STRB_W(STRB_W),
.ID_W(B_ID_W),
.AUSER_W(s_axi_wr_b.AWUSER_W > s_axi_rd_b.ARUSER_W ? s_axi_wr_b.AWUSER_W : s_axi_rd_b.ARUSER_W),
.WUSER_W(s_axi_wr_b.WUSER_W),
.RUSER_W(s_axi_rd_b.RUSER_W),
.PIPELINE_OUTPUT(B_PIPELINE_OUTPUT),
.INTERLEAVE(B_INTERLEAVE)
)
b_if (
.clk(b_clk),
.rst(b_rst),
/*
* AXI4 slave interface
*/
.s_axi_wr(s_axi_wr_b),
.s_axi_rd(s_axi_rd_b),
/*
* RAM interface
*/
.ram_cmd_id(ram_b_cmd_id),
.ram_cmd_addr(ram_b_cmd_addr),
.ram_cmd_lock(),
.ram_cmd_cache(),
.ram_cmd_prot(),
.ram_cmd_qos(),
.ram_cmd_region(),
.ram_cmd_auser(),
.ram_cmd_wr_data(ram_b_cmd_wr_data),
.ram_cmd_wr_strb(ram_b_cmd_wr_strb),
.ram_cmd_wr_user(),
.ram_cmd_wr_en(ram_b_cmd_wr_en),
.ram_cmd_rd_en(ram_b_cmd_rd_en),
.ram_cmd_last(ram_b_cmd_last),
.ram_cmd_ready(ram_b_cmd_ready),
.ram_rd_resp_id(ram_b_rd_resp_id_reg),
.ram_rd_resp_data(ram_b_rd_resp_data_reg),
.ram_rd_resp_last(ram_b_rd_resp_last_reg),
.ram_rd_resp_user('0),
.ram_rd_resp_valid(ram_b_rd_resp_valid_reg),
.ram_rd_resp_ready(ram_b_rd_resp_ready)
);
// verilator lint_off MULTIDRIVEN
// (* RAM_STYLE="BLOCK" *)
logic [DATA_W-1:0] mem[2**VALID_ADDR_W] = '{default: '0};
// verilator lint_on MULTIDRIVEN
wire [VALID_ADDR_W-1:0] addr_a_valid = VALID_ADDR_W'(ram_a_cmd_addr >> (ADDR_W - VALID_ADDR_W));
wire [VALID_ADDR_W-1:0] addr_b_valid = VALID_ADDR_W'(ram_b_cmd_addr >> (ADDR_W - VALID_ADDR_W));
assign ram_a_cmd_ready = !ram_a_rd_resp_valid_reg || ram_a_rd_resp_ready;
always_ff @(posedge a_clk) begin
ram_a_rd_resp_valid_reg <= ram_a_rd_resp_valid_reg && !ram_a_rd_resp_ready;
if (ram_a_cmd_rd_en && ram_a_cmd_ready) begin
ram_a_rd_resp_id_reg <= ram_a_cmd_id;
ram_a_rd_resp_data_reg <= mem[addr_a_valid];
ram_a_rd_resp_last_reg <= ram_a_cmd_last;
ram_a_rd_resp_valid_reg <= 1'b1;
end else if (ram_a_cmd_wr_en && ram_a_cmd_ready) begin
for (integer i = 0; i < BYTE_LANES; i = i + 1) begin
if (ram_a_cmd_wr_strb[i]) begin
mem[addr_a_valid][BYTE_W*i +: BYTE_W] <= ram_a_cmd_wr_data[BYTE_W*i +: BYTE_W];
end
end
end
if (a_rst) begin
ram_a_rd_resp_valid_reg <= 1'b0;
end
end
assign ram_b_cmd_ready = !ram_b_rd_resp_valid_reg || ram_b_rd_resp_ready;
always_ff @(posedge b_clk) begin
ram_b_rd_resp_valid_reg <= ram_b_rd_resp_valid_reg && !ram_b_rd_resp_ready;
if (ram_b_cmd_rd_en && ram_b_cmd_ready) begin
ram_b_rd_resp_id_reg <= ram_b_cmd_id;
ram_b_rd_resp_data_reg <= mem[addr_b_valid];
ram_b_rd_resp_last_reg <= ram_b_cmd_last;
ram_b_rd_resp_valid_reg <= 1'b1;
end else if (ram_b_cmd_wr_en && ram_b_cmd_ready) begin
for (integer i = 0; i < BYTE_LANES; i = i + 1) begin
if (ram_b_cmd_wr_strb[i]) begin
mem[addr_b_valid][BYTE_W*i +: BYTE_W] <= ram_b_cmd_wr_data[BYTE_W*i +: BYTE_W];
end
end
end
if (b_rst) begin
ram_b_rd_resp_valid_reg <= 1'b0;
end
end
endmodule
`resetall

View File

@@ -0,0 +1,243 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2019-2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4 RAM read interface
*/
module taxi_axi_ram_if_rd #
(
// Width of data bus in bits
parameter DATA_W = 32,
// Width of address bus in bits
parameter ADDR_W = 16,
// Width of wstrb (width of data bus in words)
parameter STRB_W = (DATA_W/8),
// Width of ID signal
parameter ID_W = 8,
// Width of auser signal
parameter AUSER_W = 1,
// Width of ruser signal
parameter RUSER_W = 1,
// Extra pipeline register on output
parameter logic PIPELINE_OUTPUT = 1'b0
)
(
input wire logic clk,
input wire logic rst,
/*
* AXI4 slave interface
*/
taxi_axi_if.rd_slv s_axi_rd,
/*
* RAM interface
*/
output wire logic [ID_W-1:0] ram_rd_cmd_id,
output wire logic [ADDR_W-1:0] ram_rd_cmd_addr,
output wire logic ram_rd_cmd_lock,
output wire logic [3:0] ram_rd_cmd_cache,
output wire logic [2:0] ram_rd_cmd_prot,
output wire logic [3:0] ram_rd_cmd_qos,
output wire logic [3:0] ram_rd_cmd_region,
output wire logic [AUSER_W-1:0] ram_rd_cmd_auser,
output wire logic ram_rd_cmd_en,
output wire logic ram_rd_cmd_last,
input wire logic ram_rd_cmd_ready,
input wire logic [ID_W-1:0] ram_rd_resp_id,
input wire logic [DATA_W-1:0] ram_rd_resp_data,
input wire logic ram_rd_resp_last,
input wire logic [RUSER_W-1:0] ram_rd_resp_user,
input wire logic ram_rd_resp_valid,
output wire logic ram_rd_resp_ready
);
// extract parameters
localparam logic AUSER_EN = s_axi_rd.ARUSER_EN;
localparam logic RUSER_EN = s_axi_rd.RUSER_EN;
localparam VALID_ADDR_W = ADDR_W - $clog2(STRB_W);
localparam BYTE_LANES = STRB_W;
localparam BYTE_W = DATA_W/BYTE_LANES;
// check configuration
if (BYTE_W * STRB_W != DATA_W)
$fatal(0, "Error: AXI data width not evenly divisible (instance %m)");
if (2**$clog2(BYTE_LANES) != BYTE_LANES)
$fatal(0, "Error: AXI word width must be even power of two (instance %m)");
if (s_axi_rd.ADDR_W < ADDR_W)
$fatal(0, "Error: AXI address width is insufficient (instance %m)");
if (s_axi_rd.ARUSER_EN && s_axi_rd.ARUSER_W > AUSER_W)
$fatal(0, "Error: AUESR_W setting is insufficient (instance %m)");
if (s_axi_rd.RUSER_EN && s_axi_rd.RUSER_W > RUSER_W)
$fatal(0, "Error: RUESR_W setting is insufficient (instance %m)");
typedef enum logic [0:0] {
STATE_IDLE,
STATE_BURST
} state_t;
state_t state_reg = STATE_IDLE, state_next;
logic [ID_W-1:0] read_id_reg = '0, read_id_next;
logic [ADDR_W-1:0] read_addr_reg = '0, read_addr_next;
logic read_lock_reg = 1'b0, read_lock_next;
logic [3:0] read_cache_reg = 4'd0, read_cache_next;
logic [2:0] read_prot_reg = 3'd0, read_prot_next;
logic [3:0] read_qos_reg = 4'd0, read_qos_next;
logic [3:0] read_region_reg = 4'd0, read_region_next;
logic [AUSER_W-1:0] read_auser_reg = '0, read_auser_next;
logic read_addr_valid_reg = 1'b0, read_addr_valid_next;
logic read_last_reg = 1'b0, read_last_next;
logic [7:0] read_count_reg = 8'd0, read_count_next;
logic [2:0] read_size_reg = 3'd0, read_size_next;
logic [1:0] read_burst_reg = 2'd0, read_burst_next;
logic s_axi_arready_reg = 1'b0, s_axi_arready_next;
logic [ID_W-1:0] s_axi_rid_pipe_reg = '0;
logic [DATA_W-1:0] s_axi_rdata_pipe_reg = '0;
logic s_axi_rlast_pipe_reg = 1'b0;
logic [RUSER_W-1:0] s_axi_ruser_pipe_reg = '0;
logic s_axi_rvalid_pipe_reg = 1'b0;
assign s_axi_rd.arready = s_axi_arready_reg;
assign s_axi_rd.rid = PIPELINE_OUTPUT ? s_axi_rid_pipe_reg : ram_rd_resp_id;
assign s_axi_rd.rdata = PIPELINE_OUTPUT ? s_axi_rdata_pipe_reg : ram_rd_resp_data;
assign s_axi_rd.rresp = 2'b00;
assign s_axi_rd.rlast = PIPELINE_OUTPUT ? s_axi_rlast_pipe_reg : ram_rd_resp_last;
assign s_axi_rd.ruser = PIPELINE_OUTPUT ? s_axi_ruser_pipe_reg : ram_rd_resp_user;
assign s_axi_rd.rvalid = PIPELINE_OUTPUT ? s_axi_rvalid_pipe_reg : ram_rd_resp_valid;
assign ram_rd_cmd_id = read_id_reg;
assign ram_rd_cmd_addr = read_addr_reg;
assign ram_rd_cmd_lock = read_lock_reg;
assign ram_rd_cmd_cache = read_cache_reg;
assign ram_rd_cmd_prot = read_prot_reg;
assign ram_rd_cmd_qos = read_qos_reg;
assign ram_rd_cmd_region = read_region_reg;
assign ram_rd_cmd_auser = AUSER_EN ? read_auser_reg : '0;
assign ram_rd_cmd_en = read_addr_valid_reg;
assign ram_rd_cmd_last = read_last_reg;
assign ram_rd_resp_ready = s_axi_rd.rready || (PIPELINE_OUTPUT && !s_axi_rvalid_pipe_reg);
always_comb begin
state_next = STATE_IDLE;
read_id_next = read_id_reg;
read_addr_next = read_addr_reg;
read_lock_next = read_lock_reg;
read_cache_next = read_cache_reg;
read_prot_next = read_prot_reg;
read_qos_next = read_qos_reg;
read_region_next = read_region_reg;
read_auser_next = read_auser_reg;
read_addr_valid_next = read_addr_valid_reg && !ram_rd_cmd_ready;
read_last_next = read_last_reg;
read_count_next = read_count_reg;
read_size_next = read_size_reg;
read_burst_next = read_burst_reg;
s_axi_arready_next = 1'b0;
case (state_reg)
STATE_IDLE: begin
s_axi_arready_next = 1'b1;
if (s_axi_rd.arready && s_axi_rd.arvalid) begin
read_id_next = s_axi_rd.arid;
read_addr_next = ADDR_W'(s_axi_rd.araddr);
read_lock_next = s_axi_rd.arlock;
read_cache_next = s_axi_rd.arcache;
read_prot_next = s_axi_rd.arprot;
read_qos_next = s_axi_rd.arqos;
read_region_next = s_axi_rd.arregion;
read_auser_next = AUSER_W'(s_axi_rd.aruser);
read_count_next = s_axi_rd.arlen;
read_size_next = s_axi_rd.arsize <= 3'($clog2(STRB_W)) ? s_axi_rd.arsize : 3'($clog2(STRB_W));
read_burst_next = s_axi_rd.arburst;
s_axi_arready_next = 1'b0;
read_last_next = read_count_next == 0;
read_addr_valid_next = 1'b1;
state_next = STATE_BURST;
end else begin
state_next = STATE_IDLE;
end
end
STATE_BURST: begin
if (ram_rd_cmd_ready && ram_rd_cmd_en) begin
if (read_burst_reg != 2'b00) begin
read_addr_next = read_addr_reg + (1 << read_size_reg);
end
read_count_next = read_count_reg - 1;
read_last_next = read_count_next == 0;
if (read_count_reg > 0) begin
read_addr_valid_next = 1'b1;
state_next = STATE_BURST;
end else begin
s_axi_arready_next = 1'b1;
state_next = STATE_IDLE;
end
end else begin
state_next = STATE_BURST;
end
end
endcase
end
always_ff @(posedge clk) begin
state_reg <= state_next;
read_id_reg <= read_id_next;
read_addr_reg <= read_addr_next;
read_lock_reg <= read_lock_next;
read_cache_reg <= read_cache_next;
read_prot_reg <= read_prot_next;
read_qos_reg <= read_qos_next;
read_region_reg <= read_region_next;
read_auser_reg <= read_auser_next;
read_addr_valid_reg <= read_addr_valid_next;
read_last_reg <= read_last_next;
read_count_reg <= read_count_next;
read_size_reg <= read_size_next;
read_burst_reg <= read_burst_next;
s_axi_arready_reg <= s_axi_arready_next;
if (!s_axi_rvalid_pipe_reg || s_axi_rd.rready) begin
s_axi_rid_pipe_reg <= ram_rd_resp_id;
s_axi_rdata_pipe_reg <= ram_rd_resp_data;
s_axi_rlast_pipe_reg <= ram_rd_resp_last;
s_axi_ruser_pipe_reg <= ram_rd_resp_user;
s_axi_rvalid_pipe_reg <= ram_rd_resp_valid;
end
if (rst) begin
state_reg <= STATE_IDLE;
read_addr_valid_reg <= 1'b0;
s_axi_arready_reg <= 1'b0;
s_axi_rvalid_pipe_reg <= 1'b0;
end
end
endmodule
`resetall

View File

@@ -0,0 +1,4 @@
taxi_axi_ram_if_wr.sv
taxi_axi_ram_if_rd.sv
taxi_axi_ram_if_rdwr.sv
taxi_axi_if.sv

View File

@@ -0,0 +1,236 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2019-2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4 RAM read/write interface
*/
module taxi_axi_ram_if_rdwr #
(
// Width of data bus in bits
parameter DATA_W = 32,
// Width of address bus in bits
parameter ADDR_W = 16,
// Width of wstrb (width of data bus in words)
parameter STRB_W = (DATA_W/8),
// Width of ID signal
parameter ID_W = 8,
// Width of auser output
parameter AUSER_W = 1,
// Width of wuser signal
parameter WUSER_W = 1,
// Width of ruser signal
parameter RUSER_W = 1,
// Extra pipeline register on output
parameter logic PIPELINE_OUTPUT = 1'b0,
// Interleave read and write burst cycles
parameter logic INTERLEAVE = 1'b0
)
(
input wire logic clk,
input wire logic rst,
/*
* AXI4 slave interface
*/
taxi_axi_if.wr_slv s_axi_wr,
taxi_axi_if.rd_slv s_axi_rd,
/*
* RAM interface
*/
output wire [ID_W-1:0] ram_cmd_id,
output wire [ADDR_W-1:0] ram_cmd_addr,
output wire ram_cmd_lock,
output wire [3:0] ram_cmd_cache,
output wire [2:0] ram_cmd_prot,
output wire [3:0] ram_cmd_qos,
output wire [3:0] ram_cmd_region,
output wire [AUSER_W-1:0] ram_cmd_auser,
output wire [DATA_W-1:0] ram_cmd_wr_data,
output wire [STRB_W-1:0] ram_cmd_wr_strb,
output wire [WUSER_W-1:0] ram_cmd_wr_user,
output wire ram_cmd_wr_en,
output wire ram_cmd_rd_en,
output wire ram_cmd_last,
input wire ram_cmd_ready,
input wire [ID_W-1:0] ram_rd_resp_id,
input wire [DATA_W-1:0] ram_rd_resp_data,
input wire ram_rd_resp_last,
input wire [RUSER_W-1:0] ram_rd_resp_user,
input wire ram_rd_resp_valid,
output wire ram_rd_resp_ready
);
wire [ID_W-1:0] ram_wr_cmd_id;
wire [ADDR_W-1:0] ram_wr_cmd_addr;
wire ram_wr_cmd_lock;
wire [3:0] ram_wr_cmd_cache;
wire [2:0] ram_wr_cmd_prot;
wire [3:0] ram_wr_cmd_qos;
wire [3:0] ram_wr_cmd_region;
wire [AUSER_W-1:0] ram_wr_cmd_auser;
wire ram_wr_cmd_en;
wire ram_wr_cmd_last;
wire ram_wr_cmd_ready;
wire [ID_W-1:0] ram_rd_cmd_id;
wire [ADDR_W-1:0] ram_rd_cmd_addr;
wire ram_rd_cmd_lock;
wire [3:0] ram_rd_cmd_cache;
wire [2:0] ram_rd_cmd_prot;
wire [3:0] ram_rd_cmd_qos;
wire [3:0] ram_rd_cmd_region;
wire [AUSER_W-1:0] ram_rd_cmd_auser;
wire ram_rd_cmd_en;
wire ram_rd_cmd_last;
wire ram_rd_cmd_ready;
taxi_axi_ram_if_wr #(
.DATA_W(DATA_W),
.ADDR_W(ADDR_W),
.STRB_W(STRB_W),
.ID_W(ID_W),
.AUSER_W(AUSER_W),
.WUSER_W(WUSER_W)
)
wr_inst (
.clk(clk),
.rst(rst),
/*
* AXI4 slave interface
*/
.s_axi_wr(s_axi_wr),
/*
* RAM interface
*/
.ram_wr_cmd_id(ram_wr_cmd_id),
.ram_wr_cmd_addr(ram_wr_cmd_addr),
.ram_wr_cmd_lock(ram_wr_cmd_lock),
.ram_wr_cmd_cache(ram_wr_cmd_cache),
.ram_wr_cmd_prot(ram_wr_cmd_prot),
.ram_wr_cmd_qos(ram_wr_cmd_qos),
.ram_wr_cmd_region(ram_wr_cmd_region),
.ram_wr_cmd_auser(ram_wr_cmd_auser),
.ram_wr_cmd_data(ram_cmd_wr_data),
.ram_wr_cmd_strb(ram_cmd_wr_strb),
.ram_wr_cmd_user(ram_cmd_wr_user),
.ram_wr_cmd_en(ram_wr_cmd_en),
.ram_wr_cmd_last(ram_wr_cmd_last),
.ram_wr_cmd_ready(ram_wr_cmd_ready)
);
taxi_axi_ram_if_rd #(
.DATA_W(DATA_W),
.ADDR_W(ADDR_W),
.STRB_W(STRB_W),
.ID_W(ID_W),
.AUSER_W(AUSER_W),
.RUSER_W(RUSER_W),
.PIPELINE_OUTPUT(PIPELINE_OUTPUT)
)
rd_inst (
.clk(clk),
.rst(rst),
/*
* AXI4 slave interface
*/
.s_axi_rd(s_axi_rd),
/*
* RAM interface
*/
.ram_rd_cmd_id(ram_rd_cmd_id),
.ram_rd_cmd_addr(ram_rd_cmd_addr),
.ram_rd_cmd_lock(ram_rd_cmd_lock),
.ram_rd_cmd_cache(ram_rd_cmd_cache),
.ram_rd_cmd_prot(ram_rd_cmd_prot),
.ram_rd_cmd_qos(ram_rd_cmd_qos),
.ram_rd_cmd_region(ram_rd_cmd_region),
.ram_rd_cmd_auser(ram_rd_cmd_auser),
.ram_rd_cmd_en(ram_rd_cmd_en),
.ram_rd_cmd_last(ram_rd_cmd_last),
.ram_rd_cmd_ready(ram_rd_cmd_ready),
.ram_rd_resp_id(ram_rd_resp_id),
.ram_rd_resp_data(ram_rd_resp_data),
.ram_rd_resp_last(ram_rd_resp_last),
.ram_rd_resp_user(ram_rd_resp_user),
.ram_rd_resp_valid(ram_rd_resp_valid),
.ram_rd_resp_ready(ram_rd_resp_ready)
);
// arbitration
logic read_eligible;
logic write_eligible;
logic write_en;
logic read_en;
logic last_read_reg = 1'b0, last_read_next;
logic transaction_reg = 1'b0, transaction_next;
assign ram_cmd_wr_en = write_en;
assign ram_cmd_rd_en = read_en;
assign ram_cmd_id = ram_cmd_rd_en ? ram_rd_cmd_id : ram_wr_cmd_id;
assign ram_cmd_addr = ram_cmd_rd_en ? ram_rd_cmd_addr : ram_wr_cmd_addr;
assign ram_cmd_lock = ram_cmd_rd_en ? ram_rd_cmd_lock : ram_wr_cmd_lock;
assign ram_cmd_cache = ram_cmd_rd_en ? ram_rd_cmd_cache : ram_wr_cmd_cache;
assign ram_cmd_prot = ram_cmd_rd_en ? ram_rd_cmd_prot : ram_wr_cmd_prot;
assign ram_cmd_qos = ram_cmd_rd_en ? ram_rd_cmd_qos : ram_wr_cmd_qos;
assign ram_cmd_region = ram_cmd_rd_en ? ram_rd_cmd_region : ram_wr_cmd_region;
assign ram_cmd_auser = ram_cmd_rd_en ? ram_rd_cmd_auser : ram_wr_cmd_auser;
assign ram_cmd_last = ram_cmd_rd_en ? ram_rd_cmd_last : ram_wr_cmd_last;
assign ram_wr_cmd_ready = ram_cmd_ready && write_en;
assign ram_rd_cmd_ready = ram_cmd_ready && read_en;
always_comb begin
write_en = 1'b0;
read_en = 1'b0;
last_read_next = last_read_reg;
transaction_next = transaction_reg;
write_eligible = ram_wr_cmd_en && ram_cmd_ready;
read_eligible = ram_rd_cmd_en && ram_cmd_ready;
if (write_eligible && (!read_eligible || last_read_reg || (!INTERLEAVE && transaction_reg)) && (INTERLEAVE || !transaction_reg || !last_read_reg)) begin
last_read_next = 1'b0;
transaction_next = !ram_wr_cmd_last;
write_en = 1'b1;
end else if (read_eligible && (INTERLEAVE || !transaction_reg || last_read_reg)) begin
last_read_next = 1'b1;
transaction_next = !ram_rd_cmd_last;
read_en = 1'b1;
end
end
always_ff @(posedge clk) begin
last_read_reg <= last_read_next;
transaction_reg <= transaction_next;
if (rst) begin
last_read_reg <= 1'b0;
transaction_reg <= 1'b0;
end
end
endmodule
`resetall

View File

@@ -0,0 +1,257 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2019-2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4 RAM write interface
*/
module taxi_axi_ram_if_wr #
(
// Width of data bus in bits
parameter DATA_W = 32,
// Width of address bus in bits
parameter ADDR_W = 16,
// Width of wstrb (width of data bus in words)
parameter STRB_W = (DATA_W/8),
// Width of ID signal
parameter ID_W = 8,
// Width of auser signal
parameter AUSER_W = 1,
// Width of wuser signal
parameter WUSER_W = 1
)
(
input wire logic clk,
input wire logic rst,
/*
* AXI4 slave interface
*/
taxi_axi_if.wr_slv s_axi_wr,
/*
* RAM interface
*/
output wire logic [ID_W-1:0] ram_wr_cmd_id,
output wire logic [ADDR_W-1:0] ram_wr_cmd_addr,
output wire logic ram_wr_cmd_lock,
output wire logic [3:0] ram_wr_cmd_cache,
output wire logic [2:0] ram_wr_cmd_prot,
output wire logic [3:0] ram_wr_cmd_qos,
output wire logic [3:0] ram_wr_cmd_region,
output wire logic [AUSER_W-1:0] ram_wr_cmd_auser,
output wire logic [DATA_W-1:0] ram_wr_cmd_data,
output wire logic [STRB_W-1:0] ram_wr_cmd_strb,
output wire logic [WUSER_W-1:0] ram_wr_cmd_user,
output wire logic ram_wr_cmd_en,
output wire logic ram_wr_cmd_last,
input wire logic ram_wr_cmd_ready
);
// extract parameters
localparam logic AUSER_EN = s_axi_wr.AWUSER_EN;
localparam logic WUSER_EN = s_axi_wr.WUSER_EN;
localparam VALID_ADDR_W = ADDR_W - $clog2(STRB_W);
localparam BYTE_LANES = STRB_W;
localparam BYTE_W = DATA_W/BYTE_LANES;
// check configuration
if (BYTE_W * STRB_W != DATA_W)
$fatal(0, "Error: AXI data width not evenly divisible (instance %m)");
if (2**$clog2(BYTE_LANES) != BYTE_LANES)
$fatal(0, "Error: AXI word width must be even power of two (instance %m)");
if (s_axi_wr.ADDR_W < ADDR_W)
$fatal(0, "Error: AXI address width is insufficient (instance %m)");
if (s_axi_wr.AWUSER_EN && s_axi_wr.AWUSER_W > AUSER_W)
$fatal(0, "Error: AUESR_W setting is insufficient (instance %m)");
if (s_axi_wr.WUSER_EN && s_axi_wr.WUSER_W > WUSER_W)
$fatal(0, "Error: WUESR_W setting is insufficient (instance %m)");
typedef enum logic [1:0] {
STATE_IDLE,
STATE_BURST,
STATE_RESP
} state_t;
state_t state_reg = STATE_IDLE, state_next;
logic [ID_W-1:0] write_id_reg = '0, write_id_next;
logic [ADDR_W-1:0] write_addr_reg = '0, write_addr_next;
logic write_lock_reg = 1'b0, write_lock_next;
logic [3:0] write_cache_reg = 4'd0, write_cache_next;
logic [2:0] write_prot_reg = 3'd0, write_prot_next;
logic [3:0] write_qos_reg = 4'd0, write_qos_next;
logic [3:0] write_region_reg = 4'd0, write_region_next;
logic [AUSER_W-1:0] write_auser_reg = '0, write_auser_next;
logic write_addr_valid_reg = 1'b0, write_addr_valid_next;
logic write_last_reg = 1'b0, write_last_next;
logic [7:0] write_count_reg = 8'd0, write_count_next;
logic [2:0] write_size_reg = 3'd0, write_size_next;
logic [1:0] write_burst_reg = 2'd0, write_burst_next;
logic s_axi_awready_reg = 1'b0, s_axi_awready_next;
logic [ID_W-1:0] s_axi_bid_reg = '0, s_axi_bid_next;
logic s_axi_bvalid_reg = 1'b0, s_axi_bvalid_next;
assign s_axi_wr.awready = s_axi_awready_reg;
assign s_axi_wr.wready = write_addr_valid_reg && ram_wr_cmd_ready;
assign s_axi_wr.bid = s_axi_bid_reg;
assign s_axi_wr.bresp = 2'b00;
assign s_axi_wr.buser = '0;
assign s_axi_wr.bvalid = s_axi_bvalid_reg;
assign ram_wr_cmd_id = write_id_reg;
assign ram_wr_cmd_addr = write_addr_reg;
assign ram_wr_cmd_lock = write_lock_reg;
assign ram_wr_cmd_cache = write_cache_reg;
assign ram_wr_cmd_prot = write_prot_reg;
assign ram_wr_cmd_qos = write_qos_reg;
assign ram_wr_cmd_region = write_region_reg;
assign ram_wr_cmd_auser = AUSER_EN ? write_auser_reg : '0;
assign ram_wr_cmd_data = s_axi_wr.wdata;
assign ram_wr_cmd_strb = s_axi_wr.wstrb;
assign ram_wr_cmd_user = WUSER_EN ? s_axi_wr.wuser : '0;
assign ram_wr_cmd_en = write_addr_valid_reg && s_axi_wr.wvalid;
assign ram_wr_cmd_last = write_last_reg;
always_comb begin
state_next = STATE_IDLE;
write_id_next = write_id_reg;
write_addr_next = write_addr_reg;
write_lock_next = write_lock_reg;
write_cache_next = write_cache_reg;
write_prot_next = write_prot_reg;
write_qos_next = write_qos_reg;
write_region_next = write_region_reg;
write_auser_next = write_auser_reg;
write_addr_valid_next = write_addr_valid_reg;
write_last_next = write_last_reg;
write_count_next = write_count_reg;
write_size_next = write_size_reg;
write_burst_next = write_burst_reg;
s_axi_awready_next = 1'b0;
s_axi_bid_next = s_axi_bid_reg;
s_axi_bvalid_next = s_axi_bvalid_reg && !s_axi_wr.bready;
case (state_reg)
STATE_IDLE: begin
s_axi_awready_next = 1'b1;
if (s_axi_wr.awready && s_axi_wr.awvalid) begin
write_id_next = s_axi_wr.awid;
write_addr_next = ADDR_W'(s_axi_wr.awaddr);
write_lock_next = s_axi_wr.awlock;
write_cache_next = s_axi_wr.awcache;
write_prot_next = s_axi_wr.awprot;
write_qos_next = s_axi_wr.awqos;
write_region_next = s_axi_wr.awregion;
write_auser_next = AUSER_W'(s_axi_wr.awuser);
write_count_next = s_axi_wr.awlen;
write_size_next = s_axi_wr.awsize <= 3'($clog2(STRB_W)) ? s_axi_wr.awsize : 3'($clog2(STRB_W));
write_burst_next = s_axi_wr.awburst;
write_addr_valid_next = 1'b1;
s_axi_awready_next = 1'b0;
if (s_axi_wr.awlen > 0) begin
write_last_next = 1'b0;
end else begin
write_last_next = 1'b1;
end
state_next = STATE_BURST;
end else begin
state_next = STATE_IDLE;
end
end
STATE_BURST: begin
if (s_axi_wr.wready && s_axi_wr.wvalid) begin
if (write_burst_reg != 2'b00) begin
write_addr_next = write_addr_reg + (1 << write_size_reg);
end
write_count_next = write_count_reg - 1;
write_last_next = write_count_next == 0;
if (write_count_reg > 0) begin
write_addr_valid_next = 1'b1;
state_next = STATE_BURST;
end else begin
write_addr_valid_next = 1'b0;
if (s_axi_wr.bready || !s_axi_wr.bvalid) begin
s_axi_bid_next = write_id_reg;
s_axi_bvalid_next = 1'b1;
s_axi_awready_next = 1'b1;
state_next = STATE_IDLE;
end else begin
state_next = STATE_RESP;
end
end
end else begin
state_next = STATE_BURST;
end
end
STATE_RESP: begin
if (s_axi_wr.bready || !s_axi_wr.bvalid) begin
s_axi_bid_next = write_id_reg;
s_axi_bvalid_next = 1'b1;
s_axi_awready_next = 1'b1;
state_next = STATE_IDLE;
end else begin
state_next = STATE_RESP;
end
end
default: begin
// unknown state
state_next = STATE_IDLE;
end
endcase
end
always_ff @(posedge clk) begin
state_reg <= state_next;
write_id_reg <= write_id_next;
write_addr_reg <= write_addr_next;
write_lock_reg <= write_lock_next;
write_cache_reg <= write_cache_next;
write_prot_reg <= write_prot_next;
write_qos_reg <= write_qos_next;
write_region_reg <= write_region_next;
write_auser_reg <= write_auser_next;
write_addr_valid_reg <= write_addr_valid_next;
write_last_reg <= write_last_next;
write_count_reg <= write_count_next;
write_size_reg <= write_size_next;
write_burst_reg <= write_burst_next;
s_axi_awready_reg <= s_axi_awready_next;
s_axi_bid_reg <= s_axi_bid_next;
s_axi_bvalid_reg <= s_axi_bvalid_next;
if (rst) begin
state_reg <= STATE_IDLE;
write_addr_valid_reg <= 1'b0;
s_axi_awready_reg <= 1'b0;
s_axi_bvalid_reg <= 1'b0;
end
end
endmodule
`resetall

View File

@@ -39,14 +39,20 @@ localparam logic RUSER_EN = s_axi_rd.RUSER_EN && m_axi_rd.RUSER_EN;
localparam RUSER_W = s_axi_rd.RUSER_W; localparam RUSER_W = s_axi_rd.RUSER_W;
// check configuration // check configuration
if (m_axi_rd.ADDR_W > ADDR_W)
$fatal(0, "Error: Output ADDR_W is wider than input ADDR_W, cannot access entire address space (instance %m)");
if (m_axi_rd.DATA_W != DATA_W) if (m_axi_rd.DATA_W != DATA_W)
$fatal(0, "Error: Interface DATA_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface DATA_W parameter mismatch (instance %m)");
if (m_axi_rd.STRB_W != STRB_W) if (m_axi_rd.STRB_W != STRB_W)
$fatal(0, "Error: Interface STRB_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface STRB_W parameter mismatch (instance %m)");
assign m_axi_rd.arid = s_axi_rd.arid; if (m_axi_rd.ID_W < ID_W)
assign m_axi_rd.araddr = s_axi_rd.araddr; $fatal(0, "Error: Output ID_W is narrower than input ID_W, cannot discard ID bits (instance %m)");
assign m_axi_rd.arid = m_axi_rd.ID_W'(s_axi_rd.arid);
assign m_axi_rd.araddr = m_axi_rd.ADDR_W'(s_axi_rd.araddr);
assign m_axi_rd.arlen = s_axi_rd.arlen; assign m_axi_rd.arlen = s_axi_rd.arlen;
assign m_axi_rd.arsize = s_axi_rd.arsize; assign m_axi_rd.arsize = s_axi_rd.arsize;
assign m_axi_rd.arburst = s_axi_rd.arburst; assign m_axi_rd.arburst = s_axi_rd.arburst;
@@ -59,7 +65,7 @@ assign m_axi_rd.aruser = ARUSER_EN ? s_axi_rd.aruser : '0;
assign m_axi_rd.arvalid = s_axi_rd.arvalid; assign m_axi_rd.arvalid = s_axi_rd.arvalid;
assign s_axi_rd.arready = m_axi_rd.arready; assign s_axi_rd.arready = m_axi_rd.arready;
assign s_axi_rd.rid = m_axi_rd.rid; assign s_axi_rd.rid = s_axi_rd.ID_W'(m_axi_rd.rid);
assign s_axi_rd.rdata = m_axi_rd.rdata; assign s_axi_rd.rdata = m_axi_rd.rdata;
assign s_axi_rd.rresp = m_axi_rd.rresp; assign s_axi_rd.rresp = m_axi_rd.rresp;
assign s_axi_rd.rlast = m_axi_rd.rlast; assign s_axi_rd.rlast = m_axi_rd.rlast;

View File

@@ -41,15 +41,20 @@ localparam logic BUSER_EN = s_axi_wr.BUSER_EN && m_axi_wr.BUSER_EN;
localparam BUSER_W = s_axi_wr.BUSER_W; localparam BUSER_W = s_axi_wr.BUSER_W;
// check configuration // check configuration
if (m_axi_wr.ADDR_W > ADDR_W)
$fatal(0, "Error: Output ADDR_W is wider than input ADDR_W, cannot access entire address space (instance %m)");
if (m_axi_wr.DATA_W != DATA_W) if (m_axi_wr.DATA_W != DATA_W)
$fatal(0, "Error: Interface DATA_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface DATA_W parameter mismatch (instance %m)");
if (m_axi_wr.STRB_W != STRB_W) if (m_axi_wr.STRB_W != STRB_W)
$fatal(0, "Error: Interface STRB_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface STRB_W parameter mismatch (instance %m)");
// bypass AW channel if (m_axi_wr.ID_W < ID_W)
assign m_axi_wr.awid = s_axi_wr.awid; $fatal(0, "Error: Output ID_W is narrower than input ID_W, cannot discard ID bits (instance %m)");
assign m_axi_wr.awaddr = s_axi_wr.awaddr;
assign m_axi_wr.awid = m_axi_wr.ID_W'(s_axi_wr.awid);
assign m_axi_wr.awaddr = m_axi_wr.ADDR_W'(s_axi_wr.awaddr);
assign m_axi_wr.awlen = s_axi_wr.awlen; assign m_axi_wr.awlen = s_axi_wr.awlen;
assign m_axi_wr.awsize = s_axi_wr.awsize; assign m_axi_wr.awsize = s_axi_wr.awsize;
assign m_axi_wr.awburst = s_axi_wr.awburst; assign m_axi_wr.awburst = s_axi_wr.awburst;
@@ -69,7 +74,7 @@ assign m_axi_wr.wuser = WUSER_EN ? s_axi_wr.wuser : '0;
assign m_axi_wr.wvalid = s_axi_wr.wvalid; assign m_axi_wr.wvalid = s_axi_wr.wvalid;
assign s_axi_wr.wready = m_axi_wr.wready; assign s_axi_wr.wready = m_axi_wr.wready;
assign s_axi_wr.bid = m_axi_wr.bid; assign s_axi_wr.bid = s_axi_wr.ID_W'(m_axi_wr.bid);
assign s_axi_wr.bresp = m_axi_wr.bresp; assign s_axi_wr.bresp = m_axi_wr.bresp;
assign s_axi_wr.buser = BUSER_EN ? m_axi_wr.buser : '0; assign s_axi_wr.buser = BUSER_EN ? m_axi_wr.buser : '0;
assign s_axi_wr.bvalid = m_axi_wr.bvalid; assign s_axi_wr.bvalid = m_axi_wr.bvalid;

View File

@@ -420,10 +420,13 @@ end else if (APB_BYTE_LANES > AXIL_BYTE_LANES) begin : upsize
end end
end end
STATE_DATA: begin STATE_DATA: begin
s_axil_buser_next = m_apb.pbuser; if (m_apb_pwrite_reg) begin
s_axil_rdata_next = m_apb.prdata[m_apb_paddr_reg[APB_ADDR_BIT_OFFSET - 1:AXIL_ADDR_BIT_OFFSET] * AXIL_DATA_W +: AXIL_DATA_W]; s_axil_buser_next = m_apb.pbuser;
s_axil_ruser_next = m_apb.pruser; end else begin
s_axil_resp_next = m_apb.pslverr ? AXI_RESP_SLVERR : AXI_RESP_OKAY; s_axil_rdata_next = m_apb.prdata[m_apb_paddr_reg[APB_ADDR_BIT_OFFSET - 1:AXIL_ADDR_BIT_OFFSET] * AXIL_DATA_W +: AXIL_DATA_W];
s_axil_ruser_next = m_apb.pruser;
s_axil_resp_next = m_apb.pslverr ? AXI_RESP_SLVERR : AXI_RESP_OKAY;
end
m_apb_psel_next = 1'b1; m_apb_psel_next = 1'b1;
m_apb_penable_next = 1'b1; m_apb_penable_next = 1'b1;
@@ -603,8 +606,11 @@ end else begin : downsize
case (state_reg) case (state_reg)
STATE_IDLE: begin STATE_IDLE: begin
current_seg_next = s_axil_wr.awaddr[APB_ADDR_BIT_OFFSET +: SEG_COUNT_W];
data_next = s_axil_wr.wdata; data_next = s_axil_wr.wdata;
strb_next = s_axil_wr.wstrb; strb_next = s_axil_wr.wstrb;
m_apb_pwdata_next = data_next[current_seg_next*SEG_DATA_W +: SEG_DATA_W];
m_apb_pstrb_next = strb_next[current_seg_next*SEG_STRB_W +: SEG_STRB_W];
s_axil_resp_next = AXI_RESP_OKAY; s_axil_resp_next = AXI_RESP_OKAY;
@@ -646,26 +652,27 @@ end else begin : downsize
end end
end end
STATE_DATA: begin STATE_DATA: begin
m_apb_pwdata_next = data_next[current_seg_reg*SEG_DATA_W +: SEG_DATA_W];
m_apb_pstrb_next = strb_next[current_seg_reg*SEG_STRB_W +: SEG_STRB_W];
s_axil_buser_next = m_apb.pbuser;
s_axil_rdata_next[current_seg_reg*SEG_DATA_W +: SEG_DATA_W] = m_apb.prdata;
s_axil_ruser_next = m_apb.pruser;
m_apb_psel_next = 1'b1; m_apb_psel_next = 1'b1;
m_apb_penable_next = 1'b1; m_apb_penable_next = 1'b1;
if (m_apb_pwrite_reg) begin
s_axil_buser_next = m_apb.pbuser;
end else begin
s_axil_rdata_next[current_seg_reg*SEG_DATA_W +: SEG_DATA_W] = m_apb.prdata;
s_axil_ruser_next = m_apb.pruser;
end
if (m_apb.psel && m_apb.penable && m_apb.pready) begin if (m_apb.psel && m_apb.penable && m_apb.pready) begin
if (m_apb.pslverr) begin if (m_apb.pslverr) begin
s_axil_resp_next = AXI_RESP_SLVERR; s_axil_resp_next = AXI_RESP_SLVERR;
end end
m_apb_paddr_next = (m_apb_paddr_reg & APB_ADDR_MASK) + SEG_STRB_W;
m_apb_penable_next = 1'b0; m_apb_penable_next = 1'b0;
current_seg_next = current_seg_reg + 1; current_seg_next = current_seg_reg + 1;
m_apb_paddr_next = (m_apb_paddr_reg & APB_ADDR_MASK) + SEG_STRB_W;
if (&current_seg_reg) begin m_apb_pwdata_next = data_next[current_seg_next*SEG_DATA_W +: SEG_DATA_W];
m_apb_pstrb_next = strb_next[current_seg_next*SEG_STRB_W +: SEG_STRB_W];
if (current_seg_reg == SEG_COUNT_W'(SEG_COUNT-1)) begin
if (m_apb_pwrite_reg) begin if (m_apb_pwrite_reg) begin
s_axil_bvalid_next = 1'b1; s_axil_bvalid_next = 1'b1;
end else begin end else begin

View File

@@ -23,11 +23,9 @@ module taxi_axil_interconnect #
parameter M_COUNT = 4, parameter M_COUNT = 4,
// Address width in bits for address decoding // Address width in bits for address decoding
parameter ADDR_W = 32, parameter ADDR_W = 32,
// TODO fix parametrization once verilator issue 5890 is fixed
// Number of concurrent operations for each slave interface
// S_COUNT concatenated fields of 32 bits
// Number of regions per master interface // Number of regions per master interface
parameter M_REGIONS = 1, parameter M_REGIONS = 1,
// TODO fix parametrization once verilator issue 5890 is fixed
// Master interface base addresses // Master interface base addresses
// M_COUNT concatenated fields of M_REGIONS concatenated fields of ADDR_W bits // M_COUNT concatenated fields of M_REGIONS concatenated fields of ADDR_W bits
// set to zero for default addressing based on M_ADDR_W // set to zero for default addressing based on M_ADDR_W

View File

@@ -38,13 +38,16 @@ localparam logic RUSER_EN = s_axil_rd.RUSER_EN && m_axil_rd.RUSER_EN;
localparam RUSER_W = s_axil_rd.RUSER_W; localparam RUSER_W = s_axil_rd.RUSER_W;
// check configuration // check configuration
if (m_axil_rd.ADDR_W > ADDR_W)
$fatal(0, "Error: Output ADDR_W is wider than input ADDR_W, cannot access entire address space (instance %m)");
if (m_axil_rd.DATA_W != DATA_W) if (m_axil_rd.DATA_W != DATA_W)
$fatal(0, "Error: Interface DATA_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface DATA_W parameter mismatch (instance %m)");
if (m_axil_rd.STRB_W != STRB_W) if (m_axil_rd.STRB_W != STRB_W)
$fatal(0, "Error: Interface STRB_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface STRB_W parameter mismatch (instance %m)");
assign m_axil_rd.araddr = s_axil_rd.araddr; assign m_axil_rd.araddr = m_axil_rd.ADDR_W'(s_axil_rd.araddr);
assign m_axil_rd.arprot = s_axil_rd.arprot; assign m_axil_rd.arprot = s_axil_rd.arprot;
assign m_axil_rd.aruser = ARUSER_EN ? s_axil_rd.aruser : '0; assign m_axil_rd.aruser = ARUSER_EN ? s_axil_rd.aruser : '0;
assign m_axil_rd.arvalid = s_axil_rd.arvalid; assign m_axil_rd.arvalid = s_axil_rd.arvalid;

View File

@@ -40,6 +40,9 @@ localparam logic BUSER_EN = s_axil_wr.BUSER_EN && m_axil_wr.BUSER_EN;
localparam BUSER_W = s_axil_wr.BUSER_W; localparam BUSER_W = s_axil_wr.BUSER_W;
// check configuration // check configuration
if (m_axil_wr.ADDR_W > ADDR_W)
$fatal(0, "Error: Output ADDR_W is wider than input ADDR_W, cannot access entire address space (instance %m)");
if (m_axil_wr.DATA_W != DATA_W) if (m_axil_wr.DATA_W != DATA_W)
$fatal(0, "Error: Interface DATA_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface DATA_W parameter mismatch (instance %m)");
@@ -47,7 +50,7 @@ if (m_axil_wr.STRB_W != STRB_W)
$fatal(0, "Error: Interface STRB_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface STRB_W parameter mismatch (instance %m)");
// bypass AW channel // bypass AW channel
assign m_axil_wr.awaddr = s_axil_wr.awaddr; assign m_axil_wr.awaddr = m_axil_wr.ADDR_W'(s_axil_wr.awaddr);
assign m_axil_wr.awprot = s_axil_wr.awprot; assign m_axil_wr.awprot = s_axil_wr.awprot;
assign m_axil_wr.awuser = AWUSER_EN ? s_axil_wr.awuser : '0; assign m_axil_wr.awuser = AWUSER_EN ? s_axil_wr.awuser : '0;
assign m_axil_wr.awvalid = s_axil_wr.awvalid; assign m_axil_wr.awvalid = s_axil_wr.awvalid;

View File

@@ -186,6 +186,8 @@ if getattr(cocotb, 'top', None) is not None:
factory.generate_tests() factory.generate_tests()
factory = TestFactory(run_stress_test) factory = TestFactory(run_stress_test)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests() factory.generate_tests()

View File

@@ -204,6 +204,8 @@ if getattr(cocotb, 'top', None) is not None:
factory.generate_tests() factory.generate_tests()
factory = TestFactory(run_stress_test) factory = TestFactory(run_stress_test)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests() factory.generate_tests()

View File

@@ -200,6 +200,8 @@ if getattr(cocotb, 'top', None) is not None:
factory.generate_tests() factory.generate_tests()
factory = TestFactory(run_stress_test) factory = TestFactory(run_stress_test)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests() factory.generate_tests()

View File

@@ -0,0 +1,57 @@
# SPDX-License-Identifier: CERN-OHL-S-2.0
#
# Copyright (c) 2020-2026 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
TOPLEVEL_LANG = verilog
SIM ?= verilator
WAVES ?= 0
COCOTB_HDL_TIMEUNIT = 1ns
COCOTB_HDL_TIMEPRECISION = 1ps
RTL_DIR = ../../rtl
LIB_DIR = ../../lib
TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
DUT = taxi_axi_dp_ram
COCOTB_TEST_MODULES = test_$(DUT)
COCOTB_TOPLEVEL = test_$(DUT)
MODULE = $(COCOTB_TEST_MODULES)
TOPLEVEL = $(COCOTB_TOPLEVEL)
VERILOG_SOURCES += $(COCOTB_TOPLEVEL).sv
VERILOG_SOURCES += $(RTL_DIR)/$(DUT).f
# handle file list files
process_f_file = $(call process_f_files,$(addprefix $(dir $1),$(shell cat $1)))
process_f_files = $(foreach f,$1,$(if $(filter %.f,$f),$(call process_f_file,$f),$f))
uniq_base = $(if $1,$(call uniq_base,$(foreach f,$1,$(if $(filter-out $(notdir $(lastword $1)),$(notdir $f)),$f,))) $(lastword $1))
VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES)))
# module parameters
export PARAM_DATA_W := 32
export PARAM_ADDR_W := 16
export PARAM_STRB_W := $(shell expr $(PARAM_DATA_W) / 8 )
export PARAM_ID_W := 8
export PARAM_A_PIPELINE_OUTPUT := 0
export PARAM_B_PIPELINE_OUTPUT := 0
export PARAM_A_INTERLEAVE := 0
export PARAM_B_INTERLEAVE := 0
ifeq ($(SIM), icarus)
PLUSARGS += -fst
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-P $(COCOTB_TOPLEVEL).$(subst PARAM_,,$(v))=$($(v)))
else ifeq ($(SIM), verilator)
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(v))=$($(v)))
ifeq ($(WAVES), 1)
COMPILE_ARGS += --trace-fst
VERILATOR_TRACE = 1
endif
endif
include $(shell cocotb-config --makefiles)/Makefile.sim

View File

@@ -0,0 +1,292 @@
#!/usr/bin/env python
# SPDX-License-Identifier: CERN-OHL-S-2.0
"""
Copyright (c) 2020-2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
"""
import itertools
import logging
import os
import random
import cocotb_test.simulator
import pytest
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, Timer
from cocotb.regression import TestFactory
from cocotbext.axi import AxiBus, AxiMaster
class TB(object):
def __init__(self, dut):
self.dut = dut
self.log = logging.getLogger("cocotb.tb")
self.log.setLevel(logging.DEBUG)
cocotb.start_soon(Clock(dut.a_clk, 8, units="ns").start())
cocotb.start_soon(Clock(dut.b_clk, 10, units="ns").start())
self.axi_master = []
self.axi_master.append(AxiMaster(AxiBus.from_entity(dut.s_axi_a), dut.a_clk, dut.a_rst))
self.axi_master.append(AxiMaster(AxiBus.from_entity(dut.s_axi_b), dut.b_clk, dut.b_rst))
def set_idle_generator(self, generator=None):
if generator:
for axi_master in self.axi_master:
axi_master.write_if.aw_channel.set_pause_generator(generator())
axi_master.write_if.w_channel.set_pause_generator(generator())
axi_master.read_if.ar_channel.set_pause_generator(generator())
def set_backpressure_generator(self, generator=None):
if generator:
for axi_master in self.axi_master:
axi_master.write_if.b_channel.set_pause_generator(generator())
axi_master.read_if.r_channel.set_pause_generator(generator())
async def cycle_reset(self):
self.dut.a_rst.setimmediatevalue(0)
self.dut.b_rst.setimmediatevalue(0)
await RisingEdge(self.dut.a_clk)
await RisingEdge(self.dut.a_clk)
self.dut.a_rst.value = 1
self.dut.b_rst.value = 1
await RisingEdge(self.dut.a_clk)
await RisingEdge(self.dut.a_clk)
self.dut.a_rst.value = 0
await RisingEdge(self.dut.b_clk)
self.dut.b_rst.value = 0
await RisingEdge(self.dut.a_clk)
await RisingEdge(self.dut.a_clk)
async def run_test_write(dut, port=0, data_in=None, idle_inserter=None, backpressure_inserter=None, size=None):
tb = TB(dut)
axi_master = tb.axi_master[port]
byte_lanes = axi_master.write_if.byte_lanes
max_burst_size = axi_master.write_if.max_burst_size
if size is None:
size = max_burst_size
await tb.cycle_reset()
tb.set_idle_generator(idle_inserter)
tb.set_backpressure_generator(backpressure_inserter)
for length in list(range(1, byte_lanes*2))+[1024]:
for offset in list(range(byte_lanes, byte_lanes*2))+list(range(4096-byte_lanes, 4096)):
tb.log.info("length %d, offset %d, size %d", length, offset, size)
addr = offset+0x1000
test_data = bytearray([x % 256 for x in range(length)])
await axi_master.write(addr-4, b'\xaa'*(length+8))
await axi_master.write(addr, test_data, size=size)
data = await axi_master.read(addr-1, length+2)
assert data.data == b'\xaa'+test_data+b'\xaa'
await RisingEdge(dut.a_clk)
await RisingEdge(dut.a_clk)
async def run_test_read(dut, port=0, data_in=None, idle_inserter=None, backpressure_inserter=None, size=None):
tb = TB(dut)
axi_master = tb.axi_master[port]
byte_lanes = axi_master.write_if.byte_lanes
max_burst_size = axi_master.write_if.max_burst_size
if size is None:
size = max_burst_size
await tb.cycle_reset()
tb.set_idle_generator(idle_inserter)
tb.set_backpressure_generator(backpressure_inserter)
for length in list(range(1, byte_lanes*2))+[1024]:
for offset in list(range(byte_lanes, byte_lanes*2))+list(range(4096-byte_lanes, 4096)):
tb.log.info("length %d, offset %d, size %d", length, offset, size)
addr = offset+0x1000
test_data = bytearray([x % 256 for x in range(length)])
await axi_master.write(addr, test_data)
data = await axi_master.read(addr, length, size=size)
assert data.data == test_data
await RisingEdge(dut.a_clk)
await RisingEdge(dut.a_clk)
async def run_test_arb(dut, data_in=None, idle_inserter=None, backpressure_inserter=None):
tb = TB(dut)
await tb.cycle_reset()
tb.set_idle_generator(idle_inserter)
tb.set_backpressure_generator(backpressure_inserter)
async def worker(master, offset):
wr_op = master.init_write(offset, b'\x11\x22\x33\x44')
rd_op = master.init_read(offset, 4)
await wr_op.wait()
await rd_op.wait()
workers = []
for k in range(10):
workers.append(cocotb.start_soon(worker(tb.axi_master[0], k*256)))
workers.append(cocotb.start_soon(worker(tb.axi_master[1], k*256)))
while workers:
await workers.pop(0).join()
await RisingEdge(dut.a_clk)
await RisingEdge(dut.a_clk)
async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None):
tb = TB(dut)
await tb.cycle_reset()
tb.set_idle_generator(idle_inserter)
tb.set_backpressure_generator(backpressure_inserter)
async def worker(master, offset, aperture, count=16):
for k in range(count):
length = random.randint(1, min(512, aperture))
addr = offset+random.randint(0, aperture-length)
test_data = bytearray([x % 256 for x in range(length)])
await Timer(random.randint(1, 100), 'ns')
await master.write(addr, test_data)
await Timer(random.randint(1, 100), 'ns')
data = await master.read(addr, length)
assert data.data == test_data
workers = []
for k in range(16):
workers.append(cocotb.start_soon(worker(tb.axi_master[k % len(tb.axi_master)], k*0x1000, 0x1000, count=16)))
while workers:
await workers.pop(0).join()
await RisingEdge(dut.a_clk)
await RisingEdge(dut.a_clk)
def cycle_pause():
return itertools.cycle([1, 1, 1, 0])
if getattr(cocotb, 'top', None) is not None:
data_width = len(cocotb.top.s_axi_a.wdata)
byte_lanes = data_width // 8
max_burst_size = (byte_lanes-1).bit_length()
for test in [run_test_write, run_test_read]:
factory = TestFactory(test)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.add_option("size", [None]+list(range(max_burst_size)))
factory.add_option("port", [0, 1])
factory.generate_tests()
factory = TestFactory(run_test_arb)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests()
factory = TestFactory(run_stress_test)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests()
# cocotb-test
tests_dir = os.path.abspath(os.path.dirname(__file__))
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
lib_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'lib'))
taxi_src_dir = os.path.abspath(os.path.join(lib_dir, 'taxi', 'src'))
def process_f_files(files):
lst = {}
for f in files:
if f[-2:].lower() == '.f':
with open(f, 'r') as fp:
l = fp.read().split()
for f in process_f_files([os.path.join(os.path.dirname(f), x) for x in l]):
lst[os.path.basename(f)] = f
else:
lst[os.path.basename(f)] = f
return list(lst.values())
@pytest.mark.parametrize("data_w", [8, 16, 32])
def test_taxi_axi_dp_ram(request, data_w):
dut = "taxi_axi_dp_ram"
module = os.path.splitext(os.path.basename(__file__))[0]
toplevel = module
verilog_sources = [
os.path.join(tests_dir, f"{toplevel}.sv"),
os.path.join(rtl_dir, f"{dut}.f"),
]
verilog_sources = process_f_files(verilog_sources)
parameters = {}
parameters['DATA_W'] = data_w
parameters['ADDR_W'] = 16
parameters['STRB_W'] = parameters['DATA_W'] // 8
parameters['ID_W'] = 8
parameters['A_PIPELINE_OUTPUT'] = 0
parameters['B_PIPELINE_OUTPUT'] = 0
parameters['A_INTERLEAVE'] = 0
parameters['B_INTERLEAVE'] = 0
extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()}
sim_build = os.path.join(tests_dir, "sim_build",
request.node.name.replace('[', '-').replace(']', ''))
cocotb_test.simulator.run(
simulator="verilator",
python_search=[tests_dir],
verilog_sources=verilog_sources,
toplevel=toplevel,
module=module,
parameters=parameters,
sim_build=sim_build,
extra_env=extra_env,
)

View File

@@ -0,0 +1,72 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4 dual-port RAM testbench
*/
module test_taxi_axi_dp_ram #
(
/* verilator lint_off WIDTHTRUNC */
parameter DATA_W = 32,
parameter ADDR_W = 16,
parameter STRB_W = (DATA_W/8),
parameter ID_W = 8,
parameter logic A_PIPELINE_OUTPUT = 1'b0,
parameter logic B_PIPELINE_OUTPUT = 1'b0,
parameter logic A_INTERLEAVE = 1'b0,
parameter logic B_INTERLEAVE = 1'b0
/* verilator lint_on WIDTHTRUNC */
)
();
logic a_clk;
logic a_rst;
logic b_clk;
logic b_rst;
taxi_axi_if #(
.DATA_W(DATA_W),
.ADDR_W(ADDR_W+16),
.STRB_W(STRB_W),
.ID_W(ID_W)
) s_axi_a(), s_axi_b();
taxi_axi_dp_ram #(
.ADDR_W(ADDR_W),
.A_PIPELINE_OUTPUT(A_PIPELINE_OUTPUT),
.B_PIPELINE_OUTPUT(B_PIPELINE_OUTPUT),
.A_INTERLEAVE(A_INTERLEAVE),
.B_INTERLEAVE(B_INTERLEAVE)
)
uut (
/*
* Port A
*/
.a_clk(a_clk),
.a_rst(a_rst),
.s_axi_wr_a(s_axi_a),
.s_axi_rd_a(s_axi_a),
/*
* Port B
*/
.b_clk(b_clk),
.b_rst(b_rst),
.s_axi_wr_b(s_axi_b),
.s_axi_rd_b(s_axi_b)
);
endmodule
`resetall

View File

@@ -187,6 +187,8 @@ if getattr(cocotb, 'top', None) is not None:
factory.generate_tests() factory.generate_tests()
factory = TestFactory(run_stress_test) factory = TestFactory(run_stress_test)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests() factory.generate_tests()

View File

@@ -198,6 +198,8 @@ if getattr(cocotb, 'top', None) is not None:
factory.generate_tests() factory.generate_tests()
factory = TestFactory(run_stress_test) factory = TestFactory(run_stress_test)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests() factory.generate_tests()

View File

@@ -194,6 +194,8 @@ if getattr(cocotb, 'top', None) is not None:
factory.generate_tests() factory.generate_tests()
factory = TestFactory(run_stress_test) factory = TestFactory(run_stress_test)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests() factory.generate_tests()

View File

@@ -165,16 +165,13 @@ def cycle_pause():
if getattr(cocotb, 'top', None) is not None: if getattr(cocotb, 'top', None) is not None:
for test in [run_test_write, run_test_read]: for test in [run_test_write, run_test_read, run_stress_test]:
factory = TestFactory(test) factory = TestFactory(test)
factory.add_option("idle_inserter", [None, cycle_pause]) factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause]) factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests() factory.generate_tests()
factory = TestFactory(run_stress_test)
factory.generate_tests()
# cocotb-test # cocotb-test

View File

@@ -161,16 +161,13 @@ def cycle_pause():
if getattr(cocotb, 'top', None) is not None: if getattr(cocotb, 'top', None) is not None:
for test in [run_test_write, run_test_read]: for test in [run_test_write, run_test_read, run_stress_test]:
factory = TestFactory(test) factory = TestFactory(test)
factory.add_option("idle_inserter", [None, cycle_pause]) factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause]) factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests() factory.generate_tests()
factory = TestFactory(run_stress_test)
factory.generate_tests()
# cocotb-test # cocotb-test

View File

@@ -165,16 +165,13 @@ def cycle_pause():
if getattr(cocotb, 'top', None) is not None: if getattr(cocotb, 'top', None) is not None:
for test in [run_test_write, run_test_read]: for test in [run_test_write, run_test_read, run_stress_test]:
factory = TestFactory(test) factory = TestFactory(test)
factory.add_option("idle_inserter", [None, cycle_pause]) factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause]) factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests() factory.generate_tests()
factory = TestFactory(run_stress_test)
factory.generate_tests()
# cocotb-test # cocotb-test

View File

@@ -185,6 +185,8 @@ if getattr(cocotb, 'top', None) is not None:
factory.generate_tests() factory.generate_tests()
factory = TestFactory(run_stress_test) factory = TestFactory(run_stress_test)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests() factory.generate_tests()

View File

@@ -181,6 +181,8 @@ if getattr(cocotb, 'top', None) is not None:
factory.generate_tests() factory.generate_tests()
factory = TestFactory(run_stress_test) factory = TestFactory(run_stress_test)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests() factory.generate_tests()

View File

@@ -185,6 +185,8 @@ if getattr(cocotb, 'top', None) is not None:
factory.generate_tests() factory.generate_tests()
factory = TestFactory(run_stress_test) factory = TestFactory(run_stress_test)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests() factory.generate_tests()

View File

@@ -181,6 +181,8 @@ if getattr(cocotb, 'top', None) is not None:
factory.generate_tests() factory.generate_tests()
factory = TestFactory(run_stress_test) factory = TestFactory(run_stress_test)
factory.add_option("idle_inserter", [None, cycle_pause])
factory.add_option("backpressure_inserter", [None, cycle_pause])
factory.generate_tests() factory.generate_tests()

View File

@@ -224,6 +224,15 @@ pyrite_inst (
.qspi_1_cs(qspi_1_cs) .qspi_1_cs(qspi_1_cs)
); );
taxi_axis_if #(
.DATA_W(32),
.KEEP_EN(1),
.ID_EN(1),
.ID_W(4),
.USER_EN(1),
.USER_W(1)
) axis_brd_ctrl_cmd(), axis_brd_ctrl_rsp();
// QSFP28 // QSFP28
assign qsfp_0_sel_l = 1'b1; assign qsfp_0_sel_l = 1'b1;
assign qsfp_1_sel_l = 1'b1; assign qsfp_1_sel_l = 1'b1;
@@ -312,7 +321,7 @@ assign qsfp_rx_n[4*0 +: 4] = qsfp_0_rx_n;
assign qsfp_rx_p[4*1 +: 4] = qsfp_1_rx_p; assign qsfp_rx_p[4*1 +: 4] = qsfp_1_rx_p;
assign qsfp_rx_n[4*1 +: 4] = qsfp_1_rx_n; assign qsfp_rx_n[4*1 +: 4] = qsfp_1_rx_n;
for (genvar n = 0; n < 2; n = n + 1) begin : gty_quad for (genvar n = 0; n < 2; n = n + 1) begin : gt_quad
localparam CNT = 4; localparam CNT = 4;
@@ -573,7 +582,10 @@ cndm_micro_pcie_us #(
.RELEASE_INFO(RELEASE_INFO), .RELEASE_INFO(RELEASE_INFO),
// Structural configuration // Structural configuration
.PORTS(8), .PORTS($size(axis_qsfp_tx)),
.BRD_CTRL_EN(1'b0),
.SYS_CLK_PER_NS_NUM(4),
.SYS_CLK_PER_NS_DEN(1),
// PTP configuration // PTP configuration
.PTP_TS_EN(PTP_TS_EN), .PTP_TS_EN(PTP_TS_EN),
@@ -642,6 +654,12 @@ cndm_inst (
.cfg_interrupt_msi_tph_st_tag(cfg_interrupt_msi_tph_st_tag), .cfg_interrupt_msi_tph_st_tag(cfg_interrupt_msi_tph_st_tag),
.cfg_interrupt_msi_function_number(cfg_interrupt_msi_function_number), .cfg_interrupt_msi_function_number(cfg_interrupt_msi_function_number),
/*
* Board control
*/
.m_axis_brd_ctrl_cmd(axis_brd_ctrl_cmd),
.s_axis_brd_ctrl_rsp(axis_brd_ctrl_rsp),
/* /*
* PTP * PTP
*/ */

View File

@@ -9,6 +9,7 @@ Authors:
""" """
import itertools
import logging import logging
import os import os
import sys import sys
@@ -282,48 +283,47 @@ class TB:
self.qsfp_sources = [] self.qsfp_sources = []
self.qsfp_sinks = [] self.qsfp_sinks = []
for inst in dut.uut.gty_quad: for ch in itertools.chain.from_iterable([inst.mac_inst.ch for inst in dut.uut.gt_quad]):
for ch in inst.mac_inst.ch: gt_inst = ch.ch_inst.gt.gt_inst
gt_inst = ch.ch_inst.gt.gt_inst
if ch.ch_inst.DATA_W.value == 64: if ch.ch_inst.DATA_W.value == 64:
if ch.ch_inst.CFG_LOW_LATENCY.value: if ch.ch_inst.CFG_LOW_LATENCY.value:
clk = 2.482 clk = 2.482
gbx_cfg = (66, [64, 65]) gbx_cfg = (66, [64, 65])
else:
clk = 2.56
gbx_cfg = None
else: else:
if ch.ch_inst.CFG_LOW_LATENCY.value: clk = 2.56
clk = 3.102 gbx_cfg = None
gbx_cfg = (66, [64, 65]) else:
else: if ch.ch_inst.CFG_LOW_LATENCY.value:
clk = 3.2 clk = 3.102
gbx_cfg = None gbx_cfg = (66, [64, 65])
else:
clk = 3.2
gbx_cfg = None
cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start()) cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start())
cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start())
self.qsfp_sources.append(BaseRSerdesSource( self.qsfp_sources.append(BaseRSerdesSource(
data=gt_inst.serdes_rx_data, data=gt_inst.serdes_rx_data,
data_valid=gt_inst.serdes_rx_data_valid, data_valid=gt_inst.serdes_rx_data_valid,
hdr=gt_inst.serdes_rx_hdr, hdr=gt_inst.serdes_rx_hdr,
hdr_valid=gt_inst.serdes_rx_hdr_valid, hdr_valid=gt_inst.serdes_rx_hdr_valid,
clock=gt_inst.rx_clk, clock=gt_inst.rx_clk,
slip=gt_inst.serdes_rx_bitslip, slip=gt_inst.serdes_rx_bitslip,
reverse=True, reverse=True,
gbx_cfg=gbx_cfg gbx_cfg=gbx_cfg
)) ))
self.qsfp_sinks.append(BaseRSerdesSink( self.qsfp_sinks.append(BaseRSerdesSink(
data=gt_inst.serdes_tx_data, data=gt_inst.serdes_tx_data,
data_valid=gt_inst.serdes_tx_data_valid, data_valid=gt_inst.serdes_tx_data_valid,
hdr=gt_inst.serdes_tx_hdr, hdr=gt_inst.serdes_tx_hdr,
hdr_valid=gt_inst.serdes_tx_hdr_valid, hdr_valid=gt_inst.serdes_tx_hdr_valid,
gbx_sync=gt_inst.serdes_tx_gbx_sync, gbx_sync=gt_inst.serdes_tx_gbx_sync,
clock=gt_inst.tx_clk, clock=gt_inst.tx_clk,
reverse=True, reverse=True,
gbx_cfg=gbx_cfg gbx_cfg=gbx_cfg
)) ))
dut.user_sw.setimmediatevalue(0) dut.user_sw.setimmediatevalue(0)
dut.qsfp_0_modprs_l.setimmediatevalue(0) dut.qsfp_0_modprs_l.setimmediatevalue(0)

View File

@@ -5,7 +5,7 @@
This design targets the Alibaba AS02MC04 FPGA board. This design targets the Alibaba AS02MC04 FPGA board.
* SFP+ cages * SFP+ cages
* Looped-back 10GBASE-R or 25GBASE-R MAC via GTY transceiver * 10GBASE-R or 25GBASE-R MAC via GTY transceiver
## Board details ## Board details

View File

@@ -53,6 +53,9 @@ set_input_delay 0 [get_ports {reset}]
#set_property -dict {LOC C9 IOSTANDARD LVCMOS33} [get_ports {gpio[4]}] ;# J5.11,12 #set_property -dict {LOC C9 IOSTANDARD LVCMOS33} [get_ports {gpio[4]}] ;# J5.11,12
#set_property -dict {LOC D9 IOSTANDARD LVCMOS33} [get_ports {gpio[5]}] ;# J5.13,14 #set_property -dict {LOC D9 IOSTANDARD LVCMOS33} [get_ports {gpio[5]}] ;# J5.13,14
# 1-wire for DS28E15
#set_property -dict {LOC A15 IOSTANDARD LVCMOS33} [get_ports {onewire}] ;# U3 DS28E15
# SFP28 Interfaces # SFP28 Interfaces
set_property -dict {LOC A4 } [get_ports {sfp_rx_p[0]}] ;# MGTYRXP3_227 GTYE4_CHANNEL_X0Y15 / GTYE4_COMMON_X0Y3 set_property -dict {LOC A4 } [get_ports {sfp_rx_p[0]}] ;# MGTYRXP3_227 GTYE4_CHANNEL_X0Y15 / GTYE4_COMMON_X0Y3
set_property -dict {LOC A3 } [get_ports {sfp_rx_n[0]}] ;# MGTYRXN3_227 GTYE4_CHANNEL_X0Y15 / GTYE4_COMMON_X0Y3 set_property -dict {LOC A3 } [get_ports {sfp_rx_n[0]}] ;# MGTYRXN3_227 GTYE4_CHANNEL_X0Y15 / GTYE4_COMMON_X0Y3
@@ -70,10 +73,10 @@ set_property -dict {LOC B14 IOSTANDARD LVCMOS33 PULLUP true} [get_ports {sfp_tx
set_property -dict {LOC F9 IOSTANDARD LVCMOS33 PULLUP true} [get_ports {sfp_tx_fault[1]}] set_property -dict {LOC F9 IOSTANDARD LVCMOS33 PULLUP true} [get_ports {sfp_tx_fault[1]}]
set_property -dict {LOC D13 IOSTANDARD LVCMOS33 PULLUP true} [get_ports {sfp_los[0]}] set_property -dict {LOC D13 IOSTANDARD LVCMOS33 PULLUP true} [get_ports {sfp_los[0]}]
set_property -dict {LOC E10 IOSTANDARD LVCMOS33 PULLUP true} [get_ports {sfp_los[1]}] set_property -dict {LOC E10 IOSTANDARD LVCMOS33 PULLUP true} [get_ports {sfp_los[1]}]
#set_property -dict {LOC C13 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12 PULLUP true} [get_ports {sfp_i2c_scl[0]}] set_property -dict {LOC C13 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12 PULLUP true} [get_ports {sfp_i2c_scl[0]}]
#set_property -dict {LOC D10 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12 PULLUP true} [get_ports {sfp_i2c_scl[1]}] set_property -dict {LOC D10 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12 PULLUP true} [get_ports {sfp_i2c_scl[1]}]
#set_property -dict {LOC C14 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12 PULLUP true} [get_ports {sfp_i2c_sda[0]}] set_property -dict {LOC C14 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12 PULLUP true} [get_ports {sfp_i2c_sda[0]}]
#set_property -dict {LOC D11 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12 PULLUP true} [get_ports {sfp_i2c_sda[1]}] set_property -dict {LOC D11 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12 PULLUP true} [get_ports {sfp_i2c_sda[1]}]
# 156.25 MHz MGT reference clock # 156.25 MHz MGT reference clock
create_clock -period 6.4 -name sfp_mgt_refclk [get_ports {sfp_mgt_refclk_p}] create_clock -period 6.4 -name sfp_mgt_refclk [get_ports {sfp_mgt_refclk_p}]
@@ -81,21 +84,32 @@ create_clock -period 6.4 -name sfp_mgt_refclk [get_ports {sfp_mgt_refclk_p}]
set_false_path -from [get_ports {sfp_npres[*] sfp_tx_fault[*] sfp_los[*]}] set_false_path -from [get_ports {sfp_npres[*] sfp_tx_fault[*] sfp_los[*]}]
set_input_delay 0 [get_ports {sfp_npres[*] sfp_tx_fault[*] sfp_los[*]}] set_input_delay 0 [get_ports {sfp_npres[*] sfp_tx_fault[*] sfp_los[*]}]
#set_false_path -to [get_ports {sfp_i2c_sda[*] sfp_i2c_scl[*]}] set_false_path -to [get_ports {sfp_i2c_sda[*] sfp_i2c_scl[*]}]
#set_output_delay 0 [get_ports {sfp_i2c_sda[*] sfp_i2c_scl[*]}] set_output_delay 0 [get_ports {sfp_i2c_sda[*] sfp_i2c_scl[*]}]
#set_false_path -from [get_ports {sfp_i2c_sda[*] sfp_i2c_scl[*]}] set_false_path -from [get_ports {sfp_i2c_sda[*] sfp_i2c_scl[*]}]
#set_input_delay 0 [get_ports {sfp_i2c_sda[*] sfp_i2c_scl[*]}] set_input_delay 0 [get_ports {sfp_i2c_sda[*] sfp_i2c_scl[*]}]
# I2C interface # I2C interface
#set_property -dict {LOC G9 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12 PULLUP true} [get_ports {i2c_scl[0]}] # U12 M24C24 0x51 "FPGA_FRU"
#set_property -dict {LOC G10 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12 PULLUP true} [get_ports {i2c_sda[0]}] set_property -dict {LOC J14 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12 PULLUP true} [get_ports {i2c_scl}]
#set_property -dict {LOC J14 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12 PULLUP true} [get_ports {i2c_scl[1]}] set_property -dict {LOC J15 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12 PULLUP true} [get_ports {i2c_sda}]
#set_property -dict {LOC J15 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12 PULLUP true} [get_ports {i2c_sda[1]}]
#set_false_path -to [get_ports {i2c_sda[*] i2c_scl[*]}] set_false_path -to [get_ports {i2c_sda i2c_scl}]
#set_output_delay 0 [get_ports {i2c_sda[*] i2c_scl[*]}] set_output_delay 0 [get_ports {i2c_sda i2c_scl}]
#set_false_path -from [get_ports {i2c_sda[*] i2c_scl[*]}] set_false_path -from [get_ports {i2c_sda i2c_scl}]
#set_input_delay 0 [get_ports {i2c_sda[*] i2c_scl[*]}] set_input_delay 0 [get_ports {i2c_sda i2c_scl}]
# SMBus interface
# PCIe SMBus pins
# U4 PCA9535 0x20
# U10 M24C24 0x50 "SYS_FRU"
set_property -dict {LOC G9 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12 PULLUP true} [get_ports {smbclk}]
set_property -dict {LOC G10 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 12 PULLUP true} [get_ports {smbdat}]
set_false_path -to [get_ports {smbdat smbclk}]
set_output_delay 0 [get_ports {smbdat smbclk}]
set_false_path -from [get_ports {smbdat smbclk}]
set_input_delay 0 [get_ports {smbdat smbclk}]
# PCIe Interface # PCIe Interface
set_property -dict {LOC P2 } [get_ports {pcie_rx_p[0]}] ;# MGTYRXP3_225 GTYE4_CHANNEL_X0Y7 / GTYE4_COMMON_X0Y1 set_property -dict {LOC P2 } [get_ports {pcie_rx_p[0]}] ;# MGTYRXP3_225 GTYE4_CHANNEL_X0Y7 / GTYE4_COMMON_X0Y1

View File

@@ -19,6 +19,7 @@ TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
SYN_FILES = $(RTL_DIR)/fpga.sv SYN_FILES = $(RTL_DIR)/fpga.sv
SYN_FILES += $(RTL_DIR)/fpga_core.sv SYN_FILES += $(RTL_DIR)/fpga_core.sv
SYN_FILES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_micro_pcie_us.f SYN_FILES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_micro_pcie_us.f
SYN_FILES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_brd_ctrl_i2c.f
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
SYN_FILES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f SYN_FILES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv

View File

@@ -19,6 +19,7 @@ TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
SYN_FILES = $(RTL_DIR)/fpga.sv SYN_FILES = $(RTL_DIR)/fpga.sv
SYN_FILES += $(RTL_DIR)/fpga_core.sv SYN_FILES += $(RTL_DIR)/fpga_core.sv
SYN_FILES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_micro_pcie_us.f SYN_FILES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_micro_pcie_us.f
SYN_FILES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_brd_ctrl_i2c.f
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
SYN_FILES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f SYN_FILES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv

View File

@@ -64,6 +64,18 @@ module fpga #
output wire logic led_g, output wire logic led_g,
output wire logic led_hb, output wire logic led_hb,
/*
* I2C
*/
inout wire logic i2c_scl,
inout wire logic i2c_sda,
/*
* SMBus
*/
inout wire logic smbclk,
inout wire logic smbdat,
/* /*
* Ethernet: SFP+ * Ethernet: SFP+
*/ */
@@ -76,6 +88,8 @@ module fpga #
input wire logic [1:0] sfp_npres, input wire logic [1:0] sfp_npres,
input wire logic [1:0] sfp_tx_fault, input wire logic [1:0] sfp_tx_fault,
input wire logic [1:0] sfp_los, input wire logic [1:0] sfp_los,
inout wire logic [1:0] sfp_i2c_scl,
inout wire logic [1:0] sfp_i2c_sda,
/* /*
* PCIe * PCIe
@@ -207,6 +221,92 @@ sync_reset_125mhz_inst (
.out(rst_125mhz_int) .out(rst_125mhz_int)
); );
// GPIO
wire [1:0] sfp_npres_int;
wire [1:0] sfp_tx_fault_int;
wire [1:0] sfp_los_int;
wire [1:0] sfp_i2c_scl_i;
wire [1:0] sfp_i2c_scl_o;
wire [1:0] sfp_i2c_sda_i;
wire [1:0] sfp_i2c_sda_o;
reg [1:0] sfp_i2c_scl_o_reg;
reg [1:0] sfp_i2c_sda_o_reg;
always @(posedge pcie_user_clk) begin
sfp_i2c_scl_o_reg <= sfp_i2c_scl_o;
sfp_i2c_sda_o_reg <= sfp_i2c_sda_o;
end
taxi_sync_signal #(
.WIDTH(5*2),
.N(2)
)
sfp_sync_inst (
.clk(pcie_user_clk),
.in({sfp_npres, sfp_tx_fault, sfp_los,
sfp_i2c_scl, sfp_i2c_sda}),
.out({sfp_npres_int, sfp_tx_fault_int, sfp_los_int,
sfp_i2c_scl_i, sfp_i2c_sda_i})
);
for (genvar n = 0; n < 2; n = n + 1) begin
assign sfp_i2c_scl[n] = sfp_i2c_scl_o_reg[n] ? 1'bz : sfp_i2c_scl_o_reg[n];
assign sfp_i2c_sda[n] = sfp_i2c_sda_o_reg[n] ? 1'bz : sfp_i2c_sda_o_reg[n];
end
wire i2c_scl_i;
wire i2c_scl_o;
wire i2c_sda_i;
wire i2c_sda_o;
reg i2c_scl_o_reg;
reg i2c_sda_o_reg;
always @(posedge pcie_user_clk) begin
i2c_scl_o_reg <= i2c_scl_o;
i2c_sda_o_reg <= i2c_sda_o;
end
taxi_sync_signal #(
.WIDTH(2),
.N(2)
)
i2c_sync_inst (
.clk(pcie_user_clk),
.in({i2c_scl, i2c_sda}),
.out({i2c_scl_i, i2c_sda_i})
);
assign i2c_scl = i2c_scl_o_reg ? 1'bz : i2c_scl_o_reg;
assign i2c_sda = i2c_sda_o_reg ? 1'bz : i2c_sda_o_reg;
wire smbclk_i;
wire smbclk_o;
wire smbdat_i;
wire smbdat_o;
reg smbclk_o_reg;
reg smbdat_o_reg;
always @(posedge pcie_user_clk) begin
smbclk_o_reg <= smbclk_o;
smbdat_o_reg <= smbdat_o;
end
taxi_sync_signal #(
.WIDTH(2),
.N(2)
)
smb_sync_inst (
.clk(pcie_user_clk),
.in({smbclk, smbdat}),
.out({smbclk_i, smbdat_i})
);
assign smbclk = smbclk_o_reg ? 1'bz : smbclk_o_reg;
assign smbdat = smbdat_o_reg ? 1'bz : smbdat_o_reg;
// Flash // Flash
wire qspi_clk_int; wire qspi_clk_int;
wire [3:0] qspi_dq_int; wire [3:0] qspi_dq_int;
@@ -738,6 +838,22 @@ core_inst (
.led_g(led_g), .led_g(led_g),
.led_hb(led_hb), .led_hb(led_hb),
/*
* I2C
*/
.i2c_scl_i(i2c_scl_i),
.i2c_scl_o(i2c_scl_o),
.i2c_sda_i(i2c_sda_i),
.i2c_sda_o(i2c_sda_o),
/*
* SMBus
*/
.smbclk_i(smbclk_i),
.smbclk_o(smbclk_o),
.smbdat_i(smbdat_i),
.smbdat_o(smbdat_o),
/* /*
* Ethernet: SFP+ * Ethernet: SFP+
*/ */
@@ -748,9 +864,14 @@ core_inst (
.sfp_mgt_refclk_p(sfp_mgt_refclk_p), .sfp_mgt_refclk_p(sfp_mgt_refclk_p),
.sfp_mgt_refclk_n(sfp_mgt_refclk_n), .sfp_mgt_refclk_n(sfp_mgt_refclk_n),
.sfp_mgt_refclk_out(), .sfp_mgt_refclk_out(),
.sfp_npres(sfp_npres), .sfp_npres(sfp_npres_int),
.sfp_tx_fault(sfp_tx_fault), .sfp_tx_fault(sfp_tx_fault_int),
.sfp_los(sfp_los), .sfp_los(sfp_los_int),
.sfp_i2c_scl_i(sfp_i2c_scl_i),
.sfp_i2c_scl_o(sfp_i2c_scl_o),
.sfp_i2c_sda_i(sfp_i2c_sda_i),
.sfp_i2c_sda_o(sfp_i2c_sda_o),
/* /*
* PCIe * PCIe

View File

@@ -66,6 +66,22 @@ module fpga_core #
output wire logic led_g, output wire logic led_g,
output wire logic led_hb, output wire logic led_hb,
/*
* I2C
*/
input wire logic i2c_scl_i,
output wire logic i2c_scl_o,
input wire logic i2c_sda_i,
output wire logic i2c_sda_o,
/*
* SMBus
*/
input wire logic smbclk_i,
output wire logic smbclk_o,
input wire logic smbdat_i,
output wire logic smbdat_o,
/* /*
* Ethernet: SFP+ * Ethernet: SFP+
*/ */
@@ -80,6 +96,11 @@ module fpga_core #
input wire logic [1:0] sfp_tx_fault, input wire logic [1:0] sfp_tx_fault,
input wire logic [1:0] sfp_los, input wire logic [1:0] sfp_los,
input wire logic [1:0] sfp_i2c_scl_i,
output wire logic [1:0] sfp_i2c_scl_o,
input wire logic [1:0] sfp_i2c_sda_i,
output wire logic [1:0] sfp_i2c_sda_o,
/* /*
* PCIe * PCIe
*/ */
@@ -211,6 +232,121 @@ pyrite_inst (
.qspi_1_cs() .qspi_1_cs()
); );
// I2C
localparam logic OPTIC_EN = 1'b1;
localparam OPTIC_CNT = 2;
localparam logic EEPROM_EN = 1'b1;
localparam EEPROM_IDX = OPTIC_EN ? OPTIC_CNT : 0;
localparam logic MAC_EEPROM_EN = EEPROM_EN;
localparam MAC_EEPROM_IDX = EEPROM_IDX;
localparam MAC_EEPROM_OFFSET = 32;
localparam MAC_COUNT = OPTIC_CNT;
localparam logic MAC_FROM_BASE = 1'b1;
localparam logic SN_EEPROM_EN = EEPROM_EN;
localparam SN_EEPROM_IDX = EEPROM_IDX;
localparam SN_EEPROM_OFFSET = 0;
localparam SN_LEN = 32;
localparam logic PLL_EN = 1'b0;
localparam PLL_IDX = EEPROM_IDX + (EEPROM_EN ? 1 : 0);
localparam logic MUX_EN = 1'b0;
localparam MUX_CNT = 1;
localparam logic [MUX_CNT-1:0][6:0] MUX_I2C_ADDR = '0;
// localparam DEV_CNT = PLL_IDX + (PLL_EN ? 1 : 0);
localparam DEV_CNT = 4;
localparam logic [DEV_CNT-1:0][6:0] DEV_I2C_ADDR = {7'h50, 7'h51, 7'h50, 7'h50};
localparam logic [DEV_CNT-1:0][31:0] DEV_ADDR_CFG = {32'h00_00_0001, 32'h00_00_0001, 32'h00_00_0040, 32'h00_00_0040};
localparam logic [DEV_CNT-1:0][MUX_CNT-1:0][7:0] DEV_MUX_MASK = '0;
localparam CYC_PER_US = 250;
localparam PAGE_SEL_DELAY_US = SIM ? 20 : 2000;
localparam I2C_PRESCALE = SIM ? 2 : 250000/(400*4);
localparam I2C_TBUF_CYC = 20;
taxi_axis_if #(
.DATA_W(32),
.KEEP_EN(1),
.ID_EN(1),
.ID_W(4),
.USER_EN(1),
.USER_W(1)
) axis_brd_ctrl_cmd(), axis_brd_ctrl_rsp();
wire [DEV_CNT-1:0] i2c_dev_sel;
wire int_i2c_scl_i;
wire int_i2c_scl_o;
wire int_i2c_sda_i;
wire int_i2c_sda_o;
assign {smbclk_o, i2c_scl_o, sfp_i2c_scl_o} = {DEV_CNT{int_i2c_scl_o}} | ~i2c_dev_sel;
assign {smbdat_o, i2c_sda_o, sfp_i2c_sda_o} = {DEV_CNT{int_i2c_sda_o}} | ~i2c_dev_sel;
assign int_i2c_scl_i = &({smbclk_i, i2c_scl_i, sfp_i2c_scl_i} | ~i2c_dev_sel);
assign int_i2c_sda_i = &({smbdat_i, i2c_sda_i, sfp_i2c_sda_i} | ~i2c_dev_sel);
cndm_brd_ctrl_i2c #(
.OPTIC_EN(OPTIC_EN),
.OPTIC_CNT(OPTIC_CNT),
.EEPROM_EN(EEPROM_EN),
.EEPROM_IDX(EEPROM_IDX),
.MAC_EEPROM_EN(MAC_EEPROM_EN),
.MAC_EEPROM_IDX(MAC_EEPROM_IDX),
.MAC_EEPROM_OFFSET(MAC_EEPROM_OFFSET),
.MAC_COUNT(MAC_COUNT),
.MAC_FROM_BASE(MAC_FROM_BASE),
.SN_EEPROM_EN(SN_EEPROM_EN),
.SN_EEPROM_IDX(SN_EEPROM_IDX),
.SN_EEPROM_OFFSET(SN_EEPROM_OFFSET),
.SN_LEN(SN_LEN),
.PLL_EN(PLL_EN),
.PLL_IDX(PLL_IDX),
.MUX_EN(MUX_EN),
.MUX_CNT(MUX_CNT),
.MUX_I2C_ADDR(MUX_I2C_ADDR),
.DEV_CNT(DEV_CNT),
.DEV_I2C_ADDR(DEV_I2C_ADDR),
.DEV_ADDR_CFG(DEV_ADDR_CFG),
.DEV_MUX_MASK(DEV_MUX_MASK),
.CYC_PER_US(CYC_PER_US),
.PAGE_SEL_DELAY_US(PAGE_SEL_DELAY_US),
.I2C_PRESCALE(I2C_PRESCALE),
.I2C_TBUF_CYC(I2C_TBUF_CYC)
)
board_ctrl_i2c_ch_inst (
.clk(pcie_clk),
.rst(pcie_rst),
/*
* Board control command interface
*/
.s_axis_cmd(axis_brd_ctrl_cmd),
.m_axis_rsp(axis_brd_ctrl_rsp),
/*
* I2C interface
*/
.i2c_scl_i(int_i2c_scl_i),
.i2c_scl_o(int_i2c_scl_o),
.i2c_sda_i(int_i2c_sda_i),
.i2c_sda_o(int_i2c_sda_o),
.dev_sel(i2c_dev_sel),
.dev_rst()
);
// SFP+ // SFP+
wire sfp_tx_clk[2]; wire sfp_tx_clk[2];
wire sfp_tx_rst[2]; wire sfp_tx_rst[2];
@@ -566,7 +702,10 @@ cndm_micro_pcie_us #(
.RELEASE_INFO(RELEASE_INFO), .RELEASE_INFO(RELEASE_INFO),
// Structural configuration // Structural configuration
.PORTS(2), .PORTS($size(axis_sfp_tx)),
.BRD_CTRL_EN(1'b1),
.SYS_CLK_PER_NS_NUM(4),
.SYS_CLK_PER_NS_DEN(1),
// PTP configuration // PTP configuration
.PTP_TS_EN(PTP_TS_EN), .PTP_TS_EN(PTP_TS_EN),
@@ -635,6 +774,12 @@ cndm_inst (
.cfg_interrupt_msi_tph_st_tag(cfg_interrupt_msi_tph_st_tag), .cfg_interrupt_msi_tph_st_tag(cfg_interrupt_msi_tph_st_tag),
.cfg_interrupt_msi_function_number(cfg_interrupt_msi_function_number), .cfg_interrupt_msi_function_number(cfg_interrupt_msi_function_number),
/*
* Board control
*/
.m_axis_brd_ctrl_cmd(axis_brd_ctrl_cmd),
.s_axis_brd_ctrl_rsp(axis_brd_ctrl_rsp),
/* /*
* PTP * PTP
*/ */

View File

@@ -25,6 +25,7 @@ TOPLEVEL = $(COCOTB_TOPLEVEL)
VERILOG_SOURCES += $(COCOTB_TOPLEVEL).sv VERILOG_SOURCES += $(COCOTB_TOPLEVEL).sv
VERILOG_SOURCES += $(RTL_DIR)/$(DUT).sv VERILOG_SOURCES += $(RTL_DIR)/$(DUT).sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_micro_pcie_us.f VERILOG_SOURCES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_micro_pcie_us.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_brd_ctrl_i2c.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f VERILOG_SOURCES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f VERILOG_SOURCES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv VERILOG_SOURCES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv

View File

@@ -11,6 +11,7 @@ Authors:
import logging import logging
import os import os
import struct
import sys import sys
import pytest import pytest
@@ -22,6 +23,7 @@ from cocotb.triggers import RisingEdge, FallingEdge, Timer
from cocotbext.axi import AxiStreamBus from cocotbext.axi import AxiStreamBus
from cocotbext.eth import XgmiiFrame from cocotbext.eth import XgmiiFrame
from cocotbext.i2c import I2cMemory
from cocotbext.pcie.core import RootComplex from cocotbext.pcie.core import RootComplex
from cocotbext.pcie.xilinx.us import UltraScalePlusPcieDevice from cocotbext.pcie.xilinx.us import UltraScalePlusPcieDevice
@@ -328,6 +330,41 @@ class TB:
dut.sfp_tx_fault.setimmediatevalue(0) dut.sfp_tx_fault.setimmediatevalue(0)
dut.sfp_los.setimmediatevalue(0) dut.sfp_los.setimmediatevalue(0)
# I2C
self.sfp0_i2c = I2cMemory(sda=dut.sfp_i2c_sda_o[0], sda_o=dut.sfp_i2c_sda_i[0],
scl=dut.sfp_i2c_scl_o[0], scl_o=dut.sfp_i2c_scl_i[0], addr=0x50, size=256)
self.sfp0_i2c.write_mem(0, bytes.fromhex("""
03 04 21 00 00 00 00 00 04 00 00 00 67 00 00 00
00 00 03 00 41 6d 70 68 65 6e 6f 6c 20 20 20 20
20 20 20 20 00 41 50 48 35 37 31 35 34 30 30 30
32 20 20 20 20 20 20 20 4b 20 20 20 01 00 00 f7
00 00 00 00 41 50 46 30 39 34 38 30 30 32 30 32
37 39 20 20 30 39 31 31 32 34 20 20 00 00 00 c1
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00
""" + " ff"*128))
self.sfp1_i2c = I2cMemory(sda=dut.sfp_i2c_sda_o[1], sda_o=dut.sfp_i2c_sda_i[1],
scl=dut.sfp_i2c_scl_o[1], scl_o=dut.sfp_i2c_scl_i[1], addr=0x50, size=256)
self.sfp1_i2c.write_mem(0, bytes.fromhex("""
03 04 21 00 00 00 00 00 04 00 00 00 67 00 00 00
00 00 03 00 41 6d 70 68 65 6e 6f 6c 20 20 20 20
20 20 20 20 00 41 50 48 35 37 31 35 34 30 30 30
32 20 20 20 20 20 20 20 4b 20 20 20 01 00 00 f7
00 00 00 00 41 50 46 30 39 34 38 30 30 32 30 32
37 39 20 20 30 39 31 31 32 34 20 20 00 00 00 c1
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00
""" + " ff"*128))
self.eeprom_i2c = I2cMemory(sda=dut.i2c_sda_o, sda_o=dut.i2c_sda_i,
scl=dut.i2c_scl_o, scl_o=dut.i2c_scl_i, addr=0x51, size=2**13)
self.eeprom_smb = I2cMemory(sda=dut.smbdat_o, sda_o=dut.smbdat_i,
scl=dut.smbclk_o, scl_o=dut.smbclk_i, addr=0x50, size=2**13)
self.loopback_enable = False self.loopback_enable = False
cocotb.start_soon(self._run_loopback()) cocotb.start_soon(self._run_loopback())
@@ -375,6 +412,28 @@ async def run_test(dut):
tb.log.info("Init complete") tb.log.info("Init complete")
tb.log.info("Read SFP0")
rsp = await driver.exec_cmd(struct.pack("<HHLHHLbbbbLLL",
0, # rsvd
cndm.CNDM_CMD_OP_HWMON, # opcode
0x00000000, # flags
0, # index
cndm.CNDM_CMD_BRD_OP_OPTIC_RD, # board op
0, # flags
0, # rsvd
0, # dev addr offset
0, # bank
0, # page
0x00, # addr
32, # len
0, # rsvd
))
print(rsp)
tb.log.info("Data: %s", rsp[32:32+32].hex())
tb.log.info("Wait for block lock") tb.log.info("Wait for block lock")
for k in range(1200): for k in range(1200):
await RisingEdge(tb.dut.clk_125mhz) await RisingEdge(tb.dut.clk_125mhz)
@@ -475,6 +534,7 @@ def test_fpga_core(request, mac_data_w):
os.path.join(tests_dir, f"{toplevel}.sv"), os.path.join(tests_dir, f"{toplevel}.sv"),
os.path.join(rtl_dir, f"{dut}.sv"), os.path.join(rtl_dir, f"{dut}.sv"),
os.path.join(taxi_src_dir, "cndm", "rtl", "cndm_micro_pcie_us.f"), os.path.join(taxi_src_dir, "cndm", "rtl", "cndm_micro_pcie_us.f"),
os.path.join(taxi_src_dir, "cndm", "rtl", "cndm_brd_ctrl_i2c.f"),
os.path.join(taxi_src_dir, "eth", "rtl", "us", "taxi_eth_mac_25g_us.f"), os.path.join(taxi_src_dir, "eth", "rtl", "us", "taxi_eth_mac_25g_us.f"),
os.path.join(taxi_src_dir, "axis", "rtl", "taxi_axis_async_fifo.f"), os.path.join(taxi_src_dir, "axis", "rtl", "taxi_axis_async_fifo.f"),
os.path.join(taxi_src_dir, "sync", "rtl", "taxi_sync_reset.sv"), os.path.join(taxi_src_dir, "sync", "rtl", "taxi_sync_reset.sv"),

View File

@@ -66,6 +66,16 @@ logic led_r;
logic led_g; logic led_g;
logic led_hb; logic led_hb;
logic i2c_scl_i;
logic i2c_scl_o;
logic i2c_sda_i;
logic i2c_sda_o;
logic smbclk_i;
logic smbclk_o;
logic smbdat_i;
logic smbdat_o;
logic sfp_mgt_refclk_p; logic sfp_mgt_refclk_p;
logic sfp_mgt_refclk_n; logic sfp_mgt_refclk_n;
logic sfp_mgt_refclk_out; logic sfp_mgt_refclk_out;
@@ -74,6 +84,11 @@ logic [1:0] sfp_npres;
logic [1:0] sfp_tx_fault; logic [1:0] sfp_tx_fault;
logic [1:0] sfp_los; logic [1:0] sfp_los;
logic sfp_i2c_scl_i[2];
logic sfp_i2c_scl_o[2];
logic sfp_i2c_sda_i[2];
logic sfp_i2c_sda_o[2];
logic pcie_clk; logic pcie_clk;
logic pcie_rst; logic pcie_rst;
@@ -215,6 +230,22 @@ uut (
.led_g(led_g), .led_g(led_g),
.led_hb(led_hb), .led_hb(led_hb),
/*
* I2C
*/
.i2c_scl_i(i2c_scl_i),
.i2c_scl_o(i2c_scl_o),
.i2c_sda_i(i2c_sda_i),
.i2c_sda_o(i2c_sda_o),
/*
* SMBus
*/
.smbclk_i(smbclk_i),
.smbclk_o(smbclk_o),
.smbdat_i(smbdat_i),
.smbdat_o(smbdat_o),
/* /*
* PCIe * PCIe
*/ */
@@ -291,6 +322,11 @@ uut (
.sfp_tx_fault(sfp_tx_fault), .sfp_tx_fault(sfp_tx_fault),
.sfp_los(sfp_los), .sfp_los(sfp_los),
.sfp_i2c_scl_i({sfp_i2c_scl_i[1], sfp_i2c_scl_i[0]}),
.sfp_i2c_scl_o({sfp_i2c_scl_o[1], sfp_i2c_scl_o[0]}),
.sfp_i2c_sda_i({sfp_i2c_sda_i[1], sfp_i2c_sda_i[0]}),
.sfp_i2c_sda_o({sfp_i2c_sda_o[1], sfp_i2c_sda_o[0]}),
/* /*
* QSPI flash * QSPI flash
*/ */

View File

@@ -380,6 +380,15 @@ for (genvar n = 1; n < UART_CNT; n = n + 1) begin : uart_ch
end end
taxi_axis_if #(
.DATA_W(32),
.KEEP_EN(1),
.ID_EN(1),
.ID_W(4),
.USER_EN(1),
.USER_W(1)
) axis_brd_ctrl_cmd(), axis_brd_ctrl_rsp();
// Ethernet // Ethernet
assign eth_port_modsell = '1; assign eth_port_modsell = '1;
assign eth_port_resetl = '1; assign eth_port_resetl = '1;
@@ -403,7 +412,7 @@ wire eth_gty_mgt_refclk_bufg[GTY_CLK_CNT];
wire eth_gty_rst[GTY_CLK_CNT]; wire eth_gty_rst[GTY_CLK_CNT];
for (genvar n = 0; n < GTY_CLK_CNT; n = n + 1) begin : gty_clk for (genvar n = 0; n < GTY_CLK_CNT; n = n + 1) begin : gt_clk
wire eth_gty_mgt_refclk_int; wire eth_gty_mgt_refclk_int;
@@ -460,7 +469,7 @@ assign led[0] = ptp_pps_str;
localparam logic [8*8-1:0] STAT_PREFIX_STR_QSFP1[4] = '{"QSFP1.1", "QSFP1.2", "QSFP1.3", "QSFP1.4"}; localparam logic [8*8-1:0] STAT_PREFIX_STR_QSFP1[4] = '{"QSFP1.1", "QSFP1.2", "QSFP1.3", "QSFP1.4"};
localparam logic [8*8-1:0] STAT_PREFIX_STR_QSFP2[4] = '{"QSFP2.1", "QSFP2.2", "QSFP2.3", "QSFP2.4"}; localparam logic [8*8-1:0] STAT_PREFIX_STR_QSFP2[4] = '{"QSFP2.1", "QSFP2.2", "QSFP2.3", "QSFP2.4"};
for (genvar n = 0; n < GTY_QUAD_CNT; n = n + 1) begin : gty_quad for (genvar n = 0; n < GTY_QUAD_CNT; n = n + 1) begin : gt_quad
localparam CLK = n; localparam CLK = n;
localparam CNT = 4; localparam CNT = 4;
@@ -747,7 +756,10 @@ cndm_micro_pcie_us #(
.RELEASE_INFO(RELEASE_INFO), .RELEASE_INFO(RELEASE_INFO),
// Structural configuration // Structural configuration
.PORTS(GTY_CNT), .PORTS($size(eth_gty_axis_tx)),
.BRD_CTRL_EN(1'b0),
.SYS_CLK_PER_NS_NUM(4),
.SYS_CLK_PER_NS_DEN(1),
// PTP configuration // PTP configuration
.PTP_TS_EN(PTP_TS_EN), .PTP_TS_EN(PTP_TS_EN),
@@ -816,6 +828,12 @@ cndm_inst (
.cfg_interrupt_msi_tph_st_tag(cfg_interrupt_msi_tph_st_tag), .cfg_interrupt_msi_tph_st_tag(cfg_interrupt_msi_tph_st_tag),
.cfg_interrupt_msi_function_number(cfg_interrupt_msi_function_number), .cfg_interrupt_msi_function_number(cfg_interrupt_msi_function_number),
/*
* Board control
*/
.m_axis_brd_ctrl_cmd(axis_brd_ctrl_cmd),
.s_axis_brd_ctrl_rsp(axis_brd_ctrl_rsp),
/* /*
* PTP * PTP
*/ */

View File

@@ -9,6 +9,7 @@ Authors:
""" """
import itertools
import logging import logging
import os import os
import sys import sys
@@ -293,48 +294,47 @@ class TB:
self.qsfp_sources = [] self.qsfp_sources = []
self.qsfp_sinks = [] self.qsfp_sinks = []
for inst in dut.uut.gty_quad: for ch in itertools.chain.from_iterable([inst.mac_inst.ch for inst in dut.uut.gt_quad]):
for ch in inst.mac_inst.ch: gt_inst = ch.ch_inst.gt.gt_inst
gt_inst = ch.ch_inst.gt.gt_inst
if ch.ch_inst.DATA_W.value == 64: if ch.ch_inst.DATA_W.value == 64:
if ch.ch_inst.CFG_LOW_LATENCY.value: if ch.ch_inst.CFG_LOW_LATENCY.value:
clk = 2.482 clk = 2.482
gbx_cfg = (66, [64, 65]) gbx_cfg = (66, [64, 65])
else:
clk = 2.56
gbx_cfg = None
else: else:
if ch.ch_inst.CFG_LOW_LATENCY.value: clk = 2.56
clk = 3.102 gbx_cfg = None
gbx_cfg = (66, [64, 65]) else:
else: if ch.ch_inst.CFG_LOW_LATENCY.value:
clk = 3.2 clk = 3.102
gbx_cfg = None gbx_cfg = (66, [64, 65])
else:
clk = 3.2
gbx_cfg = None
cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start()) cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start())
cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start())
self.qsfp_sources.append(BaseRSerdesSource( self.qsfp_sources.append(BaseRSerdesSource(
data=gt_inst.serdes_rx_data, data=gt_inst.serdes_rx_data,
data_valid=gt_inst.serdes_rx_data_valid, data_valid=gt_inst.serdes_rx_data_valid,
hdr=gt_inst.serdes_rx_hdr, hdr=gt_inst.serdes_rx_hdr,
hdr_valid=gt_inst.serdes_rx_hdr_valid, hdr_valid=gt_inst.serdes_rx_hdr_valid,
clock=gt_inst.rx_clk, clock=gt_inst.rx_clk,
slip=gt_inst.serdes_rx_bitslip, slip=gt_inst.serdes_rx_bitslip,
reverse=True, reverse=True,
gbx_cfg=gbx_cfg gbx_cfg=gbx_cfg
)) ))
self.qsfp_sinks.append(BaseRSerdesSink( self.qsfp_sinks.append(BaseRSerdesSink(
data=gt_inst.serdes_tx_data, data=gt_inst.serdes_tx_data,
data_valid=gt_inst.serdes_tx_data_valid, data_valid=gt_inst.serdes_tx_data_valid,
hdr=gt_inst.serdes_tx_hdr, hdr=gt_inst.serdes_tx_hdr,
hdr_valid=gt_inst.serdes_tx_hdr_valid, hdr_valid=gt_inst.serdes_tx_hdr_valid,
gbx_sync=gt_inst.serdes_tx_gbx_sync, gbx_sync=gt_inst.serdes_tx_gbx_sync,
clock=gt_inst.tx_clk, clock=gt_inst.tx_clk,
reverse=True, reverse=True,
gbx_cfg=gbx_cfg gbx_cfg=gbx_cfg
)) ))
dut.sw.setimmediatevalue(0) dut.sw.setimmediatevalue(0)
dut.eth_port_modprsl.setimmediatevalue(0) dut.eth_port_modprsl.setimmediatevalue(0)

View File

@@ -0,0 +1,35 @@
# Corundum for DNPCIe-40G-KU-LL-2QSFP
## Introduction
This design targets the Dini Group DNPCIe-40G-KU-LL-2QSFP FPGA board.
* USB UART
* XFCP (3 Mbaud)
* QSFP+
* 10GBASE-R MACs via GTH transceivers
## Board details
* FPGA: xcku040-ffva1156-2-e or xcku060-ffva1156-2-e
* USB UART: FTDI FT2232HQ
* PCIe: gen 3 x8 (~64 Gbps)
* Reference oscillator: Fixed 156.25 MHz from Si534
* 10GBASE-R PHY: Soft PCS with GTH transceivers
## Licensing
* Toolchain
* Vivado Enterprise (requires license)
* IP
* No licensed vendor IP or 3rd party IP
## How to build
Run `make` in the appropriate `fpga*` subdirectory to build the bitstream. Ensure that the Xilinx Vivado toolchain components are in PATH.
On the host system, run `make` in `modules/cndm` to build the driver. Ensure that the headers for the running kernel are installed, otherwise the driver cannot be compiled.
## How to test
Run `make program` to program the board with Vivado. Then, reboot the machine to re-enumerate the PCIe bus. Finally, load the driver on the host system with `insmod cndm.ko`. Check `dmesg` for output from driver initialization. Run `cndm_ddcmd.sh =p` to enable all debug messages.

View File

@@ -0,0 +1,153 @@
# SPDX-License-Identifier: MIT
###################################################################
#
# Xilinx Vivado FPGA Makefile
#
# Copyright (c) 2016-2025 Alex Forencich
#
###################################################################
#
# Parameters:
# FPGA_TOP - Top module name
# FPGA_FAMILY - FPGA family (e.g. VirtexUltrascale)
# FPGA_DEVICE - FPGA device (e.g. xcvu095-ffva2104-2-e)
# SYN_FILES - list of source files
# INC_FILES - list of include files
# XDC_FILES - list of timing constraint files
# XCI_FILES - list of IP XCI files
# IP_TCL_FILES - list of IP TCL files (sourced during project creation)
# CONFIG_TCL_FILES - list of config TCL files (sourced before each build)
#
# Note: both SYN_FILES and INC_FILES support file list files. File list
# files are files with a .f extension that contain a list of additional
# files to include, one path relative to the .f file location per line.
# The .f files are processed recursively, and then the complete file list
# is de-duplicated, with later files in the list taking precedence.
#
# Example:
#
# FPGA_TOP = fpga
# FPGA_FAMILY = VirtexUltrascale
# FPGA_DEVICE = xcvu095-ffva2104-2-e
# SYN_FILES = rtl/fpga.v
# XDC_FILES = fpga.xdc
# XCI_FILES = ip/pcspma.xci
# include ../common/vivado.mk
#
###################################################################
# phony targets
.PHONY: fpga vivado tmpclean clean distclean
# prevent make from deleting intermediate files and reports
.PRECIOUS: %.xpr %.bit %.bin %.ltx %.xsa %.mcs %.prm
.SECONDARY:
CONFIG ?= config.mk
-include $(CONFIG)
FPGA_TOP ?= fpga
PROJECT ?= $(FPGA_TOP)
XDC_FILES ?= $(PROJECT).xdc
# handle file list files
process_f_file = $(call process_f_files,$(addprefix $(dir $1),$(shell cat $1)))
process_f_files = $(foreach f,$1,$(if $(filter %.f,$f),$(call process_f_file,$f),$f))
uniq_base = $(if $1,$(call uniq_base,$(foreach f,$1,$(if $(filter-out $(notdir $(lastword $1)),$(notdir $f)),$f,))) $(lastword $1))
SYN_FILES := $(call uniq_base,$(call process_f_files,$(SYN_FILES)))
INC_FILES := $(call uniq_base,$(call process_f_files,$(INC_FILES)))
###################################################################
# Main Targets
#
# all: build everything (fpga)
# fpga: build FPGA config
# vivado: open project in Vivado
# tmpclean: remove intermediate files
# clean: remove output files and project files
# distclean: remove archived output files
###################################################################
all: fpga
fpga: $(PROJECT).bit
vivado: $(PROJECT).xpr
vivado $(PROJECT).xpr
tmpclean::
-rm -rf *.log *.jou *.cache *.gen *.hbs *.hw *.ip_user_files *.runs *.xpr *.html *.xml *.sim *.srcs *.str .Xil defines.v
-rm -rf create_project.tcl update_config.tcl run_synth.tcl run_impl.tcl generate_bit.tcl
clean:: tmpclean
-rm -rf *.bit *.bin *.ltx *.xsa program.tcl generate_mcs.tcl *.mcs *.prm flash.tcl
-rm -rf *_utilization.rpt *_utilization_hierarchical.rpt
distclean:: clean
-rm -rf rev
###################################################################
# Target implementations
###################################################################
# Vivado project file
# create fresh project if Makefile or IP files have changed
create_project.tcl: Makefile $(XCI_FILES) $(IP_TCL_FILES)
rm -rf defines.v
touch defines.v
for x in $(DEFS); do echo '`define' $$x >> defines.v; done
echo "create_project -force -part $(FPGA_PART) $(PROJECT)" > $@
echo "add_files -fileset sources_1 defines.v $(SYN_FILES)" >> $@
echo "set_property top $(FPGA_TOP) [current_fileset]" >> $@
echo "add_files -fileset constrs_1 $(XDC_FILES)" >> $@
for x in $(XCI_FILES); do echo "import_ip $$x" >> $@; done
for x in $(IP_TCL_FILES); do echo "source $$x" >> $@; done
for x in $(CONFIG_TCL_FILES); do echo "source $$x" >> $@; done
# source config TCL scripts if any source file has changed
update_config.tcl: $(CONFIG_TCL_FILES) $(SYN_FILES) $(INC_FILES) $(XDC_FILES)
echo "open_project -quiet $(PROJECT).xpr" > $@
for x in $(CONFIG_TCL_FILES); do echo "source $$x" >> $@; done
$(PROJECT).xpr: create_project.tcl update_config.tcl
vivado -nojournal -nolog -mode batch $(foreach x,$?,-source $x)
# synthesis run
$(PROJECT).runs/synth_1/$(PROJECT).dcp: create_project.tcl update_config.tcl $(SYN_FILES) $(INC_FILES) $(XDC_FILES) | $(PROJECT).xpr
echo "open_project $(PROJECT).xpr" > run_synth.tcl
echo "reset_run synth_1" >> run_synth.tcl
echo "launch_runs -jobs 4 synth_1" >> run_synth.tcl
echo "wait_on_run synth_1" >> run_synth.tcl
vivado -nojournal -nolog -mode batch -source run_synth.tcl
# implementation run
$(PROJECT).runs/impl_1/$(PROJECT)_routed.dcp: $(PROJECT).runs/synth_1/$(PROJECT).dcp
echo "open_project $(PROJECT).xpr" > run_impl.tcl
echo "reset_run impl_1" >> run_impl.tcl
echo "launch_runs -jobs 4 impl_1" >> run_impl.tcl
echo "wait_on_run impl_1" >> run_impl.tcl
echo "open_run impl_1" >> run_impl.tcl
echo "report_utilization -file $(PROJECT)_utilization.rpt" >> run_impl.tcl
echo "report_utilization -hierarchical -file $(PROJECT)_utilization_hierarchical.rpt" >> run_impl.tcl
vivado -nojournal -nolog -mode batch -source run_impl.tcl
# output files (including potentially bit, bin, ltx, and xsa)
$(PROJECT).bit $(PROJECT).bin $(PROJECT).ltx $(PROJECT).xsa: $(PROJECT).runs/impl_1/$(PROJECT)_routed.dcp
echo "open_project $(PROJECT).xpr" > generate_bit.tcl
echo "open_run impl_1" >> generate_bit.tcl
echo "write_bitstream -force -bin_file $(PROJECT).runs/impl_1/$(PROJECT).bit" >> generate_bit.tcl
echo "write_debug_probes -force $(PROJECT).runs/impl_1/$(PROJECT).ltx" >> generate_bit.tcl
echo "write_hw_platform -fixed -force -include_bit $(PROJECT).xsa" >> generate_bit.tcl
vivado -nojournal -nolog -mode batch -source generate_bit.tcl
ln -f -s $(PROJECT).runs/impl_1/$(PROJECT).bit .
ln -f -s $(PROJECT).runs/impl_1/$(PROJECT).bin .
if [ -e $(PROJECT).runs/impl_1/$(PROJECT).ltx ]; then ln -f -s $(PROJECT).runs/impl_1/$(PROJECT).ltx .; fi
mkdir -p rev
COUNT=100; \
while [ -e rev/$(PROJECT)_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
cp -pv $(PROJECT).runs/impl_1/$(PROJECT).bit rev/$(PROJECT)_rev$$COUNT.bit; \
cp -pv $(PROJECT).runs/impl_1/$(PROJECT).bin rev/$(PROJECT)_rev$$COUNT.bin; \
if [ -e $(PROJECT).runs/impl_1/$(PROJECT).ltx ]; then cp -pv $(PROJECT).runs/impl_1/$(PROJECT).ltx rev/$(PROJECT)_rev$$COUNT.ltx; fi; \
if [ -e $(PROJECT).xsa ]; then cp -pv $(PROJECT).xsa rev/$(PROJECT)_rev$$COUNT.xsa; fi

View File

@@ -0,0 +1,532 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2014-2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
# XDC constraints for the DNPCIe_40G_KU_LL_2QSFP
# part: xcku040-ffva1156-2-e
# part: xcku060-ffva1156-2-e
# General configuration
set_property CFGBVS GND [current_design]
set_property CONFIG_VOLTAGE 1.8 [current_design]
set_property BITSTREAM.GENERAL.COMPRESS true [current_design]
set_property BITSTREAM.CONFIG.UNUSEDPIN Pullup [current_design]
set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design]
set_property BITSTREAM.CONFIG.BPI_SYNC_MODE Type2 [current_design]
set_property CONFIG_MODE BPI16 [current_design]
set_property BITSTREAM.CONFIG.OVERTEMPSHUTDOWN Enable [current_design]
# LEDs
set_property -dict {LOC H22 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {user_led[0]}]
set_property -dict {LOC E20 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {user_led[1]}]
set_property -dict {LOC F22 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {user_led[2]}]
set_property -dict {LOC G22 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {user_led[3]}]
set_property -dict {LOC F12 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {user_led[4]}]
set_property -dict {LOC F10 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {user_led[5]}]
set_property -dict {LOC D10 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {user_led[6]}]
set_property -dict {LOC AK33 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {user_led[7]}]
set_property -dict {LOC AG14 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {qsfp0_led_green}]
set_property -dict {LOC AP14 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {qsfp0_led_red}]
set_property -dict {LOC AH29 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {qsfp1_led_green}]
set_property -dict {LOC AL33 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {qsfp1_led_red}]
set_false_path -to [get_ports {user_led[*] qsfp0_led_green qsfp0_led_red qsfp1_led_green qsfp1_led_red}]
set_output_delay 0 [get_ports {user_led[*] qsfp0_led_green qsfp0_led_red qsfp1_led_green qsfp1_led_red}]
# Reset button
#set_property -dict {LOC N21 IOSTANDARD LVCMOS12} [get_ports reset]
#set_false_path -from [get_ports {reset}]
#set_input_delay 0 [get_ports {reset}]
# GPIO
# DNCPU
#set_property -dict {LOC Y26 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[0]] ;# J10.1
#set_property -dict {LOC AA22 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[1]] ;# J10.2
#set_property -dict {LOC Y27 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[2]] ;# J10.3
#set_property -dict {LOC AB22 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[3]] ;# J10.4
#set_property -dict {LOC AD25 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[4]] ;# J10.5
#set_property -dict {LOC AC22 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[5]] ;# J10.6
#set_property -dict {LOC AD26 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[6]] ;# J10.7
#set_property -dict {LOC AC23 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[7]] ;# J10.8
#set_property -dict {LOC AB24 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[8]] ;# J10.9
#set_property -dict {LOC AA20 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[9]] ;# J10.10
#set_property -dict {LOC AC24 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[10]] ;# J10.11
#set_property -dict {LOC AB20 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[11]] ;# J10.12
#set_property -dict {LOC AC26 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[12]] ;# J10.13
#set_property -dict {LOC AB21 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[13]] ;# J10.14
#set_property -dict {LOC AC27 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[14]] ;# J10.15
#set_property -dict {LOC AC21 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[15]] ;# J10.16
#set_property -dict {LOC AA27 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[16]] ;# J10.17
#set_property -dict {LOC Y23 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[17]] ;# J10.18
#set_property -dict {LOC AB27 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[18]] ;# J10.19
#set_property -dict {LOC AA23 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[19]] ;# J10.20
#set_property -dict {LOC AB25 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[20]] ;# J10.21
#set_property -dict {LOC AA24 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[21]] ;# J10.22
#set_property -dict {LOC AB26 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[22]] ;# J10.23
#set_property -dict {LOC AA25 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[23]] ;# J10.24
#set_property -dict {LOC AA28 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[24]] ;# J10.25
#set_property -dict {LOC Y22 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[25]] ;# J10.26
#set_property -dict {LOC W23 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[26]] ;# J10.27
#set_property -dict {LOC V27 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[27]] ;# J10.28
#set_property -dict {LOC W24 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[28]] ;# J10.29
#set_property -dict {LOC V28 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[29]] ;# J10.30
#set_property -dict {LOC W25 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[30]] ;# J10.31
#set_property -dict {LOC U24 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[31]] ;# J10.32
#set_property -dict {LOC Y25 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[32]] ;# J10.33
#set_property -dict {LOC U25 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[33]] ;# J10.34
#set_property -dict {LOC U21 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[34]] ;# J10.35
#set_property -dict {LOC W28 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[35]] ;# J10.36
#set_property -dict {LOC U22 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[36]] ;# J10.37
#set_property -dict {LOC Y28 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[37]] ;# J10.38
#set_property -dict {LOC V22 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[38]] ;# J10.39
#set_property -dict {LOC U26 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[39]] ;# J10.40
#set_property -dict {LOC V23 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[40]] ;# J10.41
#set_property -dict {LOC U27 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[41]] ;# J10.42
#set_property -dict {LOC T22 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[42]] ;# J10.43
#set_property -dict {LOC V29 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[43]] ;# J10.44
#set_property -dict {LOC T23 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[44]] ;# J10.45
#set_property -dict {LOC W29 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[45]] ;# J10.46
#set_property -dict {LOC V21 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[46]] ;# J10.47
#set_property -dict {LOC V26 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[47]] ;# J10.48
#set_property -dict {LOC W21 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[48]] ;# J10.49
#set_property -dict {LOC W26 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[49]] ;# J10.50
#set_property -dict {LOC Y21 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[50]] ;# J10.51
#set_property -dict {LOC U29 IOSTANDARD LVCMOS12} [get_ports gpio_j10_a[51]] ;# J10.52
#set_property -dict {LOC AE27 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[0]] ;# J10.121
#set_property -dict {LOC AG31 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[1]] ;# J10.122
#set_property -dict {LOC AF27 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[2]] ;# J10.123
#set_property -dict {LOC AG32 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[3]] ;# J10.124
#set_property -dict {LOC AE28 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[4]] ;# J10.125
#set_property -dict {LOC AF33 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[5]] ;# J10.126
#set_property -dict {LOC AF28 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[6]] ;# J10.127
#set_property -dict {LOC AG34 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[7]] ;# J10.128
#set_property -dict {LOC AC28 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[8]] ;# J10.129
#set_property -dict {LOC AE32 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[9]] ;# J10.130
#set_property -dict {LOC AD28 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[10]] ;# J10.131
#set_property -dict {LOC AF32 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[11]] ;# J10.132
#set_property -dict {LOC AF29 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[12]] ;# J10.133
#set_property -dict {LOC AE33 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[13]] ;# J10.134
#set_property -dict {LOC AG29 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[14]] ;# J10.135
#set_property -dict {LOC AF34 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[15]] ;# J10.136
#set_property -dict {LOC AD29 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[16]] ;# J10.137
#set_property -dict {LOC AD30 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[17]] ;# J10.138
#set_property -dict {LOC AE30 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[18]] ;# J10.139
#set_property -dict {LOC AD31 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[19]] ;# J10.140
#set_property -dict {LOC AF30 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[20]] ;# J10.141
#set_property -dict {LOC AC31 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[21]] ;# J10.142
#set_property -dict {LOC AG30 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[22]] ;# J10.143
#set_property -dict {LOC AC32 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[23]] ;# J10.144
#set_property -dict {LOC AC29 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[24]] ;# J10.145
#set_property -dict {LOC AE31 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[25]] ;# J10.146
#set_property -dict {LOC AA32 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[26]] ;# J10.147
#set_property -dict {LOC W33 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[27]] ;# J10.148
#set_property -dict {LOC AB32 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[28]] ;# J10.149
#set_property -dict {LOC Y33 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[29]] ;# J10.150
#set_property -dict {LOC AB30 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[30]] ;# J10.151
#set_property -dict {LOC W30 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[31]] ;# J10.152
#set_property -dict {LOC AB31 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[32]] ;# J10.153
#set_property -dict {LOC Y30 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[33]] ;# J10.154
#set_property -dict {LOC AC34 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[34]] ;# J10.155
#set_property -dict {LOC V33 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[35]] ;# J10.156
#set_property -dict {LOC AD34 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[36]] ;# J10.157
#set_property -dict {LOC W34 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[37]] ;# J10.158
#set_property -dict {LOC AA29 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[38]] ;# J10.159
#set_property -dict {LOC Y31 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[39]] ;# J10.160
#set_property -dict {LOC AB29 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[40]] ;# J10.161
#set_property -dict {LOC Y32 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[41]] ;# J10.162
#set_property -dict {LOC AA34 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[42]] ;# J10.163
#set_property -dict {LOC U34 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[43]] ;# J10.164
#set_property -dict {LOC AB34 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[44]] ;# J10.165
#set_property -dict {LOC V34 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[45]] ;# J10.166
#set_property -dict {LOC AC33 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[46]] ;# J10.167
#set_property -dict {LOC V31 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[47]] ;# J10.168
#set_property -dict {LOC AD33 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[48]] ;# J10.169
#set_property -dict {LOC W31 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[49]] ;# J10.170
#set_property -dict {LOC AA33 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[50]] ;# J10.171
#set_property -dict {LOC V32 IOSTANDARD LVCMOS12} [get_ports gpio_j10_b[51]] ;# J10.172
# UART
set_property -dict {LOC F20 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports uart_txd]
set_property -dict {LOC G20 IOSTANDARD LVCMOS12} [get_ports uart_rxd]
set_false_path -to [get_ports {uart_txd}]
set_output_delay 0 [get_ports {uart_txd}]
set_false_path -from [get_ports {uart_rxd}]
set_input_delay 0 [get_ports {uart_rxd}]
# QSFP Interfaces
set_property -dict {LOC Y2 } [get_ports {qsfp0_rx_p[0]}] ;# MGTHRXP0_226 GTHE3_CHANNEL_X1Y44 / GTHE3_COMMON_X1Y11
set_property -dict {LOC Y1 } [get_ports {qsfp0_rx_n[0]}] ;# MGTHRXN0_226 GTHE3_CHANNEL_X1Y44 / GTHE3_COMMON_X1Y11
set_property -dict {LOC AA4 } [get_ports {qsfp0_tx_p[0]}] ;# MGTHTXP0_226 GTHE3_CHANNEL_X1Y44 / GTHE3_COMMON_X1Y11
set_property -dict {LOC AA3 } [get_ports {qsfp0_tx_n[0]}] ;# MGTHTXN0_226 GTHE3_CHANNEL_X1Y44 / GTHE3_COMMON_X1Y11
set_property -dict {LOC V2 } [get_ports {qsfp0_rx_p[1]}] ;# MGTHRXP1_226 GTHE3_CHANNEL_X1Y45 / GTHE3_COMMON_X1Y11
set_property -dict {LOC V1 } [get_ports {qsfp0_rx_n[1]}] ;# MGTHRXN1_226 GTHE3_CHANNEL_X1Y45 / GTHE3_COMMON_X1Y11
set_property -dict {LOC W4 } [get_ports {qsfp0_tx_p[1]}] ;# MGTHTXP1_226 GTHE3_CHANNEL_X1Y45 / GTHE3_COMMON_X1Y11
set_property -dict {LOC W3 } [get_ports {qsfp0_tx_n[1]}] ;# MGTHTXN1_226 GTHE3_CHANNEL_X1Y45 / GTHE3_COMMON_X1Y11
set_property -dict {LOC T2 } [get_ports {qsfp0_rx_p[2]}] ;# MGTHRXP2_226 GTHE3_CHANNEL_X1Y46 / GTHE3_COMMON_X1Y11
set_property -dict {LOC T1 } [get_ports {qsfp0_rx_n[2]}] ;# MGTHRXN2_226 GTHE3_CHANNEL_X1Y46 / GTHE3_COMMON_X1Y11
set_property -dict {LOC U4 } [get_ports {qsfp0_tx_p[2]}] ;# MGTHTXP2_226 GTHE3_CHANNEL_X1Y46 / GTHE3_COMMON_X1Y11
set_property -dict {LOC U3 } [get_ports {qsfp0_tx_n[2]}] ;# MGTHTXN2_226 GTHE3_CHANNEL_X1Y46 / GTHE3_COMMON_X1Y11
set_property -dict {LOC P2 } [get_ports {qsfp0_rx_p[3]}] ;# MGTHRXP3_226 GTHE3_CHANNEL_X1Y47 / GTHE3_COMMON_X1Y11
set_property -dict {LOC P1 } [get_ports {qsfp0_rx_n[3]}] ;# MGTHRXN3_226 GTHE3_CHANNEL_X1Y47 / GTHE3_COMMON_X1Y11
set_property -dict {LOC R4 } [get_ports {qsfp0_tx_p[3]}] ;# MGTHTXP3_226 GTHE3_CHANNEL_X1Y47 / GTHE3_COMMON_X1Y11
set_property -dict {LOC R3 } [get_ports {qsfp0_tx_n[3]}] ;# MGTHTXN3_226 GTHE3_CHANNEL_X1Y47 / GTHE3_COMMON_X1Y11
set_property -dict {LOC V6 } [get_ports qsfp0_mgt_refclk_p] ;# MGTREFCLK0P_226 from Y5.4
set_property -dict {LOC V5 } [get_ports qsfp0_mgt_refclk_n] ;# MGTREFCLK0N_226 from Y5.5
set_property -dict {LOC AJ11 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports {qsfp0_fs[0]}] ;# to Y5.8
set_property -dict {LOC AF10 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports {qsfp0_fs[1]}] ;# to Y5.7
set_property -dict {LOC AJ13 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports qsfp0_modsell]
set_property -dict {LOC AE12 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports qsfp0_resetl]
set_property -dict {LOC AE26 IOSTANDARD LVCMOS12 PULLUP true} [get_ports qsfp0_modprsl]
set_property -dict {LOC AE21 IOSTANDARD LVCMOS12 PULLUP true} [get_ports qsfp0_intl]
set_property -dict {LOC AF12 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports qsfp0_lpmode]
#set_property -dict {LOC AD11 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12 PULLUP true} [get_ports qsfp0_i2c_scl]
#set_property -dict {LOC AE11 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12 PULLUP true} [get_ports qsfp0_i2c_sda]
# 156.25 MHz MGT reference clock (from Y5 Si534 FB000184G, FS = 0b00)
create_clock -period 6.400 -name qsfp0_mgt_refclk [get_ports qsfp0_mgt_refclk_p]
# 200 MHz MGT reference clock (from Y5 Si534 FB000184G, FS = 0b01)
#create_clock -period 5.000 -name qsfp0_mgt_refclk [get_ports qsfp0_mgt_refclk_p]
# 250 MHz MGT reference clock (from Y5 Si534 FB000184G, FS = 0b10)
#create_clock -period 4.000 -name qsfp0_mgt_refclk [get_ports qsfp0_mgt_refclk_p]
# 312.5 MHz MGT reference clock (from Y5 Si534 FB000184G, FS = 0b11)
#create_clock -period 3.200 -name qsfp0_mgt_refclk [get_ports qsfp0_mgt_refclk_p]
set_false_path -to [get_ports {qsfp0_modsell qsfp0_resetl qsfp0_lpmode qsfp0_fs[*]}]
set_output_delay 0 [get_ports {qsfp0_modsell qsfp0_resetl qsfp0_lpmode qsfp0_fs[*]}]
set_false_path -from [get_ports {qsfp0_modprsl qsfp0_intl}]
set_input_delay 0 [get_ports {qsfp0_modprsl qsfp0_intl}]
#set_false_path -to [get_ports {qsfp0_i2c_scl qsfp0_i2c_sda}]
#set_output_delay 0 [get_ports {qsfp0_i2c_scl qsfp0_i2c_sda}]
#set_false_path -from [get_ports {qsfp0_i2c_scl qsfp0_i2c_sda}]
#set_input_delay 0 [get_ports {qsfp0_i2c_scl qsfp0_i2c_sda}]
set_property -dict {LOC M2 } [get_ports {qsfp1_rx_p[0]}] ;# MGTHRXP0_227 GTHE3_CHANNEL_X1Y40 / GTHE3_COMMON_X1Y2
set_property -dict {LOC M1 } [get_ports {qsfp1_rx_n[0]}] ;# MGTHRXN0_227 GTHE3_CHANNEL_X1Y40 / GTHE3_COMMON_X1Y2
set_property -dict {LOC N4 } [get_ports {qsfp1_tx_p[0]}] ;# MGTHTXP0_227 GTHE3_CHANNEL_X1Y40 / GTHE3_COMMON_X1Y2
set_property -dict {LOC N3 } [get_ports {qsfp1_tx_n[0]}] ;# MGTHTXN0_227 GTHE3_CHANNEL_X1Y40 / GTHE3_COMMON_X1Y2
set_property -dict {LOC K2 } [get_ports {qsfp1_rx_p[1]}] ;# MGTHRXP1_227 GTHE3_CHANNEL_X1Y41 / GTHE3_COMMON_X1Y2
set_property -dict {LOC K1 } [get_ports {qsfp1_rx_n[1]}] ;# MGTHRXN1_227 GTHE3_CHANNEL_X1Y41 / GTHE3_COMMON_X1Y2
set_property -dict {LOC L4 } [get_ports {qsfp1_tx_p[1]}] ;# MGTHTXP1_227 GTHE3_CHANNEL_X1Y41 / GTHE3_COMMON_X1Y2
set_property -dict {LOC L3 } [get_ports {qsfp1_tx_n[1]}] ;# MGTHTXN1_227 GTHE3_CHANNEL_X1Y41 / GTHE3_COMMON_X1Y2
set_property -dict {LOC H2 } [get_ports {qsfp1_rx_p[2]}] ;# MGTHRXP2_227 GTHE3_CHANNEL_X1Y42 / GTHE3_COMMON_X1Y2
set_property -dict {LOC H1 } [get_ports {qsfp1_rx_n[2]}] ;# MGTHRXN2_227 GTHE3_CHANNEL_X1Y42 / GTHE3_COMMON_X1Y2
set_property -dict {LOC J4 } [get_ports {qsfp1_tx_p[2]}] ;# MGTHTXP2_227 GTHE3_CHANNEL_X1Y42 / GTHE3_COMMON_X1Y2
set_property -dict {LOC J3 } [get_ports {qsfp1_tx_n[2]}] ;# MGTHTXN2_227 GTHE3_CHANNEL_X1Y42 / GTHE3_COMMON_X1Y2
set_property -dict {LOC F2 } [get_ports {qsfp1_rx_p[3]}] ;# MGTHRXP3_227 GTHE3_CHANNEL_X1Y43 / GTHE3_COMMON_X1Y2
set_property -dict {LOC F1 } [get_ports {qsfp1_rx_n[3]}] ;# MGTHRXN3_227 GTHE3_CHANNEL_X1Y43 / GTHE3_COMMON_X1Y2
set_property -dict {LOC G4 } [get_ports {qsfp1_tx_p[3]}] ;# MGTHTXP3_227 GTHE3_CHANNEL_X1Y43 / GTHE3_COMMON_X1Y2
set_property -dict {LOC G3 } [get_ports {qsfp1_tx_n[3]}] ;# MGTHTXN3_227 GTHE3_CHANNEL_X1Y43 / GTHE3_COMMON_X1Y2
#set_property -dict {LOC P6 } [get_ports qsfp1_mgt_refclk_p] ;# MGTREFCLK0P_227 from Y4.4
#set_property -dict {LOC P5 } [get_ports qsfp1_mgt_refclk_n] ;# MGTREFCLK0N_227 from Y4.5
set_property -dict {LOC AG11 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports {qsfp1_fs[0]}] ;# to Y4.8
set_property -dict {LOC AH11 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports {qsfp1_fs[1]}] ;# to Y4.7
set_property -dict {LOC AK13 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports qsfp1_modsell]
set_property -dict {LOC AL13 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports qsfp1_resetl]
set_property -dict {LOC AM9 IOSTANDARD LVCMOS25 PULLUP true} [get_ports qsfp1_modprsl]
set_property -dict {LOC AH13 IOSTANDARD LVCMOS25 PULLUP true} [get_ports qsfp1_intl]
set_property -dict {LOC AK11 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12} [get_ports qsfp1_lpmode]
#set_property -dict {LOC AE13 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12 PULLUP true} [get_ports qsfp1_i2c_scl]
#set_property -dict {LOC AF13 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12 PULLUP true} [get_ports qsfp1_i2c_sda]
# 156.25 MHz MGT reference clock (from Y4 Si534 FB000184G, FS = 0b00)
#create_clock -period 6.400 -name qsfp1_mgt_refclk [get_ports qsfp1_mgt_refclk_p]
# 200 MHz MGT reference clock (from Y4 Si534 FB000184G, FS = 0b01)
#create_clock -period 5.000 -name qsfp1_mgt_refclk [get_ports qsfp1_mgt_refclk_p]
# 250 MHz MGT reference clock (from Y4 Si534 FB000184G, FS = 0b10)
#create_clock -period 4.000 -name qsfp1_mgt_refclk [get_ports qsfp1_mgt_refclk_p]
# 312.5 MHz MGT reference clock (from Y4 Si534 FB000184G, FS = 0b11)
#create_clock -period 3.200 -name qsfp1_mgt_refclk [get_ports qsfp1_mgt_refclk_p]
set_false_path -to [get_ports {qsfp1_modsell qsfp1_resetl qsfp1_lpmode qsfp1_fs[*]}]
set_output_delay 0 [get_ports {qsfp1_modsell qsfp1_resetl qsfp1_lpmode qsfp1_fs[*]}]
set_false_path -from [get_ports {qsfp1_modprsl qsfp1_intl}]
set_input_delay 0 [get_ports {qsfp1_modprsl qsfp1_intl}]
#set_false_path -to [get_ports {qsfp1_i2c_scl qsfp1_i2c_sda}]
#set_output_delay 0 [get_ports {qsfp1_i2c_scl qsfp1_i2c_sda}]
#set_false_path -from [get_ports {qsfp1_i2c_scl qsfp1_i2c_sda}]
#set_input_delay 0 [get_ports {qsfp1_i2c_scl qsfp1_i2c_sda}]
# I2C EEPROM
#set_property -dict {LOC AG9 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12 PULLUP true} [get_ports eeprom_i2c_scl]
#set_property -dict {LOC AE8 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12 PULLUP true} [get_ports eeprom_i2c_sda]
#set_false_path -to [get_ports {eeprom_i2c_sda eeprom_i2c_scl}]
#set_output_delay 0 [get_ports {eeprom_i2c_sda eeprom_i2c_scl}]
#set_false_path -from [get_ports {eeprom_i2c_sda eeprom_i2c_scl}]
#set_input_delay 0 [get_ports {eeprom_i2c_sda eeprom_i2c_scl}]
# QSPI flash
#set_property -dict {LOC AF8 IOSTANDARD LVCMOS25 DRIVE 12 PULLUP true} [get_ports {qspi_clk}]
#set_property -dict {LOC AD10 IOSTANDARD LVCMOS25 DRIVE 12 PULLUP true} [get_ports {qspi_dq[0]}]
#set_property -dict {LOC AH8 IOSTANDARD LVCMOS25 DRIVE 12 PULLUP true} [get_ports {qspi_dq[1]}]
#set_property -dict {LOC AE10 IOSTANDARD LVCMOS25 DRIVE 12 PULLUP true} [get_ports {qspi_dq[2]}]
#set_property -dict {LOC AD9 IOSTANDARD LVCMOS25 DRIVE 12 PULLUP true} [get_ports {qspi_dq[3]}]
#set_property -dict {LOC AH9 IOSTANDARD LVCMOS25 DRIVE 12 PULLUP true} [get_ports {qspi_cs}]
#set_property -dict {LOC AD8 IOSTANDARD LVCMOS25 DRIVE 12 PULLUP true} [get_ports {qspi_reset}]
# PCIe Interface
set_property -dict {LOC AB2 } [get_ports {pcie_rx_p[0]}] ;# MGTHRXP3_225 GTHE3_CHANNEL_X0Y7 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AB1 } [get_ports {pcie_rx_n[0]}] ;# MGTHRXN3_225 GTHE3_CHANNEL_X0Y7 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AC4 } [get_ports {pcie_tx_p[0]}] ;# MGTHTXP3_225 GTHE3_CHANNEL_X0Y7 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AC3 } [get_ports {pcie_tx_n[0]}] ;# MGTHTXN3_225 GTHE3_CHANNEL_X0Y7 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AD2 } [get_ports {pcie_rx_p[1]}] ;# MGTHRXP2_225 GTHE3_CHANNEL_X0Y6 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AD1 } [get_ports {pcie_rx_n[1]}] ;# MGTHRXN2_225 GTHE3_CHANNEL_X0Y6 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AE4 } [get_ports {pcie_tx_p[1]}] ;# MGTHTXP2_225 GTHE3_CHANNEL_X0Y6 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AE3 } [get_ports {pcie_tx_n[1]}] ;# MGTHTXN2_225 GTHE3_CHANNEL_X0Y6 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AF2 } [get_ports {pcie_rx_p[2]}] ;# MGTHRXP1_225 GTHE3_CHANNEL_X0Y5 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AF1 } [get_ports {pcie_rx_n[2]}] ;# MGTHRXN1_225 GTHE3_CHANNEL_X0Y5 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AG4 } [get_ports {pcie_tx_p[2]}] ;# MGTHTXP1_225 GTHE3_CHANNEL_X0Y5 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AG3 } [get_ports {pcie_tx_n[2]}] ;# MGTHTXN1_225 GTHE3_CHANNEL_X0Y5 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AH2 } [get_ports {pcie_rx_p[3]}] ;# MGTHRXP0_225 GTHE3_CHANNEL_X0Y4 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AH1 } [get_ports {pcie_rx_n[3]}] ;# MGTHRXN0_225 GTHE3_CHANNEL_X0Y4 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AH6 } [get_ports {pcie_tx_p[3]}] ;# MGTHTXP0_225 GTHE3_CHANNEL_X0Y4 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AH5 } [get_ports {pcie_tx_n[3]}] ;# MGTHTXN0_225 GTHE3_CHANNEL_X0Y4 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AJ4 } [get_ports {pcie_rx_p[4]}] ;# MGTHRXP3_224 GTHE3_CHANNEL_X0Y3 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AJ3 } [get_ports {pcie_rx_n[4]}] ;# MGTHRXN3_224 GTHE3_CHANNEL_X0Y3 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AK6 } [get_ports {pcie_tx_p[4]}] ;# MGTHTXP3_224 GTHE3_CHANNEL_X0Y3 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AK5 } [get_ports {pcie_tx_n[4]}] ;# MGTHTXN3_224 GTHE3_CHANNEL_X0Y3 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AK2 } [get_ports {pcie_rx_p[5]}] ;# MGTHRXP2_224 GTHE3_CHANNEL_X0Y2 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AK1 } [get_ports {pcie_rx_n[5]}] ;# MGTHRXN2_224 GTHE3_CHANNEL_X0Y2 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AL4 } [get_ports {pcie_tx_p[5]}] ;# MGTHTXP2_224 GTHE3_CHANNEL_X0Y2 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AL3 } [get_ports {pcie_tx_n[5]}] ;# MGTHTXN2_224 GTHE3_CHANNEL_X0Y2 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AM2 } [get_ports {pcie_rx_p[6]}] ;# MGTHRXP1_224 GTHE3_CHANNEL_X0Y1 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AM1 } [get_ports {pcie_rx_n[6]}] ;# MGTHRXN1_224 GTHE3_CHANNEL_X0Y1 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AM6 } [get_ports {pcie_tx_p[6]}] ;# MGTHTXP1_224 GTHE3_CHANNEL_X0Y1 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AM5 } [get_ports {pcie_tx_n[6]}] ;# MGTHTXN1_224 GTHE3_CHANNEL_X0Y1 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AP2 } [get_ports {pcie_rx_p[7]}] ;# MGTHRXP0_224 GTHE3_CHANNEL_X0Y0 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AP1 } [get_ports {pcie_rx_n[7]}] ;# MGTHRXN0_224 GTHE3_CHANNEL_X0Y0 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AN4 } [get_ports {pcie_tx_p[7]}] ;# MGTHTXP0_224 GTHE3_CHANNEL_X0Y0 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AN3 } [get_ports {pcie_tx_n[7]}] ;# MGTHTXN0_224 GTHE3_CHANNEL_X0Y0 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AF6 } [get_ports pcie_refclk_p] ;# MGTREFCLK0P_224 from U80 ICS 1S1022EL
set_property -dict {LOC AF5 } [get_ports pcie_refclk_n] ;# MGTREFCLK0N_224 from U80 ICS 1S1022EL
set_property -dict {LOC K22 IOSTANDARD LVCMOS18 PULLUP true} [get_ports pcie_reset_n]
# 100 MHz MGT reference clock
create_clock -period 10 -name pcie_mgt_refclk [get_ports pcie_refclk_p]
set_false_path -from [get_ports {pcie_reset_n}]
set_input_delay 0 [get_ports {pcie_reset_n}]
# DDR4
# 9x MT40A512M8RH-083E
# Control
#set_property -dict {LOC AG17 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_adr[0]}] ;# IO_L15P_T2L_N4_AD11P_45
#set_property -dict {LOC AH16 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_adr[1]}] ;# IO_L14P_T2L_N2_GC_45
#set_property -dict {LOC AF15 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_adr[2]}] ;# IO_L20P_T3L_N2_AD1P_45
#set_property -dict {LOC AJ16 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_adr[3]}] ;# IO_L14N_T2L_N3_GC_45
#set_property -dict {LOC AH19 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_adr[4]}] ;# IO_L17N_T2U_N9_AD10N_45
#set_property -dict {LOC AJ15 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_adr[5]}] ;# IO_L16P_T2U_N6_QBC_AD3P_45
#set_property -dict {LOC AE18 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_adr[6]}] ;# IO_L21P_T3L_N4_AD8P_45
#set_property -dict {LOC AG15 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_adr[7]}] ;# IO_L18P_T2U_N10_AD2P_45
#set_property -dict {LOC AD18 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_adr[8]}] ;# IO_L19N_T3L_N1_DBC_AD9N_45
#set_property -dict {LOC AF14 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_adr[9]}] ;# IO_L20N_T3L_N3_AD1N_45
#set_property -dict {LOC AJ18 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_adr[10]}] ;# IO_L11P_T1U_N8_GC_45
#set_property -dict {LOC AD19 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_adr[11]}] ;# IO_L19P_T3L_N0_DBC_AD9P_45
#set_property -dict {LOC AK16 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_adr[12]}] ;# IO_L12N_T1U_N11_GC_45
#set_property -dict {LOC AG16 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_adr[13]}] ;# IO_L15N_T2L_N5_AD11N_45
#set_property -dict {LOC AJ19 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_adr[14]}] ;# IO_T1U_N12_45
#set_property -dict {LOC AL17 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_adr[15]}] ;# IO_L10N_T1U_N7_QBC_AD4N_45
#set_property -dict {LOC AL14 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_adr[16]}] ;# IO_L7P_T1L_N0_QBC_AD13P_45
#set_property -dict {LOC AF18 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_ba[0]}] ;# IO_L21N_T3L_N5_AD8N_45
#set_property -dict {LOC AJ14 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_ba[1]}] ;# IO_L16N_T2U_N7_QBC_AD3N_45
#set_property -dict {LOC AG19 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_bg[0]}] ;# IO_L17P_T2U_N8_AD10P_45
#set_property -dict {LOC AK15 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_bg[1]}] ;# IO_L9P_T1L_N4_AD12P_45
#set_property -dict {LOC AE17 IOSTANDARD DIFF_SSTL12_DCI} [get_ports {ddr4_ck_t}] ;# IO_L23P_T3U_N8_45
#set_property -dict {LOC AF17 IOSTANDARD DIFF_SSTL12_DCI} [get_ports {ddr4_ck_c}] ;# IO_L23N_T3U_N9_45
#set_property -dict {LOC AL18 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_cke}] ;# IO_L10P_T1U_N6_QBC_AD4P_45
#set_property -dict {LOC AL15 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_cs_n}] ;# IO_L9N_T1L_N5_AD12N_45
#set_property -dict {LOC AK17 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_act_n}] ;# IO_L12P_T1U_N10_GC_45
#set_property -dict {LOC AM19 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_odt}] ;# IO_L8N_T1L_N3_AD5N_45
#set_property -dict {LOC AE16 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_par}] ;# IO_L22P_T3U_N6_DBC_AD0P_45
#set_property -dict {LOC AD16 IOSTANDARD LVCMOS12 } [get_ports {ddr4_reset_n}] ;# IO_L24P_T3U_N10_45
#set_property -dict {LOC AD15 IOSTANDARD LVCMOS12 } [get_ports {ddr4_alert_n}] ;# IO_L24N_T3U_N11_45
#set_property -dict {LOC AD14 IOSTANDARD LVCMOS12 } [get_ports {ddr4_ten}] ;# IO_T3U_N12_45
# U30
#set_property -dict {LOC AD21 IOSTANDARD POD12_DCI } [get_ports {ddr4_dm_dbi_n[0]}] ;# IO_L1P_T0L_N0_DBC_44 to U30.DM_DBI_n
#set_property -dict {LOC AF20 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[0]}] ;# IO_L2P_T0L_N2_44 to U30.DQ[7:0]
#set_property -dict {LOC AG20 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[1]}] ;# IO_L2N_T0L_N3_44 to U30.DQ[7:0]
#set_property -dict {LOC AD20 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[2]}] ;# IO_L3P_T0L_N4_AD15P_44 to U30.DQ[7:0]
#set_property -dict {LOC AE20 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[3]}] ;# IO_L3N_T0L_N5_AD15N_44 to U30.DQ[7:0]
#set_property -dict {LOC AG21 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_dqs_t[0]}] ;# IO_L4P_T0U_N6_DBC_AD7P_44 to U30.DQS_t
#set_property -dict {LOC AH21 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_dqs_c[0]}] ;# IO_L4N_T0U_N7_DBC_AD7N_44 to U30.DQS_c
#set_property -dict {LOC AE22 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[4]}] ;# IO_L5P_T0U_N8_AD14P_44 to U30.DQ[7:0]
#set_property -dict {LOC AE23 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[5]}] ;# IO_L5N_T0U_N9_AD14N_44 to U30.DQ[7:0]
#set_property -dict {LOC AF22 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[6]}] ;# IO_L6P_T0U_N10_AD6P_44 to U30.DQ[7:0]
#set_property -dict {LOC AG22 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[7]}] ;# IO_L6N_T0U_N11_AD6N_44 to U30.DQ[7:0]
# U31
#set_property -dict {LOC AJ21 IOSTANDARD POD12_DCI } [get_ports {ddr4_dm_dbi_n[1]}] ;# IO_L13P_T2L_N0_GC_QBC_44 to U31.DM_DBI_n
#set_property -dict {LOC AK22 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[8]}] ;# IO_L14P_T2L_N2_GC_44 to U31.DQ[7:0]
#set_property -dict {LOC AK23 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[9]}] ;# IO_L14N_T2L_N3_GC_44 to U31.DQ[7:0]
#set_property -dict {LOC AL20 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[10]}] ;# IO_L15P_T2L_N4_AD11P_44 to U31.DQ[7:0]
#set_property -dict {LOC AM20 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[11]}] ;# IO_L15N_T2L_N5_AD11N_44 to U31.DQ[7:0]
#set_property -dict {LOC AJ20 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_dqs_t[1]}] ;# IO_L16P_T2U_N6_QBC_AD3P_44 to U31.DQS_t
#set_property -dict {LOC AK20 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_dqs_c[1]}] ;# IO_L16N_T2U_N7_QBC_AD3N_44 to U31.DQS_c
#set_property -dict {LOC AL22 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[12]}] ;# IO_L17P_T2U_N8_AD10P_44 to U31.DQ[7:0]
#set_property -dict {LOC AL23 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[13]}] ;# IO_L17N_T2U_N9_AD10N_44 to U31.DQ[7:0]
#set_property -dict {LOC AL24 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[14]}] ;# IO_L18P_T2U_N10_AD2P_44 to U31.DQ[7:0]
#set_property -dict {LOC AL25 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[15]}] ;# IO_L18N_T2U_N11_AD2N_44 to U31.DQ[7:0]
# U32
#set_property -dict {LOC AH26 IOSTANDARD POD12_DCI } [get_ports {ddr4_dm_dbi_n[2]}] ;# IO_L1P_T0L_N0_DBC_46 to U32.DM_DBI_n
#set_property -dict {LOC AM26 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[16]}] ;# IO_L2P_T0L_N2_46 to U32.DQ[7:0]
#set_property -dict {LOC AM27 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[17]}] ;# IO_L2N_T0L_N3_46 to U32.DQ[7:0]
#set_property -dict {LOC AK26 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[18]}] ;# IO_L3P_T0L_N4_AD15P_46 to U32.DQ[7:0]
#set_property -dict {LOC AK27 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[19]}] ;# IO_L3N_T0L_N5_AD15N_46 to U32.DQ[7:0]
#set_property -dict {LOC AL27 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_dqs_t[2]}] ;# IO_L4P_T0U_N6_DBC_AD7P_46 to U32.DQS_t
#set_property -dict {LOC AL28 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_dqs_c[2]}] ;# IO_L4N_T0U_N7_DBC_AD7N_46 to U32.DQS_c
#set_property -dict {LOC AH27 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[20]}] ;# IO_L5P_T0U_N8_AD14P_46 to U32.DQ[7:0]
#set_property -dict {LOC AH28 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[21]}] ;# IO_L5N_T0U_N9_AD14N_46 to U32.DQ[7:0]
#set_property -dict {LOC AJ28 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[22]}] ;# IO_L6P_T0U_N10_AD6P_46 to U32.DQ[7:0]
#set_property -dict {LOC AK28 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[23]}] ;# IO_L6N_T0U_N11_AD6N_46 to U32.DQ[7:0]
# U33
#set_property -dict {LOC AN26 IOSTANDARD POD12_DCI } [get_ports {ddr4_dm_dbi_n[3]}] ;# IO_L7P_T1L_N0_QBC_AD13P_46 to U33.DM_DBI_n
#set_property -dict {LOC AP28 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[24]}] ;# IO_L8P_T1L_N2_AD5P_46 to U33.DQ[7:0]
#set_property -dict {LOC AP29 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[25]}] ;# IO_L8N_T1L_N3_AD5N_46 to U33.DQ[7:0]
#set_property -dict {LOC AN27 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[26]}] ;# IO_L9P_T1L_N4_AD12P_46 to U33.DQ[7:0]
#set_property -dict {LOC AN28 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[27]}] ;# IO_L9N_T1L_N5_AD12N_46 to U33.DQ[7:0]
#set_property -dict {LOC AN29 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_dqs_t[3]}] ;# IO_L10P_T1U_N6_QBC_AD4P_46 to U33.DQS_t
#set_property -dict {LOC AP30 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_dqs_c[3]}] ;# IO_L10N_T1U_N7_QBC_AD4N_46 to U33.DQS_c
#set_property -dict {LOC AL29 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[28]}] ;# IO_L11P_T1U_N8_GC_46 to U33.DQ[7:0]
#set_property -dict {LOC AM29 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[29]}] ;# IO_L11N_T1U_N9_GC_46 to U33.DQ[7:0]
#set_property -dict {LOC AL30 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[30]}] ;# IO_L12P_T1U_N10_GC_46 to U33.DQ[7:0]
#set_property -dict {LOC AM30 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[31]}] ;# IO_L12N_T1U_N11_GC_46 to U33.DQ[7:0]
# U83
#set_property -dict {LOC AN14 IOSTANDARD POD12_DCI } [get_ports {ddr4_dm_dbi_n[4]}] ;# IO_L1P_T0L_N0_DBC_45 to U83.DM_DBI_n
#set_property -dict {LOC AN19 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[32]}] ;# IO_L2P_T0L_N2_45 to U83.DQ[7:0]
#set_property -dict {LOC AP18 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[33]}] ;# IO_L2N_T0L_N3_45 to U83.DQ[7:0]
#set_property -dict {LOC AM17 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[34]}] ;# IO_L3P_T0L_N4_AD15P_45 to U83.DQ[7:0]
#set_property -dict {LOC AN16 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[35]}] ;# IO_L3N_T0L_N5_AD15N_45 to U83.DQ[7:0]
#set_property -dict {LOC AN18 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_dqs_t[4]}] ;# IO_L4P_T0U_N6_DBC_AD7P_45 to U83.DQS_t
#set_property -dict {LOC AN17 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_dqs_c[4]}] ;# IO_L4N_T0U_N7_DBC_AD7N_45 to U83.DQS_c
#set_property -dict {LOC AM16 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[36]}] ;# IO_L5P_T0U_N8_AD14P_45 to U83.DQ[7:0]
#set_property -dict {LOC AM15 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[37]}] ;# IO_L5N_T0U_N9_AD14N_45 to U83.DQ[7:0]
#set_property -dict {LOC AP16 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[38]}] ;# IO_L6P_T0U_N10_AD6P_45 to U83.DQ[7:0]
#set_property -dict {LOC AP15 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[39]}] ;# IO_L6N_T0U_N11_AD6N_45 to U83.DQ[7:0]
# U86
#set_property -dict {LOC AM21 IOSTANDARD POD12_DCI } [get_ports {ddr4_dm_dbi_n[5]}] ;# IO_L19P_T3L_N0_DBC_AD9P_44 to U86.DM_DBI_n
#set_property -dict {LOC AM22 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[40]}] ;# IO_L20P_T3L_N2_AD1P_44 to U86.DQ[7:0]
#set_property -dict {LOC AN22 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[41]}] ;# IO_L20N_T3L_N3_AD1N_44 to U86.DQ[7:0]
#set_property -dict {LOC AM24 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[42]}] ;# IO_L21P_T3L_N4_AD8P_44 to U86.DQ[7:0]
#set_property -dict {LOC AN24 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[43]}] ;# IO_L21N_T3L_N5_AD8N_44 to U86.DQ[7:0]
#set_property -dict {LOC AP20 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_dqs_t[5]}] ;# IO_L22P_T3U_N6_DBC_AD0P_44 to U86.DQS_t
#set_property -dict {LOC AP21 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_dqs_c[5]}] ;# IO_L22N_T3U_N7_DBC_AD0N_44 to U86.DQS_c
#set_property -dict {LOC AP24 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[44]}] ;# IO_L23P_T3U_N8_44 to U86.DQ[7:0]
#set_property -dict {LOC AP25 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[45]}] ;# IO_L23N_T3U_N9_44 to U86.DQ[7:0]
#set_property -dict {LOC AN23 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[46]}] ;# IO_L24P_T3U_N10_44 to U86.DQ[7:0]
#set_property -dict {LOC AP23 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[47]}] ;# IO_L24N_T3U_N11_44 to U86.DQ[7:0]
# U87
#set_property -dict {LOC AE25 IOSTANDARD POD12_DCI } [get_ports {ddr4_dm_dbi_n[6]}] ;# IO_L7P_T1L_N0_QBC_AD13P_44 to U87.DM_DBI_n
#set_property -dict {LOC AF23 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[48]}] ;# IO_L8P_T1L_N2_AD5P_44 to U87.DQ[7:0]
#set_property -dict {LOC AF24 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[49]}] ;# IO_L8N_T1L_N3_AD5N_44 to U87.DQ[7:0]
#set_property -dict {LOC AG24 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[50]}] ;# IO_L9P_T1L_N4_AD12P_44 to U87.DQ[7:0]
#set_property -dict {LOC AG25 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[51]}] ;# IO_L9N_T1L_N5_AD12N_44 to U87.DQ[7:0]
#set_property -dict {LOC AH24 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_dqs_t[6]}] ;# IO_L10P_T1U_N6_QBC_AD4P_44 to U87.DQS_t
#set_property -dict {LOC AJ25 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_dqs_c[6]}] ;# IO_L10N_T1U_N7_QBC_AD4N_44 to U87.DQS_c
#set_property -dict {LOC AJ23 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[52]}] ;# IO_L11P_T1U_N8_GC_44 to U87.DQ[7:0]
#set_property -dict {LOC AJ24 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[53]}] ;# IO_L11N_T1U_N9_GC_44 to U87.DQ[7:0]
#set_property -dict {LOC AH22 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[54]}] ;# IO_L12P_T1U_N10_GC_44 to U87.DQ[7:0]
#set_property -dict {LOC AH23 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[55]}] ;# IO_L12N_T1U_N11_GC_44 to U87.DQ[7:0]
# U88
#set_property -dict {LOC AJ29 IOSTANDARD POD12_DCI } [get_ports {ddr4_dm_dbi_n[7]}] ;# IO_L13P_T2L_N0_GC_QBC_46 to U88.DM_DBI_n
#set_property -dict {LOC AK31 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[56]}] ;# IO_L14P_T2L_N2_GC_46 to U88.DQ[7:0]
#set_property -dict {LOC AK32 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[57]}] ;# IO_L14N_T2L_N3_GC_46 to U88.DQ[7:0]
#set_property -dict {LOC AJ30 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[58]}] ;# IO_L15P_T2L_N4_AD11P_46 to U88.DQ[7:0]
#set_property -dict {LOC AJ31 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[59]}] ;# IO_L15N_T2L_N5_AD11N_46 to U88.DQ[7:0]
#set_property -dict {LOC AH33 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_dqs_t[7]}] ;# IO_L16P_T2U_N6_QBC_AD3P_46 to U88.DQS_t
#set_property -dict {LOC AJ33 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_dqs_c[7]}] ;# IO_L16N_T2U_N7_QBC_AD3N_46 to U88.DQS_c
#set_property -dict {LOC AH31 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[60]}] ;# IO_L17P_T2U_N8_AD10P_46 to U88.DQ[7:0]
#set_property -dict {LOC AH32 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[61]}] ;# IO_L17N_T2U_N9_AD10N_46 to U88.DQ[7:0]
#set_property -dict {LOC AH34 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[62]}] ;# IO_L18P_T2U_N10_AD2P_46 to U88.DQ[7:0]
#set_property -dict {LOC AJ34 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[63]}] ;# IO_L18N_T2U_N11_AD2N_46 to U88.DQ[7:0]
# U89
#set_property -dict {LOC AL32 IOSTANDARD POD12_DCI } [get_ports {ddr4_dm_dbi_n[8]}] ;# IO_L19P_T3L_N0_DBC_AD9P_46 to U89.DM_DBI_n
#set_property -dict {LOC AN33 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[64]}] ;# IO_L20P_T3L_N2_AD1P_46 to U89.DQ[7:0]
#set_property -dict {LOC AP33 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[65]}] ;# IO_L20N_T3L_N3_AD1N_46 to U89.DQ[7:0]
#set_property -dict {LOC AN31 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[66]}] ;# IO_L21P_T3L_N4_AD8P_46 to U89.DQ[7:0]
#set_property -dict {LOC AP31 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[67]}] ;# IO_L21N_T3L_N5_AD8N_46 to U89.DQ[7:0]
#set_property -dict {LOC AN34 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_dqs_t[8]}] ;# IO_L22P_T3U_N6_DBC_AD0P_46 to U89.DQS_t
#set_property -dict {LOC AP34 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_dqs_c[8]}] ;# IO_L22N_T3U_N7_DBC_AD0N_46 to U89.DQS_c
#set_property -dict {LOC AM32 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[68]}] ;# IO_L23P_T3U_N8_46 to U89.DQ[7:0]
#set_property -dict {LOC AN32 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[69]}] ;# IO_L23N_T3U_N9_46 to U89.DQ[7:0]
#set_property -dict {LOC AL34 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[70]}] ;# IO_L24P_T3U_N10_46 to U89.DQ[7:0]
#set_property -dict {LOC AM34 IOSTANDARD POD12_DCI } [get_ports {ddr4_dq[71]}] ;# IO_L24N_T3U_N11_46 to U89.DQ[7:0]
# 200 MHz DDR4 clock (Si598 FCA000126G) (Y6)
set_property -dict {LOC AH18 IOSTANDARD LVDS} [get_ports clk_ddr4_p] ;# from Y6.4
set_property -dict {LOC AH17 IOSTANDARD LVDS} [get_ports clk_ddr4_n] ;# from Y6.5
create_clock -period 5.000 -name clk_ddr4 [get_ports clk_ddr4_p]
#set_property -dict {LOC AG12 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12 PULLUP true} [get_ports clk_ddr4_i2c_scl]
#set_property -dict {LOC AH12 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12 PULLUP true} [get_ports clk_ddr4_i2c_sda]
# 200 MHz RLD3 clock (Si598 FCA000126G) (Y3)
#set_property -dict {LOC D23 IOSTANDARD LVDS} [get_ports clk_rld3_p] ;# from Y3.4
#set_property -dict {LOC C23 IOSTANDARD LVDS} [get_ports clk_rld3_n] ;# from Y3.5
#create_clock -period 5.000 -name clk_rld3 [get_ports clk_rld3_p]
#set_property -dict {LOC AG10 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12 PULLUP true} [get_ports clk_rld3_i2c_scl]
#set_property -dict {LOC AF9 IOSTANDARD LVCMOS25 SLEW SLOW DRIVE 12 PULLUP true} [get_ports clk_rld3_i2c_sda]
# BPI flash
set_property -dict {LOC M20 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[4]}]
set_property -dict {LOC L20 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[5]}]
set_property -dict {LOC R21 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[6]}]
set_property -dict {LOC R22 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[7]}]
set_property -dict {LOC P20 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[8]}]
set_property -dict {LOC P21 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[9]}]
set_property -dict {LOC N22 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[10]}]
set_property -dict {LOC M22 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[11]}]
set_property -dict {LOC R23 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[12]}]
set_property -dict {LOC P23 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[13]}]
set_property -dict {LOC R25 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[14]}]
set_property -dict {LOC R26 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_dq[15]}]
set_property -dict {LOC T24 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[0]}]
set_property -dict {LOC T25 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[1]}]
set_property -dict {LOC T27 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[2]}]
set_property -dict {LOC R27 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[3]}]
set_property -dict {LOC P24 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[4]}]
set_property -dict {LOC P25 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[5]}]
set_property -dict {LOC P26 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[6]}]
set_property -dict {LOC N26 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[7]}]
set_property -dict {LOC N24 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[8]}]
set_property -dict {LOC M24 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[9]}]
set_property -dict {LOC M25 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[10]}]
set_property -dict {LOC M26 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[11]}]
set_property -dict {LOC L22 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[12]}]
set_property -dict {LOC K23 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[13]}]
set_property -dict {LOC L25 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[14]}]
set_property -dict {LOC K25 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[15]}]
set_property -dict {LOC L23 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[16]}]
set_property -dict {LOC L24 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[17]}]
set_property -dict {LOC M27 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[18]}]
set_property -dict {LOC L27 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[19]}]
set_property -dict {LOC J23 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[20]}]
set_property -dict {LOC H24 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[21]}]
set_property -dict {LOC J26 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[22]}]
set_property -dict {LOC H26 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_addr[23]}]
set_property -dict {LOC J24 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_region[0]}]
set_property -dict {LOC J25 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_region[1]}]
set_property -dict {LOC G25 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_oe_n}]
set_property -dict {LOC G26 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_we_n}]
set_property -dict {LOC N27 IOSTANDARD LVCMOS18 DRIVE 16} [get_ports {flash_adv_n}]
set_false_path -to [get_ports {flash_dq[*] flash_addr[*] flash_oe_n flash_we_n flash_adv_n}]
set_output_delay 0 [get_ports {flash_dq[*] flash_addr[*] flash_oe_n flash_we_n flash_adv_n}]
set_false_path -from [get_ports {flash_dq[*]}]
set_input_delay 0 [get_ports {flash_dq[*]}]

View File

@@ -0,0 +1,97 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
# FPGA settings
FPGA_PART = xcku040-ffva1156-2-e
FPGA_TOP = fpga
FPGA_ARCH = kintexu
RTL_DIR = ../rtl
LIB_DIR = ../lib
TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
# Files for synthesis
SYN_FILES = $(RTL_DIR)/fpga.sv
SYN_FILES += $(RTL_DIR)/fpga_core.sv
SYN_FILES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_micro_pcie_us.f
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_if_uart.f
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_switch.sv
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_apb.f
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_stats.f
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv
SYN_FILES += $(TAXI_SRC_DIR)/pyrite/rtl/pyrite_pcie_us_vsec_bpi.f
# XDC files
XDC_FILES = ../fpga.xdc
XDC_FILES += $(TAXI_SRC_DIR)/eth/syn/vivado/taxi_eth_mac_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/axis/syn/vivado/taxi_axis_async_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_leaf.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_phc_regs.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_rel2tod.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_reset.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_signal.tcl
# IP
IP_TCL_FILES += ../ip/pcie3_ultrascale_0.tcl
IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_phy_10g_us_gth_156.tcl
# Configuration
CONFIG_TCL_FILES = ./config.tcl
include ../common/vivado.mk
program: $(PROJECT).bit
echo "open_hw_manager" > program.tcl
echo "connect_hw_server" >> program.tcl
echo "open_hw_target" >> program.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> program.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> program.tcl
echo "set_property PROGRAM.FILE {$(PROJECT).bit} [current_hw_device]" >> program.tcl
echo "program_hw_devices [current_hw_device]" >> program.tcl
echo "exit" >> program.tcl
vivado -nojournal -nolog -mode batch -source program.tcl
$(PROJECT).mcs $(PROJECT).prm: $(PROJECT).bit
echo "write_cfgmem -force -format mcs -size 128 -interface BPIx16 -loadbit {up 0x0000000 $*.bit} -checksum -file $*.mcs" > generate_mcs.tcl
echo "exit" >> generate_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*$$x rev/$*_rev$$COUNT$$x; \
echo "Output: rev/$*_rev$$COUNT$$x"; done;
flash: $(PROJECT).mcs $(PROJECT).prm
echo "open_hw_manager" > flash.tcl
echo "connect_hw_server" >> flash.tcl
echo "open_hw_target" >> flash.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> flash.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> flash.tcl
echo "create_hw_cfgmem -hw_device [current_hw_device] [lindex [get_cfgmem_parts {mt28gu01gaax1e-bpi-x16}] 0]" >> flash.tcl
echo "current_hw_cfgmem -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM [current_hw_device]]" >> flash.tcl
echo "set_property PROGRAM.FILES [list \"$(PROJECT).mcs\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(PROJECT).prm\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.ERASE 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.CFG_PROGRAM 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.VERIFY 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.CHECKSUM 0 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.ADDRESS_RANGE {use_file} [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.BPI_RS_PINS {25:24} [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [current_hw_cfgmem]" >> flash.tcl
echo "create_hw_bitstream -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM_BITFILE [current_hw_device]]" >> flash.tcl
echo "program_hw_devices [current_hw_device]" >> flash.tcl
echo "refresh_hw_device [current_hw_device]" >> flash.tcl
echo "program_hw_cfgmem -hw_cfgmem [current_hw_cfgmem]" >> flash.tcl
echo "boot_hw_device [current_hw_device]" >> flash.tcl
echo "exit" >> flash.tcl
vivado -nojournal -nolog -mode batch -source flash.tcl

View File

@@ -0,0 +1,131 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025-2026 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
set params [dict create]
# collect build information
set build_date [clock seconds]
set git_hash 00000000
set git_tag ""
if { [catch {set git_hash [exec git rev-parse --short=8 HEAD]}] } {
puts "Error running git or project not under version control"
}
if { [catch {set git_tag [exec git describe --tags HEAD]}] } {
puts "Error running git, project not under version control, or no tag found"
}
puts "Build date: ${build_date}"
puts "Git hash: ${git_hash}"
puts "Git tag: ${git_tag}"
if { ! [regsub {^.*(\d+\.\d+\.\d+([\.-]\d+)?).*$} $git_tag {\1} tag_ver ] } {
puts "Failed to extract version from git tag"
set tag_ver 0.0.1
}
puts "Tag version: ${tag_ver}"
# FW and board IDs
set fpga_id [expr 0x3822093]
set fw_id [expr 0x0000C001]
set fw_ver $tag_ver
set board_vendor_id [expr 0x17df]
set board_device_id [expr 0x1a00]
set board_ver 1.0
set release_info [expr 0x00000000]
# PCIe IDs
set pcie_vendor_id [expr 0x1234]
set pcie_device_id [expr 0xC001]
set pcie_class_code [expr 0x020000]
set pcie_revision_id [expr 0x00]
set pcie_subsystem_device_id $board_device_id
set pcie_subsystem_vendor_id $board_vendor_id
# FW ID
dict set params FPGA_ID [format "32'h%08x" $fpga_id]
dict set params FW_ID [format "32'h%08x" $fw_id]
dict set params FW_VER [format "32'h%03x%02x%03x" {*}[split $fw_ver .-] 0 0 0]
dict set params BOARD_ID [format "32'h%04x%04x" $board_vendor_id $board_device_id]
dict set params BOARD_VER [format "32'h%03x%02x%03x" {*}[split $board_ver .-] 0 0 0]
dict set params BUILD_DATE "32'd${build_date}"
dict set params GIT_HASH "32'h${git_hash}"
dict set params RELEASE_INFO [format "32'h%08x" $release_info]
# PTP configuration
dict set params PTP_TS_EN "1"
# AXI lite interface configuration (control)
dict set params AXIL_CTRL_DATA_W "32"
dict set params AXIL_CTRL_ADDR_W "24"
# MAC configuration
dict set params CFG_LOW_LATENCY "1"
dict set params COMBINED_MAC_PCS "1"
dict set params MAC_DATA_W "32"
# PCIe IP core settings
set pcie [get_ips pcie3_ultrascale_0]
# configure BAR settings
proc configure_bar {pcie pf bar aperture} {
set size_list {Bytes Kilobytes Megabytes Gigabytes Terabytes Petabytes Exabytes}
for { set i 0 } { $i < [llength $size_list] } { incr i } {
set scale [lindex $size_list $i]
if {$aperture > 0 && $aperture < ($i+1)*10} {
set size [expr 1 << $aperture - ($i*10)]
puts "${pcie} PF${pf} BAR${bar}: aperture ${aperture} bits ($size $scale)"
set pcie_config [dict create]
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_enabled" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_type" {Memory}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_64bit" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_prefetchable" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_scale" $scale
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_size" $size
set_property -dict $pcie_config $pcie
return
}
}
puts "${pcie} PF${pf} BAR${bar}: disabled"
set_property "CONFIG.pf${pf}_bar${bar}_enabled" {false} $pcie
}
# Control BAR (BAR 0)
configure_bar $pcie 0 0 [dict get $params AXIL_CTRL_ADDR_W]
# PCIe IP core configuration
set pcie_config [dict create]
# PCIe IDs
dict set pcie_config "CONFIG.vendor_id" [format "%04x" $pcie_vendor_id]
dict set pcie_config "CONFIG.PF0_DEVICE_ID" [format "%04x" $pcie_device_id]
dict set pcie_config "CONFIG.PF0_CLASS_CODE" [format "%06x" $pcie_class_code]
dict set pcie_config "CONFIG.PF0_REVISION_ID" [format "%02x" $pcie_revision_id]
dict set pcie_config "CONFIG.PF0_SUBSYSTEM_VENDOR_ID" [format "%04x" $pcie_subsystem_vendor_id]
dict set pcie_config "CONFIG.PF0_SUBSYSTEM_ID" [format "%04x" $pcie_subsystem_device_id]
# MSI
dict set pcie_config "CONFIG.pf0_msi_enabled" {true}
set_property -dict $pcie_config $pcie
# apply parameters to top-level
set param_list {}
dict for {name value} $params {
lappend param_list $name=$value
}
set_property generic $param_list [get_filesets sources_1]

View File

@@ -0,0 +1,97 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
# FPGA settings
FPGA_PART = xcku060-ffva1156-2-e
FPGA_TOP = fpga
FPGA_ARCH = kintexu
RTL_DIR = ../rtl
LIB_DIR = ../lib
TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
# Files for synthesis
SYN_FILES = $(RTL_DIR)/fpga.sv
SYN_FILES += $(RTL_DIR)/fpga_core.sv
SYN_FILES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_micro_pcie_us.f
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_if_uart.f
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_switch.sv
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_apb.f
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_stats.f
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv
SYN_FILES += $(TAXI_SRC_DIR)/pyrite/rtl/pyrite_pcie_us_vsec_bpi.f
# XDC files
XDC_FILES = ../fpga.xdc
XDC_FILES += $(TAXI_SRC_DIR)/eth/syn/vivado/taxi_eth_mac_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/axis/syn/vivado/taxi_axis_async_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_leaf.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_phc_regs.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_rel2tod.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_reset.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_signal.tcl
# IP
IP_TCL_FILES += ../ip/pcie3_ultrascale_0.tcl
IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_phy_10g_us_gth_156.tcl
# Configuration
CONFIG_TCL_FILES = ./config.tcl
include ../common/vivado.mk
program: $(PROJECT).bit
echo "open_hw_manager" > program.tcl
echo "connect_hw_server" >> program.tcl
echo "open_hw_target" >> program.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> program.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> program.tcl
echo "set_property PROGRAM.FILE {$(PROJECT).bit} [current_hw_device]" >> program.tcl
echo "program_hw_devices [current_hw_device]" >> program.tcl
echo "exit" >> program.tcl
vivado -nojournal -nolog -mode batch -source program.tcl
$(PROJECT).mcs $(PROJECT).prm: $(PROJECT).bit
echo "write_cfgmem -force -format mcs -size 128 -interface BPIx16 -loadbit {up 0x0000000 $*.bit} -checksum -file $*.mcs" > generate_mcs.tcl
echo "exit" >> generate_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*$$x rev/$*_rev$$COUNT$$x; \
echo "Output: rev/$*_rev$$COUNT$$x"; done;
flash: $(PROJECT).mcs $(PROJECT).prm
echo "open_hw_manager" > flash.tcl
echo "connect_hw_server" >> flash.tcl
echo "open_hw_target" >> flash.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> flash.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> flash.tcl
echo "create_hw_cfgmem -hw_device [current_hw_device] [lindex [get_cfgmem_parts {mt28gu01gaax1e-bpi-x16}] 0]" >> flash.tcl
echo "current_hw_cfgmem -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM [current_hw_device]]" >> flash.tcl
echo "set_property PROGRAM.FILES [list \"$(PROJECT).mcs\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(PROJECT).prm\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.ERASE 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.CFG_PROGRAM 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.VERIFY 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.CHECKSUM 0 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.ADDRESS_RANGE {use_file} [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.BPI_RS_PINS {25:24} [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [current_hw_cfgmem]" >> flash.tcl
echo "create_hw_bitstream -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM_BITFILE [current_hw_device]]" >> flash.tcl
echo "program_hw_devices [current_hw_device]" >> flash.tcl
echo "refresh_hw_device [current_hw_device]" >> flash.tcl
echo "program_hw_cfgmem -hw_cfgmem [current_hw_cfgmem]" >> flash.tcl
echo "boot_hw_device [current_hw_device]" >> flash.tcl
echo "exit" >> flash.tcl
vivado -nojournal -nolog -mode batch -source flash.tcl

View File

@@ -0,0 +1,131 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025-2026 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
set params [dict create]
# collect build information
set build_date [clock seconds]
set git_hash 00000000
set git_tag ""
if { [catch {set git_hash [exec git rev-parse --short=8 HEAD]}] } {
puts "Error running git or project not under version control"
}
if { [catch {set git_tag [exec git describe --tags HEAD]}] } {
puts "Error running git, project not under version control, or no tag found"
}
puts "Build date: ${build_date}"
puts "Git hash: ${git_hash}"
puts "Git tag: ${git_tag}"
if { ! [regsub {^.*(\d+\.\d+\.\d+([\.-]\d+)?).*$} $git_tag {\1} tag_ver ] } {
puts "Failed to extract version from git tag"
set tag_ver 0.0.1
}
puts "Tag version: ${tag_ver}"
# FW and board IDs
set fpga_id [expr 0x3919093]
set fw_id [expr 0x0000C001]
set fw_ver $tag_ver
set board_vendor_id [expr 0x17df]
set board_device_id [expr 0x1a00]
set board_ver 1.0
set release_info [expr 0x00000000]
# PCIe IDs
set pcie_vendor_id [expr 0x1234]
set pcie_device_id [expr 0xC001]
set pcie_class_code [expr 0x020000]
set pcie_revision_id [expr 0x00]
set pcie_subsystem_device_id $board_device_id
set pcie_subsystem_vendor_id $board_vendor_id
# FW ID
dict set params FPGA_ID [format "32'h%08x" $fpga_id]
dict set params FW_ID [format "32'h%08x" $fw_id]
dict set params FW_VER [format "32'h%03x%02x%03x" {*}[split $fw_ver .-] 0 0 0]
dict set params BOARD_ID [format "32'h%04x%04x" $board_vendor_id $board_device_id]
dict set params BOARD_VER [format "32'h%03x%02x%03x" {*}[split $board_ver .-] 0 0 0]
dict set params BUILD_DATE "32'd${build_date}"
dict set params GIT_HASH "32'h${git_hash}"
dict set params RELEASE_INFO [format "32'h%08x" $release_info]
# PTP configuration
dict set params PTP_TS_EN "1"
# AXI lite interface configuration (control)
dict set params AXIL_CTRL_DATA_W "32"
dict set params AXIL_CTRL_ADDR_W "24"
# MAC configuration
dict set params CFG_LOW_LATENCY "1"
dict set params COMBINED_MAC_PCS "1"
dict set params MAC_DATA_W "32"
# PCIe IP core settings
set pcie [get_ips pcie3_ultrascale_0]
# configure BAR settings
proc configure_bar {pcie pf bar aperture} {
set size_list {Bytes Kilobytes Megabytes Gigabytes Terabytes Petabytes Exabytes}
for { set i 0 } { $i < [llength $size_list] } { incr i } {
set scale [lindex $size_list $i]
if {$aperture > 0 && $aperture < ($i+1)*10} {
set size [expr 1 << $aperture - ($i*10)]
puts "${pcie} PF${pf} BAR${bar}: aperture ${aperture} bits ($size $scale)"
set pcie_config [dict create]
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_enabled" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_type" {Memory}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_64bit" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_prefetchable" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_scale" $scale
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_size" $size
set_property -dict $pcie_config $pcie
return
}
}
puts "${pcie} PF${pf} BAR${bar}: disabled"
set_property "CONFIG.pf${pf}_bar${bar}_enabled" {false} $pcie
}
# Control BAR (BAR 0)
configure_bar $pcie 0 0 [dict get $params AXIL_CTRL_ADDR_W]
# PCIe IP core configuration
set pcie_config [dict create]
# PCIe IDs
dict set pcie_config "CONFIG.vendor_id" [format "%04x" $pcie_vendor_id]
dict set pcie_config "CONFIG.PF0_DEVICE_ID" [format "%04x" $pcie_device_id]
dict set pcie_config "CONFIG.PF0_CLASS_CODE" [format "%06x" $pcie_class_code]
dict set pcie_config "CONFIG.PF0_REVISION_ID" [format "%02x" $pcie_revision_id]
dict set pcie_config "CONFIG.PF0_SUBSYSTEM_VENDOR_ID" [format "%04x" $pcie_subsystem_vendor_id]
dict set pcie_config "CONFIG.PF0_SUBSYSTEM_ID" [format "%04x" $pcie_subsystem_device_id]
# MSI
dict set pcie_config "CONFIG.pf0_msi_enabled" {true}
set_property -dict $pcie_config $pcie
# apply parameters to top-level
set param_list {}
dict for {name value} $params {
lappend param_list $name=$value
}
set_property generic $param_list [get_filesets sources_1]

View File

@@ -0,0 +1,29 @@
create_ip -name pcie3_ultrascale -vendor xilinx.com -library ip -module_name pcie3_ultrascale_0
set_property -dict [list \
CONFIG.PL_LINK_CAP_MAX_LINK_SPEED {8.0_GT/s} \
CONFIG.PL_LINK_CAP_MAX_LINK_WIDTH {X8} \
CONFIG.AXISTEN_IF_RC_STRADDLE {false} \
CONFIG.axisten_if_width {256_bit} \
CONFIG.extended_tag_field {true} \
CONFIG.pf0_dev_cap_max_payload {1024_bytes} \
CONFIG.axisten_freq {250} \
CONFIG.PF0_Use_Class_Code_Lookup_Assistant {false} \
CONFIG.pf0_class_code_base {02} \
CONFIG.pf0_class_code_sub {00} \
CONFIG.pf0_class_code_interface {00} \
CONFIG.PF0_DEVICE_ID {C001} \
CONFIG.PF0_SUBSYSTEM_ID {1a00} \
CONFIG.PF0_SUBSYSTEM_VENDOR_ID {17df} \
CONFIG.pf0_bar0_64bit {true} \
CONFIG.pf0_bar0_prefetchable {true} \
CONFIG.pf0_bar0_scale {Megabytes} \
CONFIG.pf0_bar0_size {16} \
CONFIG.pf0_msi_enabled {true} \
CONFIG.PF0_MSI_CAP_MULTIMSGCAP {32_vectors} \
CONFIG.en_msi_per_vec_masking {true} \
CONFIG.ext_pcie_cfg_space_enabled {true} \
CONFIG.vendor_id {1234} \
CONFIG.mode_selection {Advanced} \
] [get_ips pcie3_ultrascale_0]

View File

@@ -0,0 +1 @@
../../../../../../

View File

@@ -0,0 +1,936 @@
// SPDX-License-Identifier: MIT
/*
Copyright (c) 2014-2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA top-level module
*/
module fpga #
(
// simulation (set to avoid vendor primitives)
parameter logic SIM = 1'b0,
// vendor ("GENERIC", "XILINX", "ALTERA")
parameter string VENDOR = "XILINX",
// device family
parameter string FAMILY = "kintexu",
// FW ID
parameter FPGA_ID = 32'h3822093,
parameter FW_ID = 32'h0000C001,
parameter FW_VER = 32'h000_01_000,
parameter BOARD_ID = 32'h17df_1a00,
parameter BOARD_VER = 32'h001_00_000,
parameter BUILD_DATE = 32'd602976000,
parameter GIT_HASH = 32'h5f87c2e8,
parameter RELEASE_INFO = 32'h00000000,
// PTP configuration
parameter logic PTP_TS_EN = 1'b1,
// AXI lite interface configuration (control)
parameter AXIL_CTRL_DATA_W = 32,
parameter AXIL_CTRL_ADDR_W = 24,
// MAC configuration
parameter logic CFG_LOW_LATENCY = 1'b1,
parameter logic COMBINED_MAC_PCS = 1'b1,
parameter MAC_DATA_W = 64
)
(
/*
* Clock: 200 MHz LVDS
*/
input wire logic clk_ddr4_p,
input wire logic clk_ddr4_n,
/*
* GPIO
*/
output wire logic [7:0] user_led,
output wire logic qsfp0_led_green,
output wire logic qsfp0_led_red,
output wire logic qsfp1_led_green,
output wire logic qsfp1_led_red,
/*
* UART: 500000 bps, 8N1
*/
input wire logic uart_rxd,
output wire logic uart_txd,
/*
* Ethernet: QSFP28
*/
input wire logic qsfp0_rx_p[4],
input wire logic qsfp0_rx_n[4],
output wire logic qsfp0_tx_p[4],
output wire logic qsfp0_tx_n[4],
input wire logic qsfp0_mgt_refclk_p,
input wire logic qsfp0_mgt_refclk_n,
output wire logic [1:0] qsfp0_fs,
output wire logic qsfp0_modsell,
output wire logic qsfp0_resetl,
input wire logic qsfp0_modprsl,
input wire logic qsfp0_intl,
output wire logic qsfp0_lpmode,
// inout wire logic qsfp0_i2c_scl,
// inout wire logic qsfp0_i2c_sda,
input wire logic qsfp1_rx_p[4],
input wire logic qsfp1_rx_n[4],
output wire logic qsfp1_tx_p[4],
output wire logic qsfp1_tx_n[4],
// input wire logic qsfp1_mgt_refclk_p,
// input wire logic qsfp1_mgt_refclk_n,
output wire logic [1:0] qsfp1_fs,
output wire logic qsfp1_modsell,
output wire logic qsfp1_resetl,
input wire logic qsfp1_modprsl,
input wire logic qsfp1_intl,
output wire logic qsfp1_lpmode,
// inout wire logic qsfp1_i2c_scl,
// inout wire logic qsfp1_i2c_sda,
/*
* PCIe
*/
input wire logic [7:0] pcie_rx_p,
input wire logic [7:0] pcie_rx_n,
output wire logic [7:0] pcie_tx_p,
output wire logic [7:0] pcie_tx_n,
input wire logic pcie_refclk_p,
input wire logic pcie_refclk_n,
input wire logic pcie_reset_n,
/*
* BPI Flash
*/
inout wire logic [15:4] flash_dq,
output wire logic [23:0] flash_addr,
output wire logic [1:0] flash_region,
output wire logic flash_oe_n,
output wire logic flash_we_n,
output wire logic flash_adv_n,
input wire logic flash_wait
);
// Clock and reset
wire pcie_user_clk;
wire pcie_user_rst;
wire clk_ddr4_ibufg;
// Internal 125 MHz clock
wire clk_125mhz_mmcm_out;
wire clk_125mhz_int;
wire rst_125mhz_int;
wire mmcm_rst = pcie_user_rst;
wire mmcm_locked;
wire mmcm_clkfb;
IBUFGDS #(
.DIFF_TERM("FALSE"),
.IBUF_LOW_PWR("FALSE")
)
clk_ddr4_ibufg_inst (
.O (clk_ddr4_ibufg),
.I (clk_ddr4_p),
.IB (clk_ddr4_n)
);
// MMCM instance
MMCME3_BASE #(
// 200 MHz input
.CLKIN1_PERIOD(8.0),
.REF_JITTER1(0.010),
// 200 MHz input / 1 = 200 MHz PFD (range 10 MHz to 500 MHz)
.DIVCLK_DIVIDE(1),
// 200 MHz PFD * 5 = 1000 MHz VCO (range 600 MHz to 1440 MHz)
.CLKFBOUT_MULT_F(5),
.CLKFBOUT_PHASE(0),
// 1000 MHz / 8 = 125 MHz, 0 degrees
.CLKOUT0_DIVIDE_F(8),
.CLKOUT0_DUTY_CYCLE(0.5),
.CLKOUT0_PHASE(0),
// Not used
.CLKOUT1_DIVIDE(1),
.CLKOUT1_DUTY_CYCLE(0.5),
.CLKOUT1_PHASE(0),
// Not used
.CLKOUT2_DIVIDE(1),
.CLKOUT2_DUTY_CYCLE(0.5),
.CLKOUT2_PHASE(0),
// Not used
.CLKOUT3_DIVIDE(1),
.CLKOUT3_DUTY_CYCLE(0.5),
.CLKOUT3_PHASE(0),
// Not used
.CLKOUT4_DIVIDE(1),
.CLKOUT4_DUTY_CYCLE(0.5),
.CLKOUT4_PHASE(0),
.CLKOUT4_CASCADE("FALSE"),
// Not used
.CLKOUT5_DIVIDE(1),
.CLKOUT5_DUTY_CYCLE(0.5),
.CLKOUT5_PHASE(0),
// Not used
.CLKOUT6_DIVIDE(1),
.CLKOUT6_DUTY_CYCLE(0.5),
.CLKOUT6_PHASE(0),
// optimized bandwidth
.BANDWIDTH("OPTIMIZED"),
// don't wait for lock during startup
.STARTUP_WAIT("FALSE")
)
clk_mmcm_inst (
// 200 MHz input
.CLKIN1(clk_ddr4_ibufg),
// direct clkfb feeback
.CLKFBIN(mmcm_clkfb),
.CLKFBOUT(mmcm_clkfb),
.CLKFBOUTB(),
// 125 MHz, 0 degrees
.CLKOUT0(clk_125mhz_mmcm_out),
.CLKOUT0B(),
// Not used
.CLKOUT1(),
.CLKOUT1B(),
// Not used
.CLKOUT2(),
.CLKOUT2B(),
// Not used
.CLKOUT3(),
.CLKOUT3B(),
// Not used
.CLKOUT4(),
// Not used
.CLKOUT5(),
// Not used
.CLKOUT6(),
// reset input
.RST(mmcm_rst),
// don't power down
.PWRDWN(1'b0),
// locked output
.LOCKED(mmcm_locked)
);
BUFG
clk_125mhz_bufg_inst (
.I(clk_125mhz_mmcm_out),
.O(clk_125mhz_int)
);
taxi_sync_reset #(
.N(4)
)
sync_reset_125mhz_inst (
.clk(clk_125mhz_int),
.rst(~mmcm_locked),
.out(rst_125mhz_int)
);
wire uart_rxd_int;
taxi_sync_signal #(
.WIDTH(1),
.N(2)
)
sync_signal_inst (
.clk(clk_125mhz_int),
.in({uart_rxd}),
.out({uart_rxd_int})
);
// Flash
wire [3:0] flash_dq_int;
wire [15:0] flash_dq_i_int;
wire [15:0] flash_dq_o_int;
wire flash_dq_oe_int;
wire [23:0] flash_addr_int;
wire [1:0] flash_region_int;
wire flash_region_oe_int;
wire flash_ce_n_int;
wire flash_oe_n_int;
wire flash_we_n_int;
wire flash_adv_n_int;
logic [15:0] flash_dq_o_reg;
logic flash_dq_oe_reg;
logic [23:0] flash_addr_reg;
logic [1:0] flash_region_reg;
logic flash_region_oe_reg;
logic flash_ce_n_reg;
logic flash_oe_n_reg;
logic flash_we_n_reg;
logic flash_adv_n_reg;
always_ff @(posedge pcie_user_clk) begin
flash_dq_o_reg <= flash_dq_o_int;
flash_dq_oe_reg <= flash_dq_oe_int;
flash_addr_reg <= flash_addr_int;
flash_region_reg <= flash_region_int;
flash_region_oe_reg <= flash_region_oe_int;
flash_ce_n_reg <= flash_ce_n_int;
flash_oe_n_reg <= flash_oe_n_int;
flash_we_n_reg <= flash_we_n_int;
flash_adv_n_reg <= flash_adv_n_int;
end
assign flash_dq[15:4] = flash_dq_oe_reg ? flash_dq_o_reg[15:4] : 12'hzzz;
assign flash_addr = flash_addr_reg;
assign flash_region = flash_region_oe_reg ? flash_region_reg : 2'bz;
assign flash_oe_n = flash_oe_n_reg;
assign flash_we_n = flash_we_n_reg;
assign flash_adv_n = flash_adv_n_reg;
taxi_sync_signal #(
.WIDTH(16),
.N(2)
)
flash_sync_signal_inst (
.clk(pcie_user_clk),
.in({flash_dq, flash_dq_int}),
.out(flash_dq_i_int)
);
STARTUPE3
startupe3_inst (
.CFGCLK(),
.CFGMCLK(),
.DI(flash_dq_int),
.DO(flash_dq_o_reg[3:0]),
.DTS({4{~flash_dq_oe_reg}}),
.EOS(),
.FCSBO(flash_ce_n_reg),
.FCSBTS(1'b0),
.GSR(1'b0),
.GTS(1'b0),
.KEYCLEARB(1'b1),
.PACK(1'b0),
.PREQ(),
.USRCCLKO(1'b0),
.USRCCLKTS(1'b1),
.USRDONEO(1'b0),
.USRDONETS(1'b1)
);
// FPGA boot
wire fpga_boot;
wire fpga_boot_sync;
taxi_sync_signal #(
.WIDTH(1),
.N(2)
)
fpga_boot_sync_inst (
.clk(clk_125mhz_int),
.in({fpga_boot}),
.out({fpga_boot_sync})
);
wire icap_avail;
logic [2:0] icap_state_reg = 0;
logic icap_csib_reg = 1'b1;
logic icap_rdwrb_reg = 1'b0;
logic [31:0] icap_di_reg = 32'hffffffff;
wire [31:0] icap_di_rev;
assign icap_di_rev[ 7] = icap_di_reg[ 0];
assign icap_di_rev[ 6] = icap_di_reg[ 1];
assign icap_di_rev[ 5] = icap_di_reg[ 2];
assign icap_di_rev[ 4] = icap_di_reg[ 3];
assign icap_di_rev[ 3] = icap_di_reg[ 4];
assign icap_di_rev[ 2] = icap_di_reg[ 5];
assign icap_di_rev[ 1] = icap_di_reg[ 6];
assign icap_di_rev[ 0] = icap_di_reg[ 7];
assign icap_di_rev[15] = icap_di_reg[ 8];
assign icap_di_rev[14] = icap_di_reg[ 9];
assign icap_di_rev[13] = icap_di_reg[10];
assign icap_di_rev[12] = icap_di_reg[11];
assign icap_di_rev[11] = icap_di_reg[12];
assign icap_di_rev[10] = icap_di_reg[13];
assign icap_di_rev[ 9] = icap_di_reg[14];
assign icap_di_rev[ 8] = icap_di_reg[15];
assign icap_di_rev[23] = icap_di_reg[16];
assign icap_di_rev[22] = icap_di_reg[17];
assign icap_di_rev[21] = icap_di_reg[18];
assign icap_di_rev[20] = icap_di_reg[19];
assign icap_di_rev[19] = icap_di_reg[20];
assign icap_di_rev[18] = icap_di_reg[21];
assign icap_di_rev[17] = icap_di_reg[22];
assign icap_di_rev[16] = icap_di_reg[23];
assign icap_di_rev[31] = icap_di_reg[24];
assign icap_di_rev[30] = icap_di_reg[25];
assign icap_di_rev[29] = icap_di_reg[26];
assign icap_di_rev[28] = icap_di_reg[27];
assign icap_di_rev[27] = icap_di_reg[28];
assign icap_di_rev[26] = icap_di_reg[29];
assign icap_di_rev[25] = icap_di_reg[30];
assign icap_di_rev[24] = icap_di_reg[31];
always_ff @(posedge clk_125mhz_int) begin
case (icap_state_reg)
0: begin
icap_state_reg <= 0;
icap_csib_reg <= 1'b1;
icap_rdwrb_reg <= 1'b0;
icap_di_reg <= 32'hffffffff; // dummy word
if (fpga_boot_sync && icap_avail) begin
icap_state_reg <= 1;
icap_csib_reg <= 1'b0;
icap_rdwrb_reg <= 1'b0;
icap_di_reg <= 32'hffffffff; // dummy word
end
end
1: begin
icap_state_reg <= 2;
icap_csib_reg <= 1'b0;
icap_rdwrb_reg <= 1'b0;
icap_di_reg <= 32'hAA995566; // sync word
end
2: begin
icap_state_reg <= 3;
icap_csib_reg <= 1'b0;
icap_rdwrb_reg <= 1'b0;
icap_di_reg <= 32'h20000000; // type 1 noop
end
3: begin
icap_state_reg <= 4;
icap_csib_reg <= 1'b0;
icap_rdwrb_reg <= 1'b0;
icap_di_reg <= 32'h30008001; // write 1 word to CMD
end
4: begin
icap_state_reg <= 5;
icap_csib_reg <= 1'b0;
icap_rdwrb_reg <= 1'b0;
icap_di_reg <= 32'h0000000F; // IPROG
end
5: begin
icap_state_reg <= 0;
icap_csib_reg <= 1'b0;
icap_rdwrb_reg <= 1'b0;
icap_di_reg <= 32'h20000000; // type 1 noop
end
endcase
end
ICAPE3
icape3_inst (
.AVAIL(icap_avail),
.CLK(clk_125mhz_int),
.CSIB(icap_csib_reg),
.I(icap_di_rev),
.O(),
.PRDONE(),
.PRERROR(),
.RDWRB(icap_rdwrb_reg)
);
// PCIe
localparam AXIS_PCIE_DATA_W = 256;
localparam AXIS_PCIE_KEEP_W = (AXIS_PCIE_DATA_W/32);
localparam AXIS_PCIE_RC_USER_W = 75;
localparam AXIS_PCIE_RQ_USER_W = 60;
localparam AXIS_PCIE_CQ_USER_W = 85;
localparam AXIS_PCIE_CC_USER_W = 33;
localparam RC_STRADDLE = 1'b0; // AXIS_PCIE_DATA_W >= 256;
localparam RQ_SEQ_NUM_W = AXIS_PCIE_RQ_USER_W == 60 ? 4 : 6;
localparam RQ_SEQ_NUM_EN = 1;
localparam PCIE_TAG_CNT = AXIS_PCIE_RQ_USER_W == 60 ? 64 : 256;
localparam BAR0_APERTURE = 24;
taxi_axis_if #(
.DATA_W(AXIS_PCIE_DATA_W),
.KEEP_EN(1),
.KEEP_W(AXIS_PCIE_KEEP_W),
.USER_EN(1),
.USER_W(AXIS_PCIE_CQ_USER_W)
) axis_pcie_cq();
taxi_axis_if #(
.DATA_W(AXIS_PCIE_DATA_W),
.KEEP_EN(1),
.KEEP_W(AXIS_PCIE_KEEP_W),
.USER_EN(1),
.USER_W(AXIS_PCIE_CC_USER_W)
) axis_pcie_cc();
taxi_axis_if #(
.DATA_W(AXIS_PCIE_DATA_W),
.KEEP_EN(1),
.KEEP_W(AXIS_PCIE_KEEP_W),
.USER_EN(1),
.USER_W(AXIS_PCIE_RQ_USER_W)
) axis_pcie_rq();
taxi_axis_if #(
.DATA_W(AXIS_PCIE_DATA_W),
.KEEP_EN(1),
.KEEP_W(AXIS_PCIE_KEEP_W),
.USER_EN(1),
.USER_W(AXIS_PCIE_RC_USER_W)
) axis_pcie_rc();
wire [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num;
wire pcie_rq_seq_num_vld;
wire [2:0] cfg_max_payload;
wire [2:0] cfg_max_read_req;
wire [3:0] cfg_rcb_status;
wire [18:0] cfg_mgmt_addr;
wire cfg_mgmt_write;
wire [31:0] cfg_mgmt_write_data;
wire [3:0] cfg_mgmt_byte_enable;
wire cfg_mgmt_read;
wire [31:0] cfg_mgmt_read_data;
wire cfg_mgmt_read_write_done;
wire [7:0] cfg_fc_ph;
wire [11:0] cfg_fc_pd;
wire [7:0] cfg_fc_nph;
wire [11:0] cfg_fc_npd;
wire [7:0] cfg_fc_cplh;
wire [11:0] cfg_fc_cpld;
wire [2:0] cfg_fc_sel;
wire cfg_ext_read_received;
wire cfg_ext_write_received;
wire [9:0] cfg_ext_register_number;
wire [7:0] cfg_ext_function_number;
wire [31:0] cfg_ext_write_data;
wire [3:0] cfg_ext_write_byte_enable;
wire [31:0] cfg_ext_read_data;
wire cfg_ext_read_data_valid;
// wire [3:0] cfg_interrupt_msix_enable;
// wire [3:0] cfg_interrupt_msix_mask;
// wire [251:0] cfg_interrupt_msix_vf_enable;
// wire [251:0] cfg_interrupt_msix_vf_mask;
// wire [63:0] cfg_interrupt_msix_address;
// wire [31:0] cfg_interrupt_msix_data;
// wire cfg_interrupt_msix_int;
// wire [1:0] cfg_interrupt_msix_vec_pending;
// wire cfg_interrupt_msix_vec_pending_status;
// wire cfg_interrupt_msix_sent;
// wire cfg_interrupt_msix_fail;
// wire [7:0] cfg_interrupt_msi_function_number;
wire [3:0] cfg_interrupt_msi_enable;
wire [11:0] cfg_interrupt_msi_mmenable;
wire cfg_interrupt_msi_mask_update;
wire [31:0] cfg_interrupt_msi_data;
wire [3:0] cfg_interrupt_msi_select;
wire [31:0] cfg_interrupt_msi_int;
wire [31:0] cfg_interrupt_msi_pending_status;
wire cfg_interrupt_msi_pending_status_data_enable;
wire [3:0] cfg_interrupt_msi_pending_status_function_num;
wire cfg_interrupt_msi_sent;
wire cfg_interrupt_msi_fail;
wire [2:0] cfg_interrupt_msi_attr;
wire cfg_interrupt_msi_tph_present;
wire [1:0] cfg_interrupt_msi_tph_type;
wire [8:0] cfg_interrupt_msi_tph_st_tag;
wire [3:0] cfg_interrupt_msi_function_number;
wire stat_err_cor = 1'b0;
wire stat_err_uncor = 1'b0;
wire pcie_sys_clk;
wire pcie_sys_clk_gt;
IBUFDS_GTE3 #(
.REFCLK_HROW_CK_SEL(2'b00)
)
ibufds_gte3_pcie_refclk_inst (
.I (pcie_refclk_p),
.IB (pcie_refclk_n),
.CEB (1'b0),
.O (pcie_sys_clk_gt),
.ODIV2 (pcie_sys_clk)
);
pcie3_ultrascale_0
pcie3_ultrascale_inst (
.pci_exp_txn(pcie_tx_n),
.pci_exp_txp(pcie_tx_p),
.pci_exp_rxn(pcie_rx_n),
.pci_exp_rxp(pcie_rx_p),
.user_clk(pcie_user_clk),
.user_reset(pcie_user_rst),
.user_lnk_up(),
.s_axis_rq_tdata(axis_pcie_rq.tdata),
.s_axis_rq_tkeep(axis_pcie_rq.tkeep),
.s_axis_rq_tlast(axis_pcie_rq.tlast),
.s_axis_rq_tready(axis_pcie_rq.tready),
.s_axis_rq_tuser(axis_pcie_rq.tuser),
.s_axis_rq_tvalid(axis_pcie_rq.tvalid),
.m_axis_rc_tdata(axis_pcie_rc.tdata),
.m_axis_rc_tkeep(axis_pcie_rc.tkeep),
.m_axis_rc_tlast(axis_pcie_rc.tlast),
.m_axis_rc_tready(axis_pcie_rc.tready),
.m_axis_rc_tuser(axis_pcie_rc.tuser),
.m_axis_rc_tvalid(axis_pcie_rc.tvalid),
.m_axis_cq_tdata(axis_pcie_cq.tdata),
.m_axis_cq_tkeep(axis_pcie_cq.tkeep),
.m_axis_cq_tlast(axis_pcie_cq.tlast),
.m_axis_cq_tready(axis_pcie_cq.tready),
.m_axis_cq_tuser(axis_pcie_cq.tuser),
.m_axis_cq_tvalid(axis_pcie_cq.tvalid),
.s_axis_cc_tdata(axis_pcie_cc.tdata),
.s_axis_cc_tkeep(axis_pcie_cc.tkeep),
.s_axis_cc_tlast(axis_pcie_cc.tlast),
.s_axis_cc_tready(axis_pcie_cc.tready),
.s_axis_cc_tuser(axis_pcie_cc.tuser),
.s_axis_cc_tvalid(axis_pcie_cc.tvalid),
.pcie_rq_seq_num(pcie_rq_seq_num),
.pcie_rq_seq_num_vld(pcie_rq_seq_num_vld),
.pcie_rq_tag(),
.pcie_rq_tag_av(),
.pcie_rq_tag_vld(),
.pcie_tfc_nph_av(),
.pcie_tfc_npd_av(),
.pcie_cq_np_req(1'b1),
.pcie_cq_np_req_count(),
.cfg_phy_link_down(),
.cfg_phy_link_status(),
.cfg_negotiated_width(),
.cfg_current_speed(),
.cfg_max_payload(cfg_max_payload),
.cfg_max_read_req(cfg_max_read_req),
.cfg_function_status(),
.cfg_function_power_state(),
.cfg_vf_status(),
.cfg_vf_power_state(),
.cfg_link_power_state(),
.cfg_mgmt_addr(cfg_mgmt_addr),
.cfg_mgmt_write(cfg_mgmt_write),
.cfg_mgmt_write_data(cfg_mgmt_write_data),
.cfg_mgmt_byte_enable(cfg_mgmt_byte_enable),
.cfg_mgmt_read(cfg_mgmt_read),
.cfg_mgmt_read_data(cfg_mgmt_read_data),
.cfg_mgmt_read_write_done(cfg_mgmt_read_write_done),
.cfg_mgmt_type1_cfg_reg_access(1'b0),
.cfg_err_cor_out(),
.cfg_err_nonfatal_out(),
.cfg_err_fatal_out(),
.cfg_local_error(),
.cfg_ltr_enable(),
.cfg_ltssm_state(),
.cfg_rcb_status(cfg_rcb_status),
.cfg_dpa_substate_change(),
.cfg_obff_enable(),
.cfg_pl_status_change(),
.cfg_tph_requester_enable(),
.cfg_tph_st_mode(),
.cfg_vf_tph_requester_enable(),
.cfg_vf_tph_st_mode(),
.cfg_msg_received(),
.cfg_msg_received_data(),
.cfg_msg_received_type(),
.cfg_msg_transmit(1'b0),
.cfg_msg_transmit_type(3'd0),
.cfg_msg_transmit_data(32'd0),
.cfg_msg_transmit_done(),
.cfg_fc_ph(cfg_fc_ph),
.cfg_fc_pd(cfg_fc_pd),
.cfg_fc_nph(cfg_fc_nph),
.cfg_fc_npd(cfg_fc_npd),
.cfg_fc_cplh(cfg_fc_cplh),
.cfg_fc_cpld(cfg_fc_cpld),
.cfg_fc_sel(cfg_fc_sel),
.cfg_per_func_status_control(3'd0),
.cfg_per_func_status_data(),
.cfg_per_function_number(4'd0),
.cfg_per_function_output_request(1'b0),
.cfg_per_function_update_done(),
.cfg_dsn(64'd0),
.cfg_power_state_change_ack(1'b1),
.cfg_power_state_change_interrupt(),
.cfg_err_cor_in(stat_err_cor),
.cfg_err_uncor_in(stat_err_uncor),
.cfg_flr_in_process(),
.cfg_flr_done(4'd0),
.cfg_vf_flr_in_process(),
.cfg_vf_flr_done(8'd0),
.cfg_link_training_enable(1'b1),
.cfg_ext_read_received(cfg_ext_read_received),
.cfg_ext_write_received(cfg_ext_write_received),
.cfg_ext_register_number(cfg_ext_register_number),
.cfg_ext_function_number(cfg_ext_function_number),
.cfg_ext_write_data(cfg_ext_write_data),
.cfg_ext_write_byte_enable(cfg_ext_write_byte_enable),
.cfg_ext_read_data(cfg_ext_read_data),
.cfg_ext_read_data_valid(cfg_ext_read_data_valid),
.cfg_interrupt_int(4'd0),
.cfg_interrupt_pending(4'd0),
.cfg_interrupt_sent(),
// .cfg_interrupt_msix_enable(cfg_interrupt_msix_enable),
// .cfg_interrupt_msix_mask(cfg_interrupt_msix_mask),
// .cfg_interrupt_msix_vf_enable(cfg_interrupt_msix_vf_enable),
// .cfg_interrupt_msix_vf_mask(cfg_interrupt_msix_vf_mask),
// .cfg_interrupt_msix_address(cfg_interrupt_msix_address),
// .cfg_interrupt_msix_data(cfg_interrupt_msix_data),
// .cfg_interrupt_msix_int(cfg_interrupt_msix_int),
// .cfg_interrupt_msix_vec_pending(cfg_interrupt_msix_vec_pending),
// .cfg_interrupt_msix_vec_pending_status(cfg_interrupt_msix_vec_pending_status),
// .cfg_interrupt_msi_sent(cfg_interrupt_msix_sent),
// .cfg_interrupt_msi_fail(cfg_interrupt_msix_fail),
// .cfg_interrupt_msi_function_number(cfg_interrupt_msi_function_number),
.cfg_interrupt_msi_enable(cfg_interrupt_msi_enable),
.cfg_interrupt_msi_vf_enable(),
.cfg_interrupt_msi_mmenable(cfg_interrupt_msi_mmenable),
.cfg_interrupt_msi_mask_update(cfg_interrupt_msi_mask_update),
.cfg_interrupt_msi_data(cfg_interrupt_msi_data),
.cfg_interrupt_msi_select(cfg_interrupt_msi_select),
.cfg_interrupt_msi_int(cfg_interrupt_msi_int),
.cfg_interrupt_msi_pending_status(cfg_interrupt_msi_pending_status),
.cfg_interrupt_msi_pending_status_data_enable(cfg_interrupt_msi_pending_status_data_enable),
.cfg_interrupt_msi_pending_status_function_num(cfg_interrupt_msi_pending_status_function_num),
.cfg_interrupt_msi_sent(cfg_interrupt_msi_sent),
.cfg_interrupt_msi_fail(cfg_interrupt_msi_fail),
.cfg_interrupt_msi_attr(cfg_interrupt_msi_attr),
.cfg_interrupt_msi_tph_present(cfg_interrupt_msi_tph_present),
.cfg_interrupt_msi_tph_type(cfg_interrupt_msi_tph_type),
.cfg_interrupt_msi_tph_st_tag(cfg_interrupt_msi_tph_st_tag),
.cfg_interrupt_msi_function_number(cfg_interrupt_msi_function_number),
.cfg_hot_reset_out(),
.cfg_config_space_enable(1'b1),
.cfg_req_pm_transition_l23_ready(1'b0),
.cfg_hot_reset_in(1'b0),
.cfg_ds_port_number(8'd0),
.cfg_ds_bus_number(8'd0),
.cfg_ds_device_number(5'd0),
.cfg_ds_function_number(3'd0),
.cfg_subsys_vend_id(BOARD_ID >> 16),
.sys_clk(pcie_sys_clk),
.sys_clk_gt(pcie_sys_clk_gt),
.sys_reset(pcie_reset_n),
.pcie_perstn1_in(1'b0),
.pcie_perstn0_out(),
.pcie_perstn1_out(),
.int_qpll1lock_out(),
.int_qpll1outrefclk_out(),
.int_qpll1outclk_out(),
.phy_rdy_out()
);
fpga_core #(
.SIM(SIM),
.VENDOR(VENDOR),
.FAMILY(FAMILY),
// FW ID
.FPGA_ID(FPGA_ID),
.FW_ID(FW_ID),
.FW_VER(FW_VER),
.BOARD_ID(BOARD_ID),
.BOARD_VER(BOARD_VER),
.BUILD_DATE(BUILD_DATE),
.GIT_HASH(GIT_HASH),
.RELEASE_INFO(RELEASE_INFO),
// PTP configuration
.PTP_TS_EN(PTP_TS_EN),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),
// AXI lite interface configuration (control)
.AXIL_CTRL_DATA_W(AXIL_CTRL_DATA_W),
.AXIL_CTRL_ADDR_W(AXIL_CTRL_ADDR_W),
// MAC configuration
.CFG_LOW_LATENCY(CFG_LOW_LATENCY),
.COMBINED_MAC_PCS(COMBINED_MAC_PCS),
.MAC_DATA_W(MAC_DATA_W)
)
core_inst (
/*
* Clock: 125MHz
* Synchronous reset
*/
.clk_125mhz(clk_125mhz_int),
.rst_125mhz(rst_125mhz_int),
/*
* GPIO
*/
.user_led(user_led),
.qsfp0_led_green(qsfp0_led_green),
.qsfp0_led_red(qsfp0_led_red),
.qsfp1_led_green(qsfp1_led_green),
.qsfp1_led_red(qsfp1_led_red),
/*
* UART: 115200 bps, 8N1
*/
.uart_rxd(uart_rxd_int),
.uart_txd(uart_txd),
/*
* Ethernet: QSFP+
*/
.qsfp0_rx_p(qsfp0_rx_p),
.qsfp0_rx_n(qsfp0_rx_n),
.qsfp0_tx_p(qsfp0_tx_p),
.qsfp0_tx_n(qsfp0_tx_n),
.qsfp0_mgt_refclk_p(qsfp0_mgt_refclk_p),
.qsfp0_mgt_refclk_n(qsfp0_mgt_refclk_n),
.qsfp0_fs(qsfp0_fs),
.qsfp0_modsell(qsfp0_modsell),
.qsfp0_resetl(qsfp0_resetl),
.qsfp0_modprsl(qsfp0_modprsl),
.qsfp0_intl(qsfp0_intl),
.qsfp0_lpmode(qsfp0_lpmode),
.qsfp1_rx_p(qsfp1_rx_p),
.qsfp1_rx_n(qsfp1_rx_n),
.qsfp1_tx_p(qsfp1_tx_p),
.qsfp1_tx_n(qsfp1_tx_n),
// .qsfp1_mgt_refclk_p(qsfp1_mgt_refclk_p),
// .qsfp1_mgt_refclk_n(qsfp1_mgt_refclk_n),
.qsfp1_fs(qsfp1_fs),
.qsfp1_modsell(qsfp1_modsell),
.qsfp1_resetl(qsfp1_resetl),
.qsfp1_modprsl(qsfp1_modprsl),
.qsfp1_intl(qsfp1_intl),
.qsfp1_lpmode(qsfp1_lpmode),
/*
* PCIe
*/
.pcie_clk(pcie_user_clk),
.pcie_rst(pcie_user_rst),
.s_axis_pcie_cq(axis_pcie_cq),
.m_axis_pcie_cc(axis_pcie_cc),
.m_axis_pcie_rq(axis_pcie_rq),
.s_axis_pcie_rc(axis_pcie_rc),
.pcie_rq_seq_num(pcie_rq_seq_num),
.pcie_rq_seq_num_vld(pcie_rq_seq_num_vld),
.cfg_max_payload(cfg_max_payload),
.cfg_max_read_req(cfg_max_read_req),
.cfg_rcb_status(cfg_rcb_status),
.cfg_mgmt_addr(cfg_mgmt_addr),
.cfg_mgmt_write(cfg_mgmt_write),
.cfg_mgmt_write_data(cfg_mgmt_write_data),
.cfg_mgmt_byte_enable(cfg_mgmt_byte_enable),
.cfg_mgmt_read(cfg_mgmt_read),
.cfg_mgmt_read_data(cfg_mgmt_read_data),
.cfg_mgmt_read_write_done(cfg_mgmt_read_write_done),
.cfg_fc_ph(cfg_fc_ph),
.cfg_fc_pd(cfg_fc_pd),
.cfg_fc_nph(cfg_fc_nph),
.cfg_fc_npd(cfg_fc_npd),
.cfg_fc_cplh(cfg_fc_cplh),
.cfg_fc_cpld(cfg_fc_cpld),
.cfg_fc_sel(cfg_fc_sel),
.cfg_ext_read_received(cfg_ext_read_received),
.cfg_ext_write_received(cfg_ext_write_received),
.cfg_ext_register_number(cfg_ext_register_number),
.cfg_ext_function_number(cfg_ext_function_number),
.cfg_ext_write_data(cfg_ext_write_data),
.cfg_ext_write_byte_enable(cfg_ext_write_byte_enable),
.cfg_ext_read_data(cfg_ext_read_data),
.cfg_ext_read_data_valid(cfg_ext_read_data_valid),
// .cfg_interrupt_msix_enable(cfg_interrupt_msix_enable),
// .cfg_interrupt_msix_mask(cfg_interrupt_msix_mask),
// .cfg_interrupt_msix_vf_enable(cfg_interrupt_msix_vf_enable),
// .cfg_interrupt_msix_vf_mask(cfg_interrupt_msix_vf_mask),
// .cfg_interrupt_msix_address(cfg_interrupt_msix_address),
// .cfg_interrupt_msix_data(cfg_interrupt_msix_data),
// .cfg_interrupt_msix_int(cfg_interrupt_msix_int),
// .cfg_interrupt_msix_vec_pending(cfg_interrupt_msix_vec_pending),
// .cfg_interrupt_msix_vec_pending_status(cfg_interrupt_msix_vec_pending_status),
// .cfg_interrupt_msix_sent(cfg_interrupt_msix_sent),
// .cfg_interrupt_msix_fail(cfg_interrupt_msix_fail),
// .cfg_interrupt_msi_function_number(cfg_interrupt_msi_function_number),
.cfg_interrupt_msi_enable(cfg_interrupt_msi_enable),
.cfg_interrupt_msi_mmenable(cfg_interrupt_msi_mmenable),
.cfg_interrupt_msi_mask_update(cfg_interrupt_msi_mask_update),
.cfg_interrupt_msi_data(cfg_interrupt_msi_data),
.cfg_interrupt_msi_select(cfg_interrupt_msi_select),
.cfg_interrupt_msi_int(cfg_interrupt_msi_int),
.cfg_interrupt_msi_pending_status(cfg_interrupt_msi_pending_status),
.cfg_interrupt_msi_pending_status_data_enable(cfg_interrupt_msi_pending_status_data_enable),
.cfg_interrupt_msi_pending_status_function_num(cfg_interrupt_msi_pending_status_function_num),
.cfg_interrupt_msi_sent(cfg_interrupt_msi_sent),
.cfg_interrupt_msi_fail(cfg_interrupt_msi_fail),
.cfg_interrupt_msi_attr(cfg_interrupt_msi_attr),
.cfg_interrupt_msi_tph_present(cfg_interrupt_msi_tph_present),
.cfg_interrupt_msi_tph_type(cfg_interrupt_msi_tph_type),
.cfg_interrupt_msi_tph_st_tag(cfg_interrupt_msi_tph_st_tag),
.cfg_interrupt_msi_function_number(cfg_interrupt_msi_function_number),
/*
* BPI flash
*/
.fpga_boot(fpga_boot),
.flash_dq_i(flash_dq_i_int),
.flash_dq_o(flash_dq_o_int),
.flash_dq_oe(flash_dq_oe_int),
.flash_addr(flash_addr_int),
.flash_region(flash_region_int),
.flash_region_oe(flash_region_oe_int),
.flash_ce_n(flash_ce_n_int),
.flash_oe_n(flash_oe_n_int),
.flash_we_n(flash_we_n_int),
.flash_adv_n(flash_adv_n_int)
);
endmodule
`resetall

View File

@@ -0,0 +1,864 @@
// SPDX-License-Identifier: MIT
/*
Copyright (c) 2014-2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA core logic
*/
module fpga_core #
(
// simulation (set to avoid vendor primitives)
parameter logic SIM = 1'b0,
// vendor ("GENERIC", "XILINX", "ALTERA")
parameter string VENDOR = "XILINX",
// device family
parameter string FAMILY = "kintexu",
// FW ID
parameter FPGA_ID = 32'h3822093,
parameter FW_ID = 32'h0000C001,
parameter FW_VER = 32'h000_01_000,
parameter BOARD_ID = 32'h17df_1a00,
parameter BOARD_VER = 32'h001_00_000,
parameter BUILD_DATE = 32'd602976000,
parameter GIT_HASH = 32'h5f87c2e8,
parameter RELEASE_INFO = 32'h00000000,
// PTP configuration
parameter logic PTP_TS_EN = 1'b1,
// PCIe interface configuration
parameter RQ_SEQ_NUM_W = 6,
// AXI lite interface configuration (control)
parameter AXIL_CTRL_DATA_W = 32,
parameter AXIL_CTRL_ADDR_W = 24,
// MAC configuration
parameter logic CFG_LOW_LATENCY = 1'b1,
parameter logic COMBINED_MAC_PCS = 1'b1,
parameter MAC_DATA_W = 64
)
(
/*
* Clock: 125MHz
* Synchronous reset
*/
input wire logic clk_125mhz,
input wire logic rst_125mhz,
/*
* GPIO
*/
output wire logic [7:0] user_led,
output wire logic qsfp0_led_green,
output wire logic qsfp0_led_red,
output wire logic qsfp1_led_green,
output wire logic qsfp1_led_red,
/*
* UART: 115200 bps, 8N1
*/
input wire logic uart_rxd,
output wire logic uart_txd,
/*
* Ethernet: QSFP+
*/
input wire logic qsfp0_rx_p[4],
input wire logic qsfp0_rx_n[4],
output wire logic qsfp0_tx_p[4],
output wire logic qsfp0_tx_n[4],
input wire logic qsfp0_mgt_refclk_p,
input wire logic qsfp0_mgt_refclk_n,
output wire logic [1:0] qsfp0_fs,
output wire logic qsfp0_modsell,
output wire logic qsfp0_resetl,
input wire logic qsfp0_modprsl,
input wire logic qsfp0_intl,
output wire logic qsfp0_lpmode,
input wire logic qsfp1_rx_p[4],
input wire logic qsfp1_rx_n[4],
output wire logic qsfp1_tx_p[4],
output wire logic qsfp1_tx_n[4],
// input wire logic qsfp1_mgt_refclk_p,
// input wire logic qsfp1_mgt_refclk_n,
output wire logic [1:0] qsfp1_fs,
output wire logic qsfp1_modsell,
output wire logic qsfp1_resetl,
input wire logic qsfp1_modprsl,
input wire logic qsfp1_intl,
output wire logic qsfp1_lpmode,
/*
* PCIe
*/
input wire logic pcie_clk,
input wire logic pcie_rst,
taxi_axis_if.snk s_axis_pcie_cq,
taxi_axis_if.src m_axis_pcie_cc,
taxi_axis_if.src m_axis_pcie_rq,
taxi_axis_if.snk s_axis_pcie_rc,
input wire logic [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num,
input wire logic pcie_rq_seq_num_vld,
input wire logic [2:0] cfg_max_payload,
input wire logic [2:0] cfg_max_read_req,
input wire logic [3:0] cfg_rcb_status,
output wire logic [18:0] cfg_mgmt_addr,
output wire logic cfg_mgmt_write,
output wire logic [31:0] cfg_mgmt_write_data,
output wire logic [3:0] cfg_mgmt_byte_enable,
output wire logic cfg_mgmt_read,
output wire logic [31:0] cfg_mgmt_read_data,
input wire logic cfg_mgmt_read_write_done,
input wire logic [7:0] cfg_fc_ph,
input wire logic [11:0] cfg_fc_pd,
input wire logic [7:0] cfg_fc_nph,
input wire logic [11:0] cfg_fc_npd,
input wire logic [7:0] cfg_fc_cplh,
input wire logic [11:0] cfg_fc_cpld,
output wire logic [2:0] cfg_fc_sel,
input wire logic cfg_ext_read_received,
input wire logic cfg_ext_write_received,
input wire logic [9:0] cfg_ext_register_number,
input wire logic [7:0] cfg_ext_function_number,
input wire logic [31:0] cfg_ext_write_data,
input wire logic [3:0] cfg_ext_write_byte_enable,
output wire logic [31:0] cfg_ext_read_data,
output wire logic cfg_ext_read_data_valid,
input wire logic [3:0] cfg_interrupt_msi_enable,
input wire logic [11:0] cfg_interrupt_msi_mmenable,
input wire logic cfg_interrupt_msi_mask_update,
input wire logic [31:0] cfg_interrupt_msi_data,
output wire logic [3:0] cfg_interrupt_msi_select,
output wire logic [31:0] cfg_interrupt_msi_int,
output wire logic [31:0] cfg_interrupt_msi_pending_status,
output wire logic cfg_interrupt_msi_pending_status_data_enable,
output wire logic [3:0] cfg_interrupt_msi_pending_status_function_num,
input wire logic cfg_interrupt_msi_sent,
input wire logic cfg_interrupt_msi_fail,
output wire logic [2:0] cfg_interrupt_msi_attr,
output wire logic cfg_interrupt_msi_tph_present,
output wire logic [1:0] cfg_interrupt_msi_tph_type,
output wire logic [8:0] cfg_interrupt_msi_tph_st_tag,
output wire logic [3:0] cfg_interrupt_msi_function_number,
/*
* BPI flash
*/
output wire logic fpga_boot,
input wire logic [15:0] flash_dq_i,
output wire logic [15:0] flash_dq_o,
output wire logic flash_dq_oe,
output wire logic [23:0] flash_addr,
output wire logic [1:0] flash_region,
output wire logic flash_region_oe,
output wire logic flash_ce_n,
output wire logic flash_oe_n,
output wire logic flash_we_n,
output wire logic flash_adv_n
);
localparam logic PTP_TS_FMT_TOD = 1'b0;
localparam PTP_TS_W = PTP_TS_FMT_TOD ? 96 : 48;
// flashing via PCIe VSEC
pyrite_pcie_us_vsec_bpi #(
.EXT_CAP_ID(16'h000B),
.EXT_CAP_VERSION(4'h1),
.EXT_CAP_OFFSET(12'h480),
.EXT_CAP_NEXT(12'h000),
.EXT_CAP_VSEC_ID(16'h00DB),
.EXT_CAP_VSEC_REV(4'h1),
// FW ID
.FPGA_ID(FPGA_ID),
.FW_ID(FW_ID),
.FW_VER(FW_VER),
.BOARD_ID(BOARD_ID),
.BOARD_VER(BOARD_VER),
.BUILD_DATE(BUILD_DATE),
.GIT_HASH(GIT_HASH),
.RELEASE_INFO(RELEASE_INFO),
// Flash
.FLASH_SEG_COUNT(4),
.FLASH_SEG_DEFAULT(1),
.FLASH_SEG_FALLBACK(0),
.FLASH_SEG0_SIZE(32'h00000000),
.FLASH_DATA_W(16),
.FLASH_ADDR_W(24),
.FLASH_RGN_W(2)
)
pyrite_inst (
.clk(pcie_clk),
.rst(pcie_rst),
/*
* PCIe
*/
.cfg_ext_read_received(cfg_ext_read_received),
.cfg_ext_write_received(cfg_ext_write_received),
.cfg_ext_register_number(cfg_ext_register_number),
.cfg_ext_function_number(cfg_ext_function_number),
.cfg_ext_write_data(cfg_ext_write_data),
.cfg_ext_write_byte_enable(cfg_ext_write_byte_enable),
.cfg_ext_read_data(cfg_ext_read_data),
.cfg_ext_read_data_valid(cfg_ext_read_data_valid),
/*
* BPI flash
*/
.fpga_boot(fpga_boot),
.flash_dq_i(flash_dq_i),
.flash_dq_o(flash_dq_o),
.flash_dq_oe(flash_dq_oe),
.flash_addr(flash_addr),
.flash_region(flash_region),
.flash_region_oe(flash_region_oe),
.flash_ce_n(flash_ce_n),
.flash_oe_n(flash_oe_n),
.flash_we_n(flash_we_n),
.flash_adv_n(flash_adv_n)
);
// XFCP
taxi_axis_if #(.DATA_W(8), .USER_EN(1), .USER_W(1)) xfcp_ds(), xfcp_us();
taxi_xfcp_if_uart #(
.TX_FIFO_DEPTH(512),
.RX_FIFO_DEPTH(512)
)
xfcp_if_uart_inst (
.clk(clk_125mhz),
.rst(rst_125mhz),
/*
* UART interface
*/
.uart_rxd(uart_rxd),
.uart_txd(uart_txd),
/*
* XFCP downstream interface
*/
.xfcp_dsp_ds(xfcp_ds),
.xfcp_dsp_us(xfcp_us),
/*
* Configuration
*/
.prescale(16'(125000000/3000000))
);
localparam XFCP_PORTS = 3;
taxi_axis_if #(.DATA_W(8), .USER_EN(1), .USER_W(1)) xfcp_sw_ds[XFCP_PORTS](), xfcp_sw_us[XFCP_PORTS]();
taxi_xfcp_switch #(
.XFCP_ID_STR("DNPCIe"),
.XFCP_EXT_ID(0),
.XFCP_EXT_ID_STR("Taxi example"),
.PORTS($size(xfcp_sw_us))
)
xfcp_sw_inst (
.clk(clk_125mhz),
.rst(rst_125mhz),
/*
* XFCP upstream port
*/
.xfcp_usp_ds(xfcp_ds),
.xfcp_usp_us(xfcp_us),
/*
* XFCP downstream ports
*/
.xfcp_dsp_ds(xfcp_sw_ds),
.xfcp_dsp_us(xfcp_sw_us)
);
taxi_axis_if #(.DATA_W(16), .KEEP_W(1), .KEEP_EN(0), .LAST_EN(0), .USER_EN(1), .USER_W(1), .ID_EN(1), .ID_W(10)) axis_stat();
taxi_xfcp_mod_stats #(
.XFCP_ID_STR("Statistics"),
.XFCP_EXT_ID(0),
.XFCP_EXT_ID_STR(""),
.STAT_COUNT_W(64),
.STAT_PIPELINE(2)
)
xfcp_stats_inst (
.clk(clk_125mhz),
.rst(rst_125mhz),
/*
* XFCP upstream port
*/
.xfcp_usp_ds(xfcp_sw_ds[0]),
.xfcp_usp_us(xfcp_sw_us[0]),
/*
* Statistics increment input
*/
.s_axis_stat(axis_stat)
);
taxi_axis_if #(.DATA_W(16), .KEEP_W(1), .KEEP_EN(0), .LAST_EN(0), .USER_EN(1), .USER_W(1), .ID_EN(1), .ID_W(10)) axis_eth_stat[2]();
taxi_axis_arb_mux #(
.S_COUNT($size(axis_eth_stat)),
.UPDATE_TID(1'b0),
.ARB_ROUND_ROBIN(1'b1),
.ARB_LSB_HIGH_PRIO(1'b0)
)
stat_mux_inst (
.clk(clk_125mhz),
.rst(rst_125mhz),
/*
* AXI4-Stream inputs (sink)
*/
.s_axis(axis_eth_stat),
/*
* AXI4-Stream output (source)
*/
.m_axis(axis_stat)
);
taxi_axis_if #(
.DATA_W(32),
.KEEP_EN(1),
.ID_EN(1),
.ID_W(4),
.USER_EN(1),
.USER_W(1)
) axis_brd_ctrl_cmd(), axis_brd_ctrl_rsp();
// QSFP+
assign qsfp0_fs = 2'b00;
assign qsfp0_modsell = 1'b0;
assign qsfp0_resetl = 1'b1;
assign qsfp0_lpmode = 1'b0;
assign qsfp1_fs = 2'b00;
assign qsfp1_modsell = 1'b0;
assign qsfp1_resetl = 1'b1;
assign qsfp1_lpmode = 1'b0;
wire qsfp_tx_clk[8];
wire qsfp_tx_rst[8];
wire qsfp_rx_clk[8];
wire qsfp_rx_rst[8];
wire qsfp_rx_status[8];
assign user_led[0] = qsfp_rx_status[0];
assign user_led[1] = qsfp_rx_status[1];
assign user_led[2] = qsfp_rx_status[2];
assign user_led[3] = qsfp_rx_status[3];
assign user_led[4] = qsfp_rx_status[4];
assign user_led[5] = qsfp_rx_status[5];
assign user_led[6] = qsfp_rx_status[6];
// assign user_led[7] = qsfp_rx_status[7];
wire [1:0] qsfp_gtpowergood;
wire qsfp0_mgt_refclk;
wire qsfp0_mgt_refclk_int;
wire qsfp0_mgt_refclk_bufg;
wire qsfp_rst;
taxi_axis_if #(.DATA_W(MAC_DATA_W), .ID_W(8), .USER_EN(1), .USER_W(1)) axis_qsfp_tx[8]();
taxi_axis_if #(.DATA_W(PTP_TS_W), .KEEP_W(1), .ID_W(8)) axis_qsfp_tx_cpl[8]();
taxi_axis_if #(.DATA_W(MAC_DATA_W), .ID_W(8), .USER_EN(1), .USER_W(1+PTP_TS_W)) axis_qsfp_rx[8]();
if (SIM) begin
assign qsfp0_mgt_refclk = qsfp0_mgt_refclk_p;
assign qsfp0_mgt_refclk_int = qsfp0_mgt_refclk_p;
assign qsfp0_mgt_refclk_bufg = qsfp0_mgt_refclk_int;
end else begin
IBUFDS_GTE3 ibuf0s_gte3_qsfp0_mgt_refclk_inst (
.I (qsfp0_mgt_refclk_p),
.IB (qsfp0_mgt_refclk_n),
.CEB (1'b0),
.O (qsfp0_mgt_refclk),
.ODIV2 (qsfp0_mgt_refclk_int)
);
BUFG_GT bufg0gt_qsfp0_mgt_refclk_inst (
.CE (&qsfp_gtpowergood),
.CEMASK (1'b1),
.CLR (1'b0),
.CLRMASK (1'b1),
.DIV (3'd0),
.I (qsfp0_mgt_refclk_int),
.O (qsfp0_mgt_refclk_bufg)
);
end
taxi_sync_reset #(
.N(4)
)
qsfp_sync_reset_inst (
.clk(qsfp0_mgt_refclk_bufg),
.rst(rst_125mhz),
.out(qsfp_rst)
);
wire qsfp_tx_p[8];
wire qsfp_tx_n[8];
wire qsfp_rx_p[8];
wire qsfp_rx_n[8];
assign qsfp0_tx_p = qsfp_tx_p[4*0 +: 4];
assign qsfp0_tx_n = qsfp_tx_n[4*0 +: 4];
assign qsfp1_tx_p = qsfp_tx_p[4*1 +: 4];
assign qsfp1_tx_n = qsfp_tx_n[4*1 +: 4];
assign qsfp_rx_p[4*0 +: 4] = qsfp0_rx_p;
assign qsfp_rx_n[4*0 +: 4] = qsfp0_rx_n;
assign qsfp_rx_p[4*1 +: 4] = qsfp1_rx_p;
assign qsfp_rx_n[4*1 +: 4] = qsfp1_rx_n;
wire ptp_clk = qsfp0_mgt_refclk_bufg;
wire ptp_rst = qsfp_rst;
wire ptp_sample_clk = clk_125mhz;
wire ptp_td_sd;
wire ptp_pps;
wire ptp_pps_str;
assign user_led[7] = ptp_pps_str;
localparam logic [8*8-1:0] STAT_PREFIX_STR_QSFP1[4] = '{"QSFP1.1", "QSFP1.2", "QSFP1.3", "QSFP1.4"};
localparam logic [8*8-1:0] STAT_PREFIX_STR_QSFP2[4] = '{"QSFP2.1", "QSFP2.2", "QSFP2.3", "QSFP2.4"};
for (genvar n = 0; n < 2; n = n + 1) begin : gt_quad
localparam CNT = 4;
taxi_apb_if #(
.ADDR_W(18),
.DATA_W(16)
)
gt_apb_ctrl();
taxi_xfcp_mod_apb #(
.XFCP_EXT_ID_STR("GTH CTRL")
)
xfcp_mod_apb_inst (
.clk(clk_125mhz),
.rst(rst_125mhz),
/*
* XFCP upstream port
*/
.xfcp_usp_ds(xfcp_sw_ds[n+1]),
.xfcp_usp_us(xfcp_sw_us[n+1]),
/*
* APB master interface
*/
.m_apb(gt_apb_ctrl)
);
taxi_eth_mac_25g_us #(
.SIM(SIM),
.VENDOR(VENDOR),
.FAMILY(FAMILY),
.CNT(4),
// GT config
.CFG_LOW_LATENCY(CFG_LOW_LATENCY),
// GT type
.GT_TYPE("GTH"),
// MAC/PHY config
.COMBINED_MAC_PCS(COMBINED_MAC_PCS),
.DATA_W(MAC_DATA_W),
.PADDING_EN(1'b1),
.DIC_EN(1'b1),
.MIN_FRAME_LEN(64),
.PTP_TS_EN(PTP_TS_EN),
.PTP_TD_EN(PTP_TS_EN),
.PTP_TS_FMT_TOD(PTP_TS_FMT_TOD),
.PTP_TS_W(PTP_TS_W),
.PTP_TD_SDI_PIPELINE(2),
.PRBS31_EN(1'b0),
.TX_SERDES_PIPELINE(1),
.RX_SERDES_PIPELINE(1),
.COUNT_125US(125000/6.4),
.STAT_EN(1),
.STAT_TX_LEVEL(1),
.STAT_RX_LEVEL(1),
.STAT_ID_BASE(n*CNT*(16+16)),
.STAT_UPDATE_PERIOD(1024),
.STAT_STR_EN(1),
.STAT_PREFIX_STR(n == 0 ? STAT_PREFIX_STR_QSFP1 : STAT_PREFIX_STR_QSFP2)
)
mac_inst (
.xcvr_ctrl_clk(clk_125mhz),
.xcvr_ctrl_rst(qsfp_rst),
/*
* Transceiver control
*/
.s_apb_ctrl(gt_apb_ctrl),
/*
* Common
*/
.xcvr_gtpowergood_out(qsfp_gtpowergood[n]),
.xcvr_gtrefclk00_in(qsfp0_mgt_refclk),
.xcvr_qpll0pd_in(1'b0),
.xcvr_qpll0reset_in(1'b0),
.xcvr_qpll0pcierate_in(3'd0),
.xcvr_qpll0lock_out(),
.xcvr_qpll0clk_out(),
.xcvr_qpll0refclk_out(),
.xcvr_gtrefclk01_in(qsfp0_mgt_refclk),
.xcvr_qpll1pd_in(1'b0),
.xcvr_qpll1reset_in(1'b0),
.xcvr_qpll1pcierate_in(3'd0),
.xcvr_qpll1lock_out(),
.xcvr_qpll1clk_out(),
.xcvr_qpll1refclk_out(),
/*
* Serial data
*/
.xcvr_txp(qsfp_tx_p[n*CNT +: CNT]),
.xcvr_txn(qsfp_tx_n[n*CNT +: CNT]),
.xcvr_rxp(qsfp_rx_p[n*CNT +: CNT]),
.xcvr_rxn(qsfp_rx_n[n*CNT +: CNT]),
/*
* MAC clocks
*/
.rx_clk(qsfp_rx_clk[n*CNT +: CNT]),
.rx_rst_in('{CNT{1'b0}}),
.rx_rst_out(qsfp_rx_rst[n*CNT +: CNT]),
.tx_clk(qsfp_tx_clk[n*CNT +: CNT]),
.tx_rst_in('{CNT{1'b0}}),
.tx_rst_out(qsfp_tx_rst[n*CNT +: CNT]),
/*
* Transmit interface (AXI stream)
*/
.s_axis_tx(axis_qsfp_tx[n*CNT +: CNT]),
.m_axis_tx_cpl(axis_qsfp_tx_cpl[n*CNT +: CNT]),
/*
* Receive interface (AXI stream)
*/
.m_axis_rx(axis_qsfp_rx[n*CNT +: CNT]),
/*
* PTP clock
*/
.ptp_clk(ptp_clk),
.ptp_rst(ptp_rst),
.ptp_sample_clk(ptp_sample_clk),
.ptp_td_sdi(ptp_td_sd),
.tx_ptp_ts_in('{CNT{'0}}),
.tx_ptp_ts_out(),
.tx_ptp_ts_step_out(),
.tx_ptp_locked(),
.rx_ptp_ts_in('{CNT{'0}}),
.rx_ptp_ts_out(),
.rx_ptp_ts_step_out(),
.rx_ptp_locked(),
/*
* Link-level Flow Control (LFC) (IEEE 802.3 annex 31B PAUSE)
*/
.tx_lfc_req('{CNT{1'b0}}),
.tx_lfc_resend('{CNT{1'b0}}),
.rx_lfc_en('{CNT{1'b0}}),
.rx_lfc_req(),
.rx_lfc_ack('{CNT{1'b0}}),
/*
* Priority Flow Control (PFC) (IEEE 802.3 annex 31D PFC)
*/
.tx_pfc_req('{CNT{'0}}),
.tx_pfc_resend('{CNT{1'b0}}),
.rx_pfc_en('{CNT{'0}}),
.rx_pfc_req(),
.rx_pfc_ack('{CNT{'0}}),
/*
* Pause interface
*/
.tx_lfc_pause_en('{CNT{1'b0}}),
.tx_pause_req('{CNT{1'b0}}),
.tx_pause_ack(),
/*
* Statistics
*/
.stat_clk(clk_125mhz),
.stat_rst(rst_125mhz),
.m_axis_stat(axis_eth_stat[n]),
/*
* Status
*/
.tx_start_packet(),
.stat_tx_byte(),
.stat_tx_pkt_len(),
.stat_tx_pkt_ucast(),
.stat_tx_pkt_mcast(),
.stat_tx_pkt_bcast(),
.stat_tx_pkt_vlan(),
.stat_tx_pkt_good(),
.stat_tx_pkt_bad(),
.stat_tx_err_oversize(),
.stat_tx_err_user(),
.stat_tx_err_underflow(),
.rx_start_packet(),
.rx_error_count(),
.rx_block_lock(),
.rx_high_ber(),
.rx_status(qsfp_rx_status[n*CNT +: CNT]),
.stat_rx_byte(),
.stat_rx_pkt_len(),
.stat_rx_pkt_fragment(),
.stat_rx_pkt_jabber(),
.stat_rx_pkt_ucast(),
.stat_rx_pkt_mcast(),
.stat_rx_pkt_bcast(),
.stat_rx_pkt_vlan(),
.stat_rx_pkt_good(),
.stat_rx_pkt_bad(),
.stat_rx_err_oversize(),
.stat_rx_err_bad_fcs(),
.stat_rx_err_bad_block(),
.stat_rx_err_framing(),
.stat_rx_err_preamble(),
.stat_rx_fifo_drop('{CNT{1'b0}}),
.stat_tx_mcf(),
.stat_rx_mcf(),
.stat_tx_lfc_pkt(),
.stat_tx_lfc_xon(),
.stat_tx_lfc_xoff(),
.stat_tx_lfc_paused(),
.stat_tx_pfc_pkt(),
.stat_tx_pfc_xon(),
.stat_tx_pfc_xoff(),
.stat_tx_pfc_paused(),
.stat_rx_lfc_pkt(),
.stat_rx_lfc_xon(),
.stat_rx_lfc_xoff(),
.stat_rx_lfc_paused(),
.stat_rx_pfc_pkt(),
.stat_rx_pfc_xon(),
.stat_rx_pfc_xoff(),
.stat_rx_pfc_paused(),
/*
* Configuration
*/
.cfg_tx_max_pkt_len('{CNT{16'd9218}}),
.cfg_tx_ifg('{CNT{8'd12}}),
.cfg_tx_enable('{CNT{1'b1}}),
.cfg_rx_max_pkt_len('{CNT{16'd9218}}),
.cfg_rx_enable('{CNT{1'b1}}),
.cfg_tx_prbs31_enable('{CNT{1'b0}}),
.cfg_rx_prbs31_enable('{CNT{1'b0}}),
.cfg_mcf_rx_eth_dst_mcast('{CNT{48'h01_80_C2_00_00_01}}),
.cfg_mcf_rx_check_eth_dst_mcast('{CNT{1'b1}}),
.cfg_mcf_rx_eth_dst_ucast('{CNT{48'd0}}),
.cfg_mcf_rx_check_eth_dst_ucast('{CNT{1'b0}}),
.cfg_mcf_rx_eth_src('{CNT{48'd0}}),
.cfg_mcf_rx_check_eth_src('{CNT{1'b0}}),
.cfg_mcf_rx_eth_type('{CNT{16'h8808}}),
.cfg_mcf_rx_opcode_lfc('{CNT{16'h0001}}),
.cfg_mcf_rx_check_opcode_lfc('{CNT{1'b1}}),
.cfg_mcf_rx_opcode_pfc('{CNT{16'h0101}}),
.cfg_mcf_rx_check_opcode_pfc('{CNT{1'b1}}),
.cfg_mcf_rx_forward('{CNT{1'b0}}),
.cfg_mcf_rx_enable('{CNT{1'b0}}),
.cfg_tx_lfc_eth_dst('{CNT{48'h01_80_C2_00_00_01}}),
.cfg_tx_lfc_eth_src('{CNT{48'h80_23_31_43_54_4C}}),
.cfg_tx_lfc_eth_type('{CNT{16'h8808}}),
.cfg_tx_lfc_opcode('{CNT{16'h0001}}),
.cfg_tx_lfc_en('{CNT{1'b0}}),
.cfg_tx_lfc_quanta('{CNT{16'hffff}}),
.cfg_tx_lfc_refresh('{CNT{16'h7fff}}),
.cfg_tx_pfc_eth_dst('{CNT{48'h01_80_C2_00_00_01}}),
.cfg_tx_pfc_eth_src('{CNT{48'h80_23_31_43_54_4C}}),
.cfg_tx_pfc_eth_type('{CNT{16'h8808}}),
.cfg_tx_pfc_opcode('{CNT{16'h0101}}),
.cfg_tx_pfc_en('{CNT{1'b0}}),
.cfg_tx_pfc_quanta('{CNT{'{8{16'hffff}}}}),
.cfg_tx_pfc_refresh('{CNT{'{8{16'h7fff}}}}),
.cfg_rx_lfc_opcode('{CNT{16'h0001}}),
.cfg_rx_lfc_en('{CNT{1'b0}}),
.cfg_rx_pfc_opcode('{CNT{16'h0101}}),
.cfg_rx_pfc_en('{CNT{1'b0}})
);
end
wire [1:0] cfg_interrupt_msi_pending_status_function_num_int;
wire [7:0] cfg_interrupt_msi_tph_st_tag_int;
wire [7:0] cfg_interrupt_msi_function_number_int;
assign cfg_interrupt_msi_pending_status_function_num = 4'(cfg_interrupt_msi_pending_status_function_num_int);
assign cfg_interrupt_msi_tph_st_tag = 9'(cfg_interrupt_msi_tph_st_tag_int);
assign cfg_interrupt_msi_function_number = cfg_interrupt_msi_function_number_int[3:0];
cndm_micro_pcie_us #(
.SIM(SIM),
.VENDOR(VENDOR),
.FAMILY(FAMILY),
// FW ID
.FPGA_ID(FPGA_ID),
.FW_ID(FW_ID),
.FW_VER(FW_VER),
.BOARD_ID(BOARD_ID),
.BOARD_VER(BOARD_VER),
.BUILD_DATE(BUILD_DATE),
.GIT_HASH(GIT_HASH),
.RELEASE_INFO(RELEASE_INFO),
// Structural configuration
.PORTS($size(axis_qsfp_tx)),
.BRD_CTRL_EN(1'b0),
.SYS_CLK_PER_NS_NUM(4),
.SYS_CLK_PER_NS_DEN(1),
// PTP configuration
.PTP_TS_EN(PTP_TS_EN),
.PTP_TS_FMT_TOD(1'b0),
.PTP_CLK_PER_NS_NUM(32),
.PTP_CLK_PER_NS_DEN(5),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),
// AXI lite interface configuration (control)
.AXIL_CTRL_DATA_W(AXIL_CTRL_DATA_W),
.AXIL_CTRL_ADDR_W(AXIL_CTRL_ADDR_W)
)
cndm_inst (
/*
* PCIe
*/
.pcie_clk(pcie_clk),
.pcie_rst(pcie_rst),
.s_axis_pcie_cq(s_axis_pcie_cq),
.m_axis_pcie_cc(m_axis_pcie_cc),
.m_axis_pcie_rq(m_axis_pcie_rq),
.s_axis_pcie_rc(s_axis_pcie_rc),
.pcie_rq_seq_num0(pcie_rq_seq_num),
.pcie_rq_seq_num_vld0(pcie_rq_seq_num_vld),
.pcie_rq_seq_num1('0),
.pcie_rq_seq_num_vld1('0),
.cfg_max_payload(cfg_max_payload),
.cfg_max_read_req(cfg_max_read_req),
.cfg_rcb_status(cfg_rcb_status),
.cfg_mgmt_addr(cfg_mgmt_addr[9:0]),
.cfg_mgmt_function_number(cfg_mgmt_addr[17:10]),
.cfg_mgmt_write(cfg_mgmt_write),
.cfg_mgmt_write_data(cfg_mgmt_write_data),
.cfg_mgmt_byte_enable(cfg_mgmt_byte_enable),
.cfg_mgmt_read(cfg_mgmt_read),
.cfg_mgmt_read_data(cfg_mgmt_read_data),
.cfg_mgmt_read_write_done(cfg_mgmt_read_write_done),
.cfg_fc_ph(cfg_fc_ph),
.cfg_fc_pd(cfg_fc_pd),
.cfg_fc_nph(cfg_fc_nph),
.cfg_fc_npd(cfg_fc_npd),
.cfg_fc_cplh(cfg_fc_cplh),
.cfg_fc_cpld(cfg_fc_cpld),
.cfg_fc_sel(cfg_fc_sel),
.cfg_interrupt_msi_enable(cfg_interrupt_msi_enable),
.cfg_interrupt_msi_mmenable(cfg_interrupt_msi_mmenable),
.cfg_interrupt_msi_mask_update(cfg_interrupt_msi_mask_update),
.cfg_interrupt_msi_data(cfg_interrupt_msi_data),
.cfg_interrupt_msi_select(2'(cfg_interrupt_msi_select)),
.cfg_interrupt_msi_int(cfg_interrupt_msi_int),
.cfg_interrupt_msi_pending_status(cfg_interrupt_msi_pending_status),
.cfg_interrupt_msi_pending_status_data_enable(cfg_interrupt_msi_pending_status_data_enable),
.cfg_interrupt_msi_pending_status_function_num(cfg_interrupt_msi_pending_status_function_num_int),
.cfg_interrupt_msi_sent(cfg_interrupt_msi_sent),
.cfg_interrupt_msi_fail(cfg_interrupt_msi_fail),
.cfg_interrupt_msi_attr(cfg_interrupt_msi_attr),
.cfg_interrupt_msi_tph_present(cfg_interrupt_msi_tph_present),
.cfg_interrupt_msi_tph_type(cfg_interrupt_msi_tph_type),
.cfg_interrupt_msi_tph_st_tag(cfg_interrupt_msi_tph_st_tag_int),
.cfg_interrupt_msi_function_number(cfg_interrupt_msi_function_number_int),
/*
* Board control
*/
.m_axis_brd_ctrl_cmd(axis_brd_ctrl_cmd),
.s_axis_brd_ctrl_rsp(axis_brd_ctrl_rsp),
/*
* PTP
*/
.ptp_clk(ptp_clk),
.ptp_rst(ptp_rst),
.ptp_sample_clk(ptp_sample_clk),
.ptp_td_sdo(ptp_td_sd),
.ptp_pps(ptp_pps),
.ptp_pps_str(ptp_pps_str),
.ptp_sync_locked(),
.ptp_sync_ts_rel(),
.ptp_sync_ts_rel_step(),
.ptp_sync_ts_tod(),
.ptp_sync_ts_tod_step(),
.ptp_sync_pps(),
.ptp_sync_pps_str(),
/*
* Ethernet
*/
.mac_tx_clk(qsfp_tx_clk),
.mac_tx_rst(qsfp_tx_rst),
.mac_axis_tx(axis_qsfp_tx),
.mac_axis_tx_cpl(axis_qsfp_tx_cpl),
.mac_rx_clk(qsfp_rx_clk),
.mac_rx_rst(qsfp_rx_rst),
.mac_axis_rx(axis_qsfp_rx)
);
endmodule
`resetall

View File

@@ -0,0 +1,73 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2020-2026 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
TOPLEVEL_LANG = verilog
SIM ?= verilator
WAVES ?= 0
COCOTB_HDL_TIMEUNIT = 1ns
COCOTB_HDL_TIMEPRECISION = 1ps
RTL_DIR = ../../rtl
LIB_DIR = ../../lib
TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
DUT = fpga_core
COCOTB_TEST_MODULES = test_$(DUT)
COCOTB_TOPLEVEL = test_$(DUT)
MODULE = $(COCOTB_TEST_MODULES)
TOPLEVEL = $(COCOTB_TOPLEVEL)
VERILOG_SOURCES += $(COCOTB_TOPLEVEL).sv
VERILOG_SOURCES += $(RTL_DIR)/$(DUT).sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_micro_pcie_us.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_if_uart.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_apb.sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_switch.sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_stats.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/pyrite/rtl/pyrite_pcie_us_vsec_bpi.f
# handle file list files
process_f_file = $(call process_f_files,$(addprefix $(dir $1),$(shell cat $1)))
process_f_files = $(foreach f,$1,$(if $(filter %.f,$f),$(call process_f_file,$f),$f))
uniq_base = $(if $1,$(call uniq_base,$(foreach f,$1,$(if $(filter-out $(notdir $(lastword $1)),$(notdir $f)),$f,))) $(lastword $1))
VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES)))
# module parameters
export PARAM_SIM := "1'b1"
export PARAM_VENDOR := "\"XILINX\""
export PARAM_FAMILY := "\"kintexu\""
# PTP configuration
export PARAM_PTP_TS_EN := 1
# AXI lite interface configuration (control)
export PARAM_AXIL_CTRL_DATA_W := 32
export PARAM_AXIL_CTRL_ADDR_W := 24
# MAC configuration
export PARAM_CFG_LOW_LATENCY := 1
export PARAM_COMBINED_MAC_PCS := 1
export PARAM_MAC_DATA_W := 32
ifeq ($(SIM), icarus)
PLUSARGS += -fst
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-P $(COCOTB_TOPLEVEL).$(subst PARAM_,,$(v))=$($(v)))
else ifeq ($(SIM), verilator)
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(v))=$($(v)))
ifeq ($(WAVES), 1)
COMPILE_ARGS += --trace-fst
VERILATOR_TRACE = 1
endif
endif
include $(shell cocotb-config --makefiles)/Makefile.sim

View File

@@ -0,0 +1 @@
../../lib/taxi/src/eth/tb/baser.py

View File

@@ -0,0 +1 @@
../../lib/taxi/src/cndm/tb/cndm.py

View File

@@ -0,0 +1,495 @@
#!/usr/bin/env python
# SPDX-License-Identifier: MIT
"""
Copyright (c) 2020-2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
"""
import itertools
import logging
import os
import sys
import cocotb_test.simulator
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, FallingEdge, Timer
from cocotbext.axi import AxiStreamBus
from cocotbext.eth import XgmiiFrame
from cocotbext.uart import UartSource, UartSink
from cocotbext.pcie.core import RootComplex
from cocotbext.pcie.xilinx.us import UltraScalePcieDevice
try:
from baser import BaseRSerdesSource, BaseRSerdesSink
import cndm
except ImportError:
# attempt import from current directory
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
try:
from baser import BaseRSerdesSource, BaseRSerdesSink
import cndm
finally:
del sys.path[0]
class TB:
def __init__(self, dut):
self.dut = dut
self.log = logging.getLogger("cocotb.tb")
self.log.setLevel(logging.DEBUG)
# Clocks
cocotb.start_soon(Clock(dut.clk_125mhz, 8, units="ns").start())
# PCIe
self.rc = RootComplex()
self.rc.max_payload_size = 0x1 # 256 bytes
self.rc.max_read_request_size = 0x2 # 512 bytes
self.dev = UltraScalePcieDevice(
# configuration options
pcie_generation=3,
pcie_link_width=8,
user_clk_frequency=250e6,
alignment="dword",
rc_straddle=False,
pf_count=1,
max_payload_size=1024,
enable_client_tag=True,
enable_extended_tag=True,
enable_parity=False,
enable_rx_msg_interface=False,
enable_sriov=False,
enable_extended_configuration=False,
pf0_msi_enable=True,
pf0_msi_count=32,
pf1_msi_enable=False,
pf1_msi_count=1,
pf0_msix_enable=False,
pf0_msix_table_size=31,
pf0_msix_table_bir=4,
pf0_msix_table_offset=0x00000000,
pf0_msix_pba_bir=4,
pf0_msix_pba_offset=0x00008000,
pf1_msix_enable=False,
pf1_msix_table_size=0,
pf1_msix_table_bir=0,
pf1_msix_table_offset=0x00000000,
pf1_msix_pba_bir=0,
pf1_msix_pba_offset=0x00000000,
# signals
# Clock and Reset Interface
user_clk=dut.pcie_clk,
user_reset=dut.pcie_rst,
# user_lnk_up
# sys_clk
# sys_clk_gt
# sys_reset
# phy_rdy_out
# Requester reQuest Interface
rq_bus=AxiStreamBus.from_entity(dut.m_axis_pcie_rq),
pcie_rq_seq_num=dut.pcie_rq_seq_num,
pcie_rq_seq_num_vld=dut.pcie_rq_seq_num_vld,
# pcie_rq_tag
# pcie_rq_tag_av
# pcie_rq_tag_vld
# Requester Completion Interface
rc_bus=AxiStreamBus.from_entity(dut.s_axis_pcie_rc),
# Completer reQuest Interface
cq_bus=AxiStreamBus.from_entity(dut.s_axis_pcie_cq),
# pcie_cq_np_req
# pcie_cq_np_req_count
# Completer Completion Interface
cc_bus=AxiStreamBus.from_entity(dut.m_axis_pcie_cc),
# Transmit Flow Control Interface
# pcie_tfc_nph_av=dut.pcie_tfc_nph_av,
# pcie_tfc_npd_av=dut.pcie_tfc_npd_av,
# Configuration Management Interface
cfg_mgmt_addr=dut.cfg_mgmt_addr,
cfg_mgmt_write=dut.cfg_mgmt_write,
cfg_mgmt_write_data=dut.cfg_mgmt_write_data,
cfg_mgmt_byte_enable=dut.cfg_mgmt_byte_enable,
cfg_mgmt_read=dut.cfg_mgmt_read,
cfg_mgmt_read_data=dut.cfg_mgmt_read_data,
cfg_mgmt_read_write_done=dut.cfg_mgmt_read_write_done,
# cfg_mgmt_debug_access
# Configuration Status Interface
# cfg_phy_link_down
# cfg_phy_link_status
# cfg_negotiated_width
# cfg_current_speed
cfg_max_payload=dut.cfg_max_payload,
cfg_max_read_req=dut.cfg_max_read_req,
# cfg_function_status
# cfg_vf_status
# cfg_function_power_state
# cfg_vf_power_state
# cfg_link_power_state
# cfg_err_cor_out
# cfg_err_nonfatal_out
# cfg_err_fatal_out
# cfg_local_error_out
# cfg_local_error_valid
# cfg_rx_pm_state
# cfg_tx_pm_state
# cfg_ltssm_state
cfg_rcb_status=dut.cfg_rcb_status,
# cfg_obff_enable
# cfg_pl_status_change
# cfg_tph_requester_enable
# cfg_tph_st_mode
# cfg_vf_tph_requester_enable
# cfg_vf_tph_st_mode
# Configuration Received Message Interface
# cfg_msg_received
# cfg_msg_received_data
# cfg_msg_received_type
# Configuration Transmit Message Interface
# cfg_msg_transmit
# cfg_msg_transmit_type
# cfg_msg_transmit_data
# cfg_msg_transmit_done
# Configuration Flow Control Interface
cfg_fc_ph=dut.cfg_fc_ph,
cfg_fc_pd=dut.cfg_fc_pd,
cfg_fc_nph=dut.cfg_fc_nph,
cfg_fc_npd=dut.cfg_fc_npd,
cfg_fc_cplh=dut.cfg_fc_cplh,
cfg_fc_cpld=dut.cfg_fc_cpld,
cfg_fc_sel=dut.cfg_fc_sel,
# Configuration Control Interface
# cfg_hot_reset_in
# cfg_hot_reset_out
# cfg_config_space_enable
# cfg_dsn
# cfg_bus_number
# cfg_ds_port_number
# cfg_ds_bus_number
# cfg_ds_device_number
# cfg_ds_function_number
# cfg_power_state_change_ack
# cfg_power_state_change_interrupt
# cfg_err_cor_in=dut.status_error_cor,
# cfg_err_uncor_in=dut.status_error_uncor,
# cfg_flr_in_process
# cfg_flr_done
# cfg_vf_flr_in_process
# cfg_vf_flr_func_num
# cfg_vf_flr_done
# cfg_pm_aspm_l1_entry_reject
# cfg_pm_aspm_tx_l0s_entry_disable
# cfg_req_pm_transition_l23_ready
# cfg_link_training_enable
# Configuration Interrupt Controller Interface
# cfg_interrupt_int
# cfg_interrupt_sent
# cfg_interrupt_pending
cfg_interrupt_msi_enable=dut.cfg_interrupt_msi_enable,
# cfg_interrupt_msi_vf_enable=dut.cfg_interrupt_msi_vf_enable,
cfg_interrupt_msi_mmenable=dut.cfg_interrupt_msi_mmenable,
cfg_interrupt_msi_mask_update=dut.cfg_interrupt_msi_mask_update,
cfg_interrupt_msi_data=dut.cfg_interrupt_msi_data,
cfg_interrupt_msi_select=dut.cfg_interrupt_msi_select,
cfg_interrupt_msi_int=dut.cfg_interrupt_msi_int,
cfg_interrupt_msi_pending_status=dut.cfg_interrupt_msi_pending_status,
cfg_interrupt_msi_pending_status_data_enable=dut.cfg_interrupt_msi_pending_status_data_enable,
cfg_interrupt_msi_pending_status_function_num=dut.cfg_interrupt_msi_pending_status_function_num,
cfg_interrupt_msi_sent=dut.cfg_interrupt_msi_sent,
cfg_interrupt_msi_fail=dut.cfg_interrupt_msi_fail,
# cfg_interrupt_msix_enable=dut.cfg_interrupt_msix_enable,
# cfg_interrupt_msix_mask=dut.cfg_interrupt_msix_mask,
# cfg_interrupt_msix_vf_enable=dut.cfg_interrupt_msix_vf_enable,
# cfg_interrupt_msix_vf_mask=dut.cfg_interrupt_msix_vf_mask,
# cfg_interrupt_msix_address=dut.cfg_interrupt_msix_address,
# cfg_interrupt_msix_data=dut.cfg_interrupt_msix_data,
# cfg_interrupt_msix_int=dut.cfg_interrupt_msix_int,
# cfg_interrupt_msix_sent=dut.cfg_interrupt_msix_sent,
# cfg_interrupt_msix_fail=dut.cfg_interrupt_msix_fail,
cfg_interrupt_msi_attr=dut.cfg_interrupt_msi_attr,
cfg_interrupt_msi_tph_present=dut.cfg_interrupt_msi_tph_present,
cfg_interrupt_msi_tph_type=dut.cfg_interrupt_msi_tph_type,
cfg_interrupt_msi_tph_st_tag=dut.cfg_interrupt_msi_tph_st_tag,
cfg_interrupt_msi_function_number=dut.cfg_interrupt_msi_function_number,
# Configuration Extend Interface
# cfg_ext_read_received
# cfg_ext_write_received
# cfg_ext_register_number
# cfg_ext_function_number
# cfg_ext_write_data
# cfg_ext_write_byte_enable
# cfg_ext_read_data
# cfg_ext_read_data_valid
)
# self.dev.log.setLevel(logging.DEBUG)
self.rc.make_port().connect(self.dev)
self.dev.functions[0].configure_bar(0, 2**int(dut.uut.cndm_inst.axil_ctrl_bar.ADDR_W))
self.uart_source = UartSource(dut.uart_rxd, baud=3000000, bits=8, stop_bits=1)
self.uart_sink = UartSink(dut.uart_txd, baud=3000000, bits=8, stop_bits=1)
# Ethernet
cocotb.start_soon(Clock(dut.qsfp0_mgt_refclk_p, 6.4, units="ns").start())
self.qsfp_sources = []
self.qsfp_sinks = []
for ch in itertools.chain.from_iterable([inst.mac_inst.ch for inst in dut.uut.gt_quad]):
gt_inst = ch.ch_inst.gt.gt_inst
if ch.ch_inst.DATA_W.value == 64:
if ch.ch_inst.CFG_LOW_LATENCY.value:
clk = 6.206
gbx_cfg = (66, [64, 65])
else:
clk = 6.4
gbx_cfg = None
else:
if ch.ch_inst.CFG_LOW_LATENCY.value:
clk = 3.102
gbx_cfg = (66, [64, 65])
else:
clk = 3.2
gbx_cfg = None
cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start())
cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start())
self.qsfp_sources.append(BaseRSerdesSource(
data=gt_inst.serdes_rx_data,
data_valid=gt_inst.serdes_rx_data_valid,
hdr=gt_inst.serdes_rx_hdr,
hdr_valid=gt_inst.serdes_rx_hdr_valid,
clock=gt_inst.rx_clk,
slip=gt_inst.serdes_rx_bitslip,
reverse=True,
gbx_cfg=gbx_cfg
))
self.qsfp_sinks.append(BaseRSerdesSink(
data=gt_inst.serdes_tx_data,
data_valid=gt_inst.serdes_tx_data_valid,
hdr=gt_inst.serdes_tx_hdr,
hdr_valid=gt_inst.serdes_tx_hdr_valid,
gbx_sync=gt_inst.serdes_tx_gbx_sync,
clock=gt_inst.tx_clk,
reverse=True,
gbx_cfg=gbx_cfg
))
self.loopback_enable = False
cocotb.start_soon(self._run_loopback())
async def init(self):
self.dut.rst_125mhz.setimmediatevalue(0)
await FallingEdge(self.dut.pcie_rst)
await Timer(100, 'ns')
for k in range(10):
await RisingEdge(self.dut.clk_125mhz)
self.dut.rst_125mhz.value = 1
for k in range(10):
await RisingEdge(self.dut.clk_125mhz)
self.dut.rst_125mhz.value = 0
for k in range(10):
await RisingEdge(self.dut.clk_125mhz)
await self.rc.enumerate()
async def _run_loopback(self):
while True:
await RisingEdge(self.dut.pcie_clk)
if self.loopback_enable:
for src, snk in zip(self.qsfp_sources, self.qsfp_sinks):
while not snk.empty():
await src.send(await snk.recv())
@cocotb.test()
async def run_test(dut):
tb = TB(dut)
await tb.init()
tb.log.info("Init driver model")
driver = cndm.Driver()
await driver.init_pcie_dev(tb.rc.find_device(tb.dev.functions[0].pcie_id))
tb.log.info("Init complete")
tb.log.info("Wait for block lock")
for k in range(1200):
await RisingEdge(tb.dut.clk_125mhz)
for snk in tb.qsfp_sinks:
snk.clear()
tb.log.info("Send and receive single packet on each port")
for k in range(len(driver.ports)):
data = f"Corundum rocks on port {k}!".encode('ascii')
await driver.ports[k].start_xmit(data)
pkt = await tb.qsfp_sinks[k].recv()
tb.log.info("Got TX packet: %s", pkt)
assert pkt.get_payload() == data.ljust(60, b'\x00')
assert pkt.check_fcs()
await tb.qsfp_sources[k].send(pkt)
pkt = await driver.ports[k].recv()
tb.log.info("Got RX packet: %s", pkt)
assert bytes(pkt) == data.ljust(60, b'\x00')
tb.log.info("Multiple small packets")
count = 64
pkts = [bytearray([(x+k) % 256 for x in range(60)]) for k in range(count)]
tb.loopback_enable = True
for p in pkts:
await driver.ports[0].start_xmit(p)
for k in range(count):
pkt = await driver.ports[0].recv()
tb.log.info("Got RX packet: %s", pkt)
assert bytes(pkt) == pkts[k].ljust(60, b'\x00')
tb.loopback_enable = False
tb.log.info("Multiple large packets")
count = 64
pkts = [bytearray([(x+k) % 256 for x in range(1514)]) for k in range(count)]
tb.loopback_enable = True
for p in pkts:
await driver.ports[0].start_xmit(p)
for k in range(count):
pkt = await driver.ports[0].recv()
tb.log.info("Got RX packet: %s", pkt)
assert bytes(pkt) == pkts[k].ljust(60, b'\x00')
tb.loopback_enable = False
await RisingEdge(dut.clk_125mhz)
await RisingEdge(dut.clk_125mhz)
# cocotb-test
tests_dir = os.path.abspath(os.path.dirname(__file__))
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
lib_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'lib'))
taxi_src_dir = os.path.abspath(os.path.join(lib_dir, 'taxi', 'src'))
def process_f_files(files):
lst = {}
for f in files:
if f[-2:].lower() == '.f':
with open(f, 'r') as fp:
l = fp.read().split()
for f in process_f_files([os.path.join(os.path.dirname(f), x) for x in l]):
lst[os.path.basename(f)] = f
else:
lst[os.path.basename(f)] = f
return list(lst.values())
def test_fpga_core(request):
dut = "fpga_core"
module = os.path.splitext(os.path.basename(__file__))[0]
toplevel = module
verilog_sources = [
os.path.join(tests_dir, f"{toplevel}.sv"),
os.path.join(rtl_dir, f"{dut}.sv"),
os.path.join(taxi_src_dir, "cndm", "rtl", "cndm_micro_pcie_us.f"),
os.path.join(taxi_src_dir, "eth", "rtl", "us", "taxi_eth_mac_25g_us.f"),
os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_if_uart.f"),
os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_switch.sv"),
os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_mod_apb.f"),
os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_mod_stats.f"),
os.path.join(taxi_src_dir, "sync", "rtl", "taxi_sync_reset.sv"),
os.path.join(taxi_src_dir, "sync", "rtl", "taxi_sync_signal.sv"),
os.path.join(taxi_src_dir, "pyrite", "rtl", "pyrite_pcie_us_vsec_bpi.f"),
]
verilog_sources = process_f_files(verilog_sources)
parameters = {}
parameters['SIM'] = "1'b1"
parameters['VENDOR'] = "\"XILINX\""
parameters['FAMILY'] = "\"kintexu\""
# PTP configuration
parameters['PTP_TS_EN'] = 1
# AXI lite interface configuration (control)
parameters['AXIL_CTRL_DATA_W'] = 32
parameters['AXIL_CTRL_ADDR_W'] = 24
# MAC configuration
parameters['CFG_LOW_LATENCY'] = 1
parameters['COMBINED_MAC_PCS'] = 1
parameters['MAC_DATA_W'] = 32
extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()}
sim_build = os.path.join(tests_dir, "sim_build",
request.node.name.replace('[', '-').replace(']', ''))
cocotb_test.simulator.run(
simulator="verilator",
python_search=[tests_dir],
verilog_sources=verilog_sources,
toplevel=toplevel,
module=module,
parameters=parameters,
sim_build=sim_build,
extra_env=extra_env,
)

View File

@@ -0,0 +1,345 @@
// SPDX-License-Identifier: MIT
/*
Copyright (c) 2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA core logic testbench
*/
module test_fpga_core #
(
/* verilator lint_off WIDTHTRUNC */
parameter logic SIM = 1'b0,
parameter string VENDOR = "XILINX",
parameter string FAMILY = "kintexu",
// FW ID
parameter FPGA_ID = 32'h3822093,
parameter FW_ID = 32'h0000C001,
parameter FW_VER = 32'h000_01_000,
parameter BOARD_ID = 32'h17df_1a00,
parameter BOARD_VER = 32'h001_00_000,
parameter BUILD_DATE = 32'd602976000,
parameter GIT_HASH = 32'h5f87c2e8,
parameter RELEASE_INFO = 32'h00000000,
// PTP configuration
parameter logic PTP_TS_EN = 1'b1,
// PCIe interface configuration
parameter AXIS_PCIE_DATA_W = 256,
parameter AXIS_PCIE_RC_USER_W = 75,
parameter AXIS_PCIE_RQ_USER_W = 60,
parameter AXIS_PCIE_CQ_USER_W = 85,
parameter AXIS_PCIE_CC_USER_W = 33,
// AXI lite interface configuration (control)
parameter AXIL_CTRL_DATA_W = 32,
parameter AXIL_CTRL_ADDR_W = 24,
// MAC configuration
parameter logic CFG_LOW_LATENCY = 1'b1,
parameter logic COMBINED_MAC_PCS = 1'b1,
parameter MAC_DATA_W = 32
/* verilator lint_on WIDTHTRUNC */
)
();
localparam AXIS_PCIE_KEEP_W = (AXIS_PCIE_DATA_W/32);
localparam RQ_SEQ_NUM_W = AXIS_PCIE_RQ_USER_W == 60 ? 4 : 6;
logic clk_125mhz;
logic rst_125mhz;
logic [7:0] user_led;
logic qsfp0_led_green;
logic qsfp0_led_red;
logic qsfp1_led_green;
logic qsfp1_led_red;
logic uart_rxd;
logic uart_txd;
logic qsfp0_mgt_refclk_p;
logic qsfp0_mgt_refclk_n;
logic [1:0] qsfp0_fs;
logic qsfp0_modsell;
logic qsfp0_resetl;
logic qsfp0_modprsl;
logic qsfp0_intl;
logic qsfp0_lpmode;
// logic qsfp1_mgt_refclk_p;
// logic qsfp1_mgt_refclk_n;
logic [1:0] qsfp1_fs;
logic qsfp1_modsell;
logic qsfp1_resetl;
logic qsfp1_modprsl;
logic qsfp1_intl;
logic qsfp1_lpmode;
logic pcie_clk;
logic pcie_rst;
taxi_axis_if #(
.DATA_W(AXIS_PCIE_DATA_W),
.KEEP_EN(1),
.KEEP_W(AXIS_PCIE_KEEP_W),
.USER_EN(1),
.USER_W(AXIS_PCIE_CQ_USER_W)
) s_axis_pcie_cq();
taxi_axis_if #(
.DATA_W(AXIS_PCIE_DATA_W),
.KEEP_EN(1),
.KEEP_W(AXIS_PCIE_KEEP_W),
.USER_EN(1),
.USER_W(AXIS_PCIE_CC_USER_W)
) m_axis_pcie_cc();
taxi_axis_if #(
.DATA_W(AXIS_PCIE_DATA_W),
.KEEP_EN(1),
.KEEP_W(AXIS_PCIE_KEEP_W),
.USER_EN(1),
.USER_W(AXIS_PCIE_RQ_USER_W)
) m_axis_pcie_rq();
taxi_axis_if #(
.DATA_W(AXIS_PCIE_DATA_W),
.KEEP_EN(1),
.KEEP_W(AXIS_PCIE_KEEP_W),
.USER_EN(1),
.USER_W(AXIS_PCIE_RC_USER_W)
) s_axis_pcie_rc();
logic [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num;
logic pcie_rq_seq_num_vld;
logic [2:0] cfg_max_payload;
logic [2:0] cfg_max_read_req;
logic [3:0] cfg_rcb_status;
logic [18:0] cfg_mgmt_addr;
logic cfg_mgmt_write;
logic [31:0] cfg_mgmt_write_data;
logic [3:0] cfg_mgmt_byte_enable;
logic cfg_mgmt_read;
logic [31:0] cfg_mgmt_read_data;
logic cfg_mgmt_read_write_done;
logic [7:0] cfg_fc_ph;
logic [11:0] cfg_fc_pd;
logic [7:0] cfg_fc_nph;
logic [11:0] cfg_fc_npd;
logic [7:0] cfg_fc_cplh;
logic [11:0] cfg_fc_cpld;
logic [2:0] cfg_fc_sel;
logic cfg_ext_read_received;
logic cfg_ext_write_received;
logic [9:0] cfg_ext_register_number;
logic [7:0] cfg_ext_function_number;
logic [31:0] cfg_ext_write_data;
logic [3:0] cfg_ext_write_byte_enable;
logic [31:0] cfg_ext_read_data;
logic cfg_ext_read_data_valid;
logic [3:0] cfg_interrupt_msi_enable;
logic [11:0] cfg_interrupt_msi_mmenable;
logic cfg_interrupt_msi_mask_update;
logic [31:0] cfg_interrupt_msi_data;
logic [3:0] cfg_interrupt_msi_select;
logic [31:0] cfg_interrupt_msi_int;
logic [31:0] cfg_interrupt_msi_pending_status;
logic cfg_interrupt_msi_pending_status_data_enable;
logic [3:0] cfg_interrupt_msi_pending_status_function_num;
logic cfg_interrupt_msi_sent;
logic cfg_interrupt_msi_fail;
logic [2:0] cfg_interrupt_msi_attr;
logic cfg_interrupt_msi_tph_present;
logic [1:0] cfg_interrupt_msi_tph_type;
logic [8:0] cfg_interrupt_msi_tph_st_tag;
logic [3:0] cfg_interrupt_msi_function_number;
logic fpga_boot;
logic [15:0] flash_dq_i;
logic [15:0] flash_dq_o;
logic flash_dq_oe;
logic [23:0] flash_addr;
logic [1:0] flash_region;
logic flash_region_oe;
logic flash_ce_n;
logic flash_oe_n;
logic flash_we_n;
logic flash_adv_n;
fpga_core #(
.SIM(SIM),
.VENDOR(VENDOR),
.FAMILY(FAMILY),
// FW ID
.FPGA_ID(FPGA_ID),
.FW_ID(FW_ID),
.FW_VER(FW_VER),
.BOARD_ID(BOARD_ID),
.BOARD_VER(BOARD_VER),
.BUILD_DATE(BUILD_DATE),
.GIT_HASH(GIT_HASH),
.RELEASE_INFO(RELEASE_INFO),
// PTP configuration
.PTP_TS_EN(PTP_TS_EN),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),
// AXI lite interface configuration (control)
.AXIL_CTRL_DATA_W(AXIL_CTRL_DATA_W),
.AXIL_CTRL_ADDR_W(AXIL_CTRL_ADDR_W),
// MAC configuration
.CFG_LOW_LATENCY(CFG_LOW_LATENCY),
.COMBINED_MAC_PCS(COMBINED_MAC_PCS),
.MAC_DATA_W(MAC_DATA_W)
)
uut (
/*
* Clock: 125MHz
* Synchronous reset
*/
.clk_125mhz(clk_125mhz),
.rst_125mhz(rst_125mhz),
/*
* GPIO
*/
.user_led(user_led),
.qsfp0_led_green(qsfp0_led_green),
.qsfp0_led_red(qsfp0_led_red),
.qsfp1_led_green(qsfp1_led_green),
.qsfp1_led_red(qsfp1_led_red),
/*
* UART: 115200 bps, 8N1
*/
.uart_rxd(uart_rxd),
.uart_txd(uart_txd),
/*
* Ethernet: QSFP+
*/
.qsfp0_rx_p('{4{1'b0}}),
.qsfp0_rx_n('{4{1'b0}}),
.qsfp0_tx_p(),
.qsfp0_tx_n(),
.qsfp0_mgt_refclk_p(qsfp0_mgt_refclk_p),
.qsfp0_mgt_refclk_n(qsfp0_mgt_refclk_n),
.qsfp0_fs(qsfp0_fs),
.qsfp0_modsell(qsfp0_modsell),
.qsfp0_resetl(qsfp0_resetl),
.qsfp0_modprsl(qsfp0_modprsl),
.qsfp0_intl(qsfp0_intl),
.qsfp0_lpmode(qsfp0_lpmode),
.qsfp1_rx_p('{4{1'b0}}),
.qsfp1_rx_n('{4{1'b0}}),
.qsfp1_tx_p(),
.qsfp1_tx_n(),
// .qsfp1_mgt_refclk_p(qsfp1_mgt_refclk_p),
// .qsfp1_mgt_refclk_n(qsfp1_mgt_refclk_n),
.qsfp1_fs(qsfp1_fs),
.qsfp1_modsell(qsfp1_modsell),
.qsfp1_resetl(qsfp1_resetl),
.qsfp1_modprsl(qsfp1_modprsl),
.qsfp1_intl(qsfp1_intl),
.qsfp1_lpmode(qsfp1_lpmode),
/*
* PCIe
*/
.pcie_clk(pcie_clk),
.pcie_rst(pcie_rst),
.s_axis_pcie_cq(s_axis_pcie_cq),
.m_axis_pcie_cc(m_axis_pcie_cc),
.m_axis_pcie_rq(m_axis_pcie_rq),
.s_axis_pcie_rc(s_axis_pcie_rc),
.pcie_rq_seq_num(pcie_rq_seq_num),
.pcie_rq_seq_num_vld(pcie_rq_seq_num_vld),
.cfg_max_payload(cfg_max_payload),
.cfg_max_read_req(cfg_max_read_req),
.cfg_rcb_status(cfg_rcb_status),
.cfg_mgmt_addr(cfg_mgmt_addr),
.cfg_mgmt_write(cfg_mgmt_write),
.cfg_mgmt_write_data(cfg_mgmt_write_data),
.cfg_mgmt_byte_enable(cfg_mgmt_byte_enable),
.cfg_mgmt_read(cfg_mgmt_read),
.cfg_mgmt_read_data(cfg_mgmt_read_data),
.cfg_mgmt_read_write_done(cfg_mgmt_read_write_done),
.cfg_fc_ph(cfg_fc_ph),
.cfg_fc_pd(cfg_fc_pd),
.cfg_fc_nph(cfg_fc_nph),
.cfg_fc_npd(cfg_fc_npd),
.cfg_fc_cplh(cfg_fc_cplh),
.cfg_fc_cpld(cfg_fc_cpld),
.cfg_fc_sel(cfg_fc_sel),
.cfg_ext_read_received(cfg_ext_read_received),
.cfg_ext_write_received(cfg_ext_write_received),
.cfg_ext_register_number(cfg_ext_register_number),
.cfg_ext_function_number(cfg_ext_function_number),
.cfg_ext_write_data(cfg_ext_write_data),
.cfg_ext_write_byte_enable(cfg_ext_write_byte_enable),
.cfg_ext_read_data(cfg_ext_read_data),
.cfg_ext_read_data_valid(cfg_ext_read_data_valid),
.cfg_interrupt_msi_enable(cfg_interrupt_msi_enable),
.cfg_interrupt_msi_mmenable(cfg_interrupt_msi_mmenable),
.cfg_interrupt_msi_mask_update(cfg_interrupt_msi_mask_update),
.cfg_interrupt_msi_data(cfg_interrupt_msi_data),
.cfg_interrupt_msi_select(cfg_interrupt_msi_select),
.cfg_interrupt_msi_int(cfg_interrupt_msi_int),
.cfg_interrupt_msi_pending_status(cfg_interrupt_msi_pending_status),
.cfg_interrupt_msi_pending_status_data_enable(cfg_interrupt_msi_pending_status_data_enable),
.cfg_interrupt_msi_pending_status_function_num(cfg_interrupt_msi_pending_status_function_num),
.cfg_interrupt_msi_sent(cfg_interrupt_msi_sent),
.cfg_interrupt_msi_fail(cfg_interrupt_msi_fail),
.cfg_interrupt_msi_attr(cfg_interrupt_msi_attr),
.cfg_interrupt_msi_tph_present(cfg_interrupt_msi_tph_present),
.cfg_interrupt_msi_tph_type(cfg_interrupt_msi_tph_type),
.cfg_interrupt_msi_tph_st_tag(cfg_interrupt_msi_tph_st_tag),
.cfg_interrupt_msi_function_number(cfg_interrupt_msi_function_number),
/*
* QSPI flash
*/
.fpga_boot(fpga_boot),
.flash_dq_i(flash_dq_i),
.flash_dq_o(flash_dq_o),
.flash_dq_oe(flash_dq_oe),
.flash_addr(flash_addr),
.flash_region(flash_region),
.flash_region_oe(flash_region_oe),
.flash_ce_n(flash_ce_n),
.flash_oe_n(flash_oe_n),
.flash_we_n(flash_we_n),
.flash_adv_n(flash_adv_n)
);
endmodule
`resetall

View File

@@ -0,0 +1,37 @@
# Corundum for KCU105
## Introduction
This design targets the Xilinx KCU105 FPGA board.
* USB UART
* XFCP (921600 baud)
* RJ-45 Ethernet port with Marvell 88E1111 PHY
* Looped-back MAC via SGMII via Xilinx PCS/PMA core and LVDS IOSERDES
* SFP+ cages
* 1000BASE-X via Xilinx PCS/PMA core and GTH transceiver
* 10GBASE-R MAC via GTH transceiver
## Board details
* FPGA: xcku040-ffva1156-2-e
* USB UART: Silicon Labs CP2105 SCI
* 1000BASE-T PHY: Marvell 88E1111 via SGMII
* 10GBASE-R PHY: Soft PCS with GTH transceiver
## Licensing
* Toolchain
* Vivado Enterprise (requires license)
* IP
* No licensed vendor IP or 3rd party IP
## How to build
Run `make` in the appropriate `fpga*` subdirectory to build the bitstream. Ensure that the Xilinx Vivado toolchain components are in PATH.
On the host system, run `make` in `modules/cndm` to build the driver. Ensure that the headers for the running kernel are installed, otherwise the driver cannot be compiled.
## How to test
Run `make program` to program the board with Vivado. Then, reboot the machine to re-enumerate the PCIe bus. Finally, load the driver on the host system with `insmod cndm.ko`. Check `dmesg` for output from driver initialization. Run `cndm_ddcmd.sh =p` to enable all debug messages.

View File

@@ -0,0 +1,153 @@
# SPDX-License-Identifier: MIT
###################################################################
#
# Xilinx Vivado FPGA Makefile
#
# Copyright (c) 2016-2025 Alex Forencich
#
###################################################################
#
# Parameters:
# FPGA_TOP - Top module name
# FPGA_FAMILY - FPGA family (e.g. VirtexUltrascale)
# FPGA_DEVICE - FPGA device (e.g. xcvu095-ffva2104-2-e)
# SYN_FILES - list of source files
# INC_FILES - list of include files
# XDC_FILES - list of timing constraint files
# XCI_FILES - list of IP XCI files
# IP_TCL_FILES - list of IP TCL files (sourced during project creation)
# CONFIG_TCL_FILES - list of config TCL files (sourced before each build)
#
# Note: both SYN_FILES and INC_FILES support file list files. File list
# files are files with a .f extension that contain a list of additional
# files to include, one path relative to the .f file location per line.
# The .f files are processed recursively, and then the complete file list
# is de-duplicated, with later files in the list taking precedence.
#
# Example:
#
# FPGA_TOP = fpga
# FPGA_FAMILY = VirtexUltrascale
# FPGA_DEVICE = xcvu095-ffva2104-2-e
# SYN_FILES = rtl/fpga.v
# XDC_FILES = fpga.xdc
# XCI_FILES = ip/pcspma.xci
# include ../common/vivado.mk
#
###################################################################
# phony targets
.PHONY: fpga vivado tmpclean clean distclean
# prevent make from deleting intermediate files and reports
.PRECIOUS: %.xpr %.bit %.bin %.ltx %.xsa %.mcs %.prm
.SECONDARY:
CONFIG ?= config.mk
-include $(CONFIG)
FPGA_TOP ?= fpga
PROJECT ?= $(FPGA_TOP)
XDC_FILES ?= $(PROJECT).xdc
# handle file list files
process_f_file = $(call process_f_files,$(addprefix $(dir $1),$(shell cat $1)))
process_f_files = $(foreach f,$1,$(if $(filter %.f,$f),$(call process_f_file,$f),$f))
uniq_base = $(if $1,$(call uniq_base,$(foreach f,$1,$(if $(filter-out $(notdir $(lastword $1)),$(notdir $f)),$f,))) $(lastword $1))
SYN_FILES := $(call uniq_base,$(call process_f_files,$(SYN_FILES)))
INC_FILES := $(call uniq_base,$(call process_f_files,$(INC_FILES)))
###################################################################
# Main Targets
#
# all: build everything (fpga)
# fpga: build FPGA config
# vivado: open project in Vivado
# tmpclean: remove intermediate files
# clean: remove output files and project files
# distclean: remove archived output files
###################################################################
all: fpga
fpga: $(PROJECT).bit
vivado: $(PROJECT).xpr
vivado $(PROJECT).xpr
tmpclean::
-rm -rf *.log *.jou *.cache *.gen *.hbs *.hw *.ip_user_files *.runs *.xpr *.html *.xml *.sim *.srcs *.str .Xil defines.v
-rm -rf create_project.tcl update_config.tcl run_synth.tcl run_impl.tcl generate_bit.tcl
clean:: tmpclean
-rm -rf *.bit *.bin *.ltx *.xsa program.tcl generate_mcs.tcl *.mcs *.prm flash.tcl
-rm -rf *_utilization.rpt *_utilization_hierarchical.rpt
distclean:: clean
-rm -rf rev
###################################################################
# Target implementations
###################################################################
# Vivado project file
# create fresh project if Makefile or IP files have changed
create_project.tcl: Makefile $(XCI_FILES) $(IP_TCL_FILES)
rm -rf defines.v
touch defines.v
for x in $(DEFS); do echo '`define' $$x >> defines.v; done
echo "create_project -force -part $(FPGA_PART) $(PROJECT)" > $@
echo "add_files -fileset sources_1 defines.v $(SYN_FILES)" >> $@
echo "set_property top $(FPGA_TOP) [current_fileset]" >> $@
echo "add_files -fileset constrs_1 $(XDC_FILES)" >> $@
for x in $(XCI_FILES); do echo "import_ip $$x" >> $@; done
for x in $(IP_TCL_FILES); do echo "source $$x" >> $@; done
for x in $(CONFIG_TCL_FILES); do echo "source $$x" >> $@; done
# source config TCL scripts if any source file has changed
update_config.tcl: $(CONFIG_TCL_FILES) $(SYN_FILES) $(INC_FILES) $(XDC_FILES)
echo "open_project -quiet $(PROJECT).xpr" > $@
for x in $(CONFIG_TCL_FILES); do echo "source $$x" >> $@; done
$(PROJECT).xpr: create_project.tcl update_config.tcl
vivado -nojournal -nolog -mode batch $(foreach x,$?,-source $x)
# synthesis run
$(PROJECT).runs/synth_1/$(PROJECT).dcp: create_project.tcl update_config.tcl $(SYN_FILES) $(INC_FILES) $(XDC_FILES) | $(PROJECT).xpr
echo "open_project $(PROJECT).xpr" > run_synth.tcl
echo "reset_run synth_1" >> run_synth.tcl
echo "launch_runs -jobs 4 synth_1" >> run_synth.tcl
echo "wait_on_run synth_1" >> run_synth.tcl
vivado -nojournal -nolog -mode batch -source run_synth.tcl
# implementation run
$(PROJECT).runs/impl_1/$(PROJECT)_routed.dcp: $(PROJECT).runs/synth_1/$(PROJECT).dcp
echo "open_project $(PROJECT).xpr" > run_impl.tcl
echo "reset_run impl_1" >> run_impl.tcl
echo "launch_runs -jobs 4 impl_1" >> run_impl.tcl
echo "wait_on_run impl_1" >> run_impl.tcl
echo "open_run impl_1" >> run_impl.tcl
echo "report_utilization -file $(PROJECT)_utilization.rpt" >> run_impl.tcl
echo "report_utilization -hierarchical -file $(PROJECT)_utilization_hierarchical.rpt" >> run_impl.tcl
vivado -nojournal -nolog -mode batch -source run_impl.tcl
# output files (including potentially bit, bin, ltx, and xsa)
$(PROJECT).bit $(PROJECT).bin $(PROJECT).ltx $(PROJECT).xsa: $(PROJECT).runs/impl_1/$(PROJECT)_routed.dcp
echo "open_project $(PROJECT).xpr" > generate_bit.tcl
echo "open_run impl_1" >> generate_bit.tcl
echo "write_bitstream -force -bin_file $(PROJECT).runs/impl_1/$(PROJECT).bit" >> generate_bit.tcl
echo "write_debug_probes -force $(PROJECT).runs/impl_1/$(PROJECT).ltx" >> generate_bit.tcl
echo "write_hw_platform -fixed -force -include_bit $(PROJECT).xsa" >> generate_bit.tcl
vivado -nojournal -nolog -mode batch -source generate_bit.tcl
ln -f -s $(PROJECT).runs/impl_1/$(PROJECT).bit .
ln -f -s $(PROJECT).runs/impl_1/$(PROJECT).bin .
if [ -e $(PROJECT).runs/impl_1/$(PROJECT).ltx ]; then ln -f -s $(PROJECT).runs/impl_1/$(PROJECT).ltx .; fi
mkdir -p rev
COUNT=100; \
while [ -e rev/$(PROJECT)_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
cp -pv $(PROJECT).runs/impl_1/$(PROJECT).bit rev/$(PROJECT)_rev$$COUNT.bit; \
cp -pv $(PROJECT).runs/impl_1/$(PROJECT).bin rev/$(PROJECT)_rev$$COUNT.bin; \
if [ -e $(PROJECT).runs/impl_1/$(PROJECT).ltx ]; then cp -pv $(PROJECT).runs/impl_1/$(PROJECT).ltx rev/$(PROJECT)_rev$$COUNT.ltx; fi; \
if [ -e $(PROJECT).xsa ]; then cp -pv $(PROJECT).xsa rev/$(PROJECT)_rev$$COUNT.xsa; fi

View File

@@ -0,0 +1,625 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
# XDC constraints for the Xilinx KCU105 board
# part: xcku040-ffva1156-2-e
# General configuration
set_property CFGBVS GND [current_design]
set_property CONFIG_VOLTAGE 1.8 [current_design]
set_property BITSTREAM.GENERAL.COMPRESS true [current_design]
set_property BITSTREAM.CONFIG.EXTMASTERCCLK_EN {DIV-1} [current_design]
set_property BITSTREAM.CONFIG.SPI_32BIT_ADDR YES [current_design]
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 8 [current_design]
set_property BITSTREAM.CONFIG.SPI_FALL_EDGE YES [current_design]
set_property BITSTREAM.CONFIG.UNUSEDPIN Pullup [current_design]
set_property BITSTREAM.CONFIG.OVERTEMPSHUTDOWN Enable [current_design]
# System clocks
# 300 MHz system clock
#set_property -dict {LOC AK17 IOSTANDARD DIFF_SSTL12} [get_ports clk_300mhz_p] ;# from U122 Si5335
#set_property -dict {LOC AK16 IOSTANDARD DIFF_SSTL12} [get_ports clk_300mhz_n] ;# from U122 Si5335
#create_clock -period 3.333 -name clk_300mhz [get_ports clk_300mhz_p]
# 125 MHz system clock
set_property -dict {LOC G10 IOSTANDARD LVDS} [get_ports clk_125mhz_p] ;# from U122 Si5335
set_property -dict {LOC F10 IOSTANDARD LVDS} [get_ports clk_125mhz_n] ;# from U122 Si5335
create_clock -period 8.000 -name clk_125mhz [get_ports clk_125mhz_p]
# Si570 user clock (156.25 MHz default)
#set_property -dict {LOC M25 IOSTANDARD LVDS_25} [get_ports clk_user_p] ;# from U122 Si5335
#set_property -dict {LOC M26 IOSTANDARD LVDS_25} [get_ports clk_user_n] ;# from U122 Si5335
#create_clock -period 6.400 -name clk_user [get_ports clk_user_p]
# 90 MHz
#set_property -dict {LOC K20 IOSTANDARD LVCMOS18} [get_ports clk_90mhz] ;# from U122 Si5335
#create_clock -period 11.111 -name clk_90mhz [get_ports clk_90mhz]
# User SMA clock J34/J35
#set_property -dict {LOC D23 IOSTANDARD LVDS} [get_ports clk_user_sma_p] ;# J34
#set_property -dict {LOC C23 IOSTANDARD LVDS} [get_ports clk_user_sma_n] ;# J35
#create_clock -period 10.000 -name clk_user_sma [get_ports clk_user_sma_p]
# User SMA GPIO J36/J37
#set_property -dict {LOC H27 IOSTANDARD LVDS} [get_ports user_sma_gpio_p] ;# J36
#set_property -dict {LOC G27 IOSTANDARD LVDS} [get_ports user_sma_gpio_n] ;# J37
# LEDs
set_property -dict {LOC AP8 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {led[0]}] ;# to DS7
set_property -dict {LOC H23 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {led[1]}] ;# to DS6
set_property -dict {LOC P20 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {led[2]}] ;# to DS8
set_property -dict {LOC P21 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {led[3]}] ;# to DS9
set_property -dict {LOC N22 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {led[4]}] ;# to DS10
set_property -dict {LOC M22 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {led[5]}] ;# to DS33
set_property -dict {LOC R23 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {led[6]}] ;# to DS32
set_property -dict {LOC P23 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {led[7]}] ;# to DS31
set_false_path -to [get_ports {led[*]}]
set_output_delay 0 [get_ports {led[*]}]
# Reset button
set_property -dict {LOC AN8 IOSTANDARD LVCMOS18} [get_ports reset] ;# from SW5
set_false_path -from [get_ports {reset}]
set_input_delay 0 [get_ports {reset}]
# Push buttons
set_property -dict {LOC AD10 IOSTANDARD LVCMOS18} [get_ports btnu] ;# from SW10
set_property -dict {LOC AF9 IOSTANDARD LVCMOS18} [get_ports btnl] ;# from SW6
set_property -dict {LOC AF8 IOSTANDARD LVCMOS18} [get_ports btnd] ;# from SW8
set_property -dict {LOC AE8 IOSTANDARD LVCMOS18} [get_ports btnr] ;# from SW9
set_property -dict {LOC AE10 IOSTANDARD LVCMOS18} [get_ports btnc] ;# from SW7
set_false_path -from [get_ports {btnu btnl btnd btnr btnc}]
set_input_delay 0 [get_ports {btnu btnl btnd btnr btnc}]
# DIP switches
set_property -dict {LOC AN16 IOSTANDARD LVCMOS12} [get_ports {sw[0]}] ;# from SW12.4
set_property -dict {LOC AN19 IOSTANDARD LVCMOS12} [get_ports {sw[1]}] ;# from SW12.3
set_property -dict {LOC AP18 IOSTANDARD LVCMOS12} [get_ports {sw[2]}] ;# from SW12.2
set_property -dict {LOC AN14 IOSTANDARD LVCMOS12} [get_ports {sw[3]}] ;# from SW12.1
set_false_path -from [get_ports {sw[*]}]
set_input_delay 0 [get_ports {sw[*]}]
# PMOD0
#set_property -dict {LOC AK25 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {pmod0[0]}] ;# J52.1
#set_property -dict {LOC AN21 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {pmod0[1]}] ;# J52.3
#set_property -dict {LOC AH18 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {pmod0[2]}] ;# J52.5
#set_property -dict {LOC AM19 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {pmod0[3]}] ;# J52.7
#set_property -dict {LOC AE26 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {pmod0[4]}] ;# J52.2
#set_property -dict {LOC AF25 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {pmod0[5]}] ;# J52.4
#set_property -dict {LOC AE21 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {pmod0[6]}] ;# J52.6
#set_property -dict {LOC AM17 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {pmod0[7]}] ;# J52.8
#set_false_path -to [get_ports {pmod0[*]}]
#set_output_delay 0 [get_ports {pmod0[*]}]
# PMOD1
#set_property -dict {LOC AL14 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {pmod1[0]}] ;# J53.1
#set_property -dict {LOC AM14 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {pmod1[1]}] ;# J53.3
#set_property -dict {LOC AP16 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {pmod1[2]}] ;# J53.5
#set_property -dict {LOC AP15 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {pmod1[3]}] ;# J53.7
#set_property -dict {LOC AM16 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {pmod1[4]}] ;# J53.2
#set_property -dict {LOC AM15 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {pmod1[5]}] ;# J53.4
#set_property -dict {LOC AN18 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {pmod1[6]}] ;# J53.6
#set_property -dict {LOC AN17 IOSTANDARD LVCMOS12 SLEW SLOW DRIVE 8} [get_ports {pmod1[7]}] ;# J53.8
#set_false_path -to [get_ports {pmod1[*]}]
#set_output_delay 0 [get_ports {pmod1[*]}]
# UART (U34 CP2105 SCI)
set_property -dict {LOC K26 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {uart_txd}] ;# U34.20 RXD_SCI_I
set_property -dict {LOC G25 IOSTANDARD LVCMOS18} [get_ports {uart_rxd}] ;# U34.21 TXD_SCI_O
set_property -dict {LOC L23 IOSTANDARD LVCMOS18} [get_ports {uart_rts}] ;# U34.19 RTS_SCI_O
set_property -dict {LOC K27 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {uart_cts}] ;# U34.18 CTS_SCI_I
set_false_path -to [get_ports {uart_txd uart_cts}]
set_output_delay 0 [get_ports {uart_txd uart_cts}]
set_false_path -from [get_ports {uart_rxd uart_rts}]
set_input_delay 0 [get_ports {uart_rxd uart_rts}]
# I2C interface
set_property -dict {LOC J24 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports i2c_scl]
set_property -dict {LOC J25 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports i2c_sda]
set_property -dict {LOC AP10 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports i2c_mux_reset]
set_false_path -to [get_ports {i2c_sda i2c_scl}]
set_output_delay 0 [get_ports {i2c_sda i2c_scl}]
set_false_path -from [get_ports {i2c_sda i2c_scl}]
set_input_delay 0 [get_ports {i2c_sda i2c_scl}]
# Gigabit Ethernet SGMII PHY
set_property -dict {LOC P24 IOSTANDARD DIFF_HSTL_I_18} [get_ports phy_sgmii_rx_p]
set_property -dict {LOC P25 IOSTANDARD DIFF_HSTL_I_18} [get_ports phy_sgmii_rx_n]
set_property -dict {LOC N24 IOSTANDARD DIFF_HSTL_I_18} [get_ports phy_sgmii_tx_p]
set_property -dict {LOC M24 IOSTANDARD DIFF_HSTL_I_18} [get_ports phy_sgmii_tx_n]
set_property -dict {LOC P26 IOSTANDARD LVDS_25} [get_ports phy_sgmii_clk_p]
set_property -dict {LOC N26 IOSTANDARD LVDS_25} [get_ports phy_sgmii_clk_n]
set_property -dict {LOC J23 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports phy_reset_n]
set_property -dict {LOC K25 IOSTANDARD LVCMOS18} [get_ports phy_int_n]
#set_property -dict {LOC H26 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports phy_mdio]
#set_property -dict {LOC L25 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports phy_mdc]
# 625 MHz ref clock from SGMII PHY
#create_clock -period 1.600 -name phy_sgmii_clk [get_ports phy_sgmii_clk_p]
set_false_path -to [get_ports {phy_reset_n}]
set_output_delay 0 [get_ports {phy_reset_n}]
set_false_path -from [get_ports {phy_int_n}]
set_input_delay 0 [get_ports {phy_int_n}]
#set_false_path -to [get_ports {phy_mdio phy_mdc}]
#set_output_delay 0 [get_ports {phy_mdio phy_mdc}]
#set_false_path -from [get_ports {phy_mdio}]
#set_input_delay 0 [get_ports {phy_mdio}]
# SFP+ interface
set_property -dict {LOC T2 } [get_ports {sfp_rx_p[0]}] ;# MGTYRXP2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2
set_property -dict {LOC T1 } [get_ports {sfp_rx_n[0]}] ;# MGTYRXN2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2
set_property -dict {LOC U4 } [get_ports {sfp_tx_p[0]}] ;# MGTYTXP2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2
set_property -dict {LOC U3 } [get_ports {sfp_tx_n[0]}] ;# MGTYTXN2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2
set_property -dict {LOC V2 } [get_ports {sfp_rx_p[1]}] ;# MGTYRXP1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2
set_property -dict {LOC V1 } [get_ports {sfp_rx_n[1]}] ;# MGTYRXN1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2
set_property -dict {LOC W4 } [get_ports {sfp_tx_p[1]}] ;# MGTYTXP1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2
set_property -dict {LOC W3 } [get_ports {sfp_tx_n[1]}] ;# MGTYTXN1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2
set_property -dict {LOC P6 } [get_ports sfp_mgt_refclk_0_p] ;# MGTREFCLK0P_227 from U32 Si570 via U104 Si53340
set_property -dict {LOC P5 } [get_ports sfp_mgt_refclk_0_n] ;# MGTREFCLK0N_227 from U32 Si570 via U104 Si53340
#set_property -dict {LOC M6 } [get_ports sfp_mgt_refclk_1_p] ;# MGTREFCLK1P_227 from U57 Si5328B
#set_property -dict {LOC M5 } [get_ports sfp_mgt_refclk_1_n] ;# MGTREFCLK1N_227 from U57 Si5328B
#set_property -dict {LOC AG11 IOSTANDARD LVDS} [get_ports sfp_recclk_p] ;# to U57 CKIN1 SI5328
#set_property -dict {LOC AH11 IOSTANDARD LVDS} [get_ports sfp_recclk_n] ;# to U57 CKIN1 SI5328
set_property -dict {LOC AL8 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {sfp_tx_disable_b[0]}]
set_property -dict {LOC K21 IOSTANDARD LVCMOS18} [get_ports {sfp_rx_los[0]}]
set_property -dict {LOC D28 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {sfp_tx_disable_b[1]}]
set_property -dict {LOC AM9 IOSTANDARD LVCMOS18} [get_ports {sfp_rx_los[1]}]
# 156.25 MHz MGT reference clock
create_clock -period 6.400 -name sfp_mgt_refclk_0 [get_ports sfp_mgt_refclk_0_p]
#create_clock -period 6.400 -name sfp_mgt_refclk_1 [get_ports sfp_mgt_refclk_1_p]
set_false_path -to [get_ports {sfp_tx_disable_b[*]}]
set_output_delay 0 [get_ports {sfp_tx_disable_b[*]}]
# PCIe Interface
set_property -dict {LOC AB2 } [get_ports {pcie_rx_p[0]}] ;# MGTHRXP3_225 GTHE3_CHANNEL_X0Y7 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AB1 } [get_ports {pcie_rx_n[0]}] ;# MGTHRXN3_225 GTHE3_CHANNEL_X0Y7 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AC4 } [get_ports {pcie_tx_p[0]}] ;# MGTHTXP3_225 GTHE3_CHANNEL_X0Y7 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AC3 } [get_ports {pcie_tx_n[0]}] ;# MGTHTXN3_225 GTHE3_CHANNEL_X0Y7 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AD2 } [get_ports {pcie_rx_p[1]}] ;# MGTHRXP2_225 GTHE3_CHANNEL_X0Y6 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AD1 } [get_ports {pcie_rx_n[1]}] ;# MGTHRXN2_225 GTHE3_CHANNEL_X0Y6 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AE4 } [get_ports {pcie_tx_p[1]}] ;# MGTHTXP2_225 GTHE3_CHANNEL_X0Y6 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AE3 } [get_ports {pcie_tx_n[1]}] ;# MGTHTXN2_225 GTHE3_CHANNEL_X0Y6 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AF2 } [get_ports {pcie_rx_p[2]}] ;# MGTHRXP1_225 GTHE3_CHANNEL_X0Y5 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AF1 } [get_ports {pcie_rx_n[2]}] ;# MGTHRXN1_225 GTHE3_CHANNEL_X0Y5 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AG4 } [get_ports {pcie_tx_p[2]}] ;# MGTHTXP1_225 GTHE3_CHANNEL_X0Y5 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AG3 } [get_ports {pcie_tx_n[2]}] ;# MGTHTXN1_225 GTHE3_CHANNEL_X0Y5 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AH2 } [get_ports {pcie_rx_p[3]}] ;# MGTHRXP0_225 GTHE3_CHANNEL_X0Y4 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AH1 } [get_ports {pcie_rx_n[3]}] ;# MGTHRXN0_225 GTHE3_CHANNEL_X0Y4 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AH6 } [get_ports {pcie_tx_p[3]}] ;# MGTHTXP0_225 GTHE3_CHANNEL_X0Y4 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AH5 } [get_ports {pcie_tx_n[3]}] ;# MGTHTXN0_225 GTHE3_CHANNEL_X0Y4 / GTHE3_COMMON_X0Y1
set_property -dict {LOC AJ4 } [get_ports {pcie_rx_p[4]}] ;# MGTHRXP3_224 GTHE3_CHANNEL_X0Y3 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AJ3 } [get_ports {pcie_rx_n[4]}] ;# MGTHRXN3_224 GTHE3_CHANNEL_X0Y3 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AK6 } [get_ports {pcie_tx_p[4]}] ;# MGTHTXP3_224 GTHE3_CHANNEL_X0Y3 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AK5 } [get_ports {pcie_tx_n[4]}] ;# MGTHTXN3_224 GTHE3_CHANNEL_X0Y3 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AK2 } [get_ports {pcie_rx_p[5]}] ;# MGTHRXP2_224 GTHE3_CHANNEL_X0Y2 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AK1 } [get_ports {pcie_rx_n[5]}] ;# MGTHRXN2_224 GTHE3_CHANNEL_X0Y2 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AL4 } [get_ports {pcie_tx_p[5]}] ;# MGTHTXP2_224 GTHE3_CHANNEL_X0Y2 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AL3 } [get_ports {pcie_tx_n[5]}] ;# MGTHTXN2_224 GTHE3_CHANNEL_X0Y2 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AM2 } [get_ports {pcie_rx_p[6]}] ;# MGTHRXP1_224 GTHE3_CHANNEL_X0Y1 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AM1 } [get_ports {pcie_rx_n[6]}] ;# MGTHRXN1_224 GTHE3_CHANNEL_X0Y1 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AM6 } [get_ports {pcie_tx_p[6]}] ;# MGTHTXP1_224 GTHE3_CHANNEL_X0Y1 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AM5 } [get_ports {pcie_tx_n[6]}] ;# MGTHTXN1_224 GTHE3_CHANNEL_X0Y1 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AP2 } [get_ports {pcie_rx_p[7]}] ;# MGTHRXP0_224 GTHE3_CHANNEL_X0Y0 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AP1 } [get_ports {pcie_rx_n[7]}] ;# MGTHRXN0_224 GTHE3_CHANNEL_X0Y0 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AN4 } [get_ports {pcie_tx_p[7]}] ;# MGTHTXP0_224 GTHE3_CHANNEL_X0Y0 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AN3 } [get_ports {pcie_tx_n[7]}] ;# MGTHTXN0_224 GTHE3_CHANNEL_X0Y0 / GTHE3_COMMON_X0Y0
set_property -dict {LOC AB6 } [get_ports pcie_refclk_p] ;# MGTREFCLK0P_225
set_property -dict {LOC AB5 } [get_ports pcie_refclk_n] ;# MGTREFCLK0N_225
set_property -dict {LOC K22 IOSTANDARD LVCMOS18 PULLUP true} [get_ports pcie_reset_n]
# 100 MHz MGT reference clock
create_clock -period 10 -name pcie_mgt_refclk [get_ports pcie_refclk_p]
set_false_path -from [get_ports {pcie_reset_n}]
set_input_delay 0 [get_ports {pcie_reset_n}]
# FMC interface
# FMC HPC J22
#set_property -dict {LOC H11 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[0]"] ;# J22.G9 LA00_P_CC
#set_property -dict {LOC G11 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[0]"] ;# J22.G10 LA00_N_CC
#set_property -dict {LOC G9 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[1]"] ;# J22.D8 LA01_P_CC
#set_property -dict {LOC F9 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[1]"] ;# J22.D9 LA01_N_CC
#set_property -dict {LOC K10 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[2]"] ;# J22.H7 LA02_P
#set_property -dict {LOC J10 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[2]"] ;# J22.H8 LA02_N
#set_property -dict {LOC A13 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[3]"] ;# J22.G12 LA03_P
#set_property -dict {LOC A12 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[3]"] ;# J22.G13 LA03_N
#set_property -dict {LOC L12 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[4]"] ;# J22.H10 LA04_P
#set_property -dict {LOC K12 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[4]"] ;# J22.H11 LA04_N
#set_property -dict {LOC L13 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[5]"] ;# J22.D11 LA05_P
#set_property -dict {LOC K13 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[5]"] ;# J22.D12 LA05_N
#set_property -dict {LOC D13 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[6]"] ;# J22.C10 LA06_P
#set_property -dict {LOC C13 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[6]"] ;# J22.C11 LA06_N
#set_property -dict {LOC F8 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[7]"] ;# J22.H13 LA07_P
#set_property -dict {LOC E8 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[7]"] ;# J22.H14 LA07_N
#set_property -dict {LOC J8 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[8]"] ;# J22.G12 LA08_P
#set_property -dict {LOC H8 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[8]"] ;# J22.G13 LA08_N
#set_property -dict {LOC J9 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[9]"] ;# J22.D14 LA09_P
#set_property -dict {LOC H9 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[9]"] ;# J22.D15 LA09_N
#set_property -dict {LOC L8 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[10]"] ;# J22.C14 LA10_P
#set_property -dict {LOC K8 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[10]"] ;# J22.C15 LA10_N
#set_property -dict {LOC K11 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[11]"] ;# J22.H16 LA11_P
#set_property -dict {LOC J11 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[11]"] ;# J22.H17 LA11_N
#set_property -dict {LOC E10 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[12]"] ;# J22.G15 LA12_P
#set_property -dict {LOC D10 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[12]"] ;# J22.G16 LA12_N
#set_property -dict {LOC D9 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[13]"] ;# J22.D17 LA13_P
#set_property -dict {LOC C9 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[13]"] ;# J22.D18 LA13_N
#set_property -dict {LOC B10 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[14]"] ;# J22.C18 LA14_P
#set_property -dict {LOC A10 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[14]"] ;# J22.C19 LA14_N
#set_property -dict {LOC D8 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[15]"] ;# J22.H19 LA15_P
#set_property -dict {LOC C8 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[15]"] ;# J22.H20 LA15_N
#set_property -dict {LOC B9 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[16]"] ;# J22.G18 LA16_P
#set_property -dict {LOC A9 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[16]"] ;# J22.G19 LA16_N
#set_property -dict {LOC D24 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[17]"] ;# J22.D20 LA17_P_CC
#set_property -dict {LOC C24 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[17]"] ;# J22.D21 LA17_N_CC
#set_property -dict {LOC E22 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[18]"] ;# J22.C22 LA18_P_CC
#set_property -dict {LOC E23 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[18]"] ;# J22.C23 LA18_N_CC
#set_property -dict {LOC C21 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[19]"] ;# J22.H22 LA19_P
#set_property -dict {LOC C22 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[19]"] ;# J22.H23 LA19_N
#set_property -dict {LOC B24 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[20]"] ;# J22.G21 LA20_P
#set_property -dict {LOC A24 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[20]"] ;# J22.G22 LA20_N
#set_property -dict {LOC F23 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[21]"] ;# J22.H25 LA21_P
#set_property -dict {LOC F24 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[21]"] ;# J22.H26 LA21_N
#set_property -dict {LOC G24 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[22]"] ;# J22.G24 LA22_P
#set_property -dict {LOC F25 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[22]"] ;# J22.G25 LA22_N
#set_property -dict {LOC G22 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[23]"] ;# J22.D23 LA23_P
#set_property -dict {LOC F22 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[23]"] ;# J22.D24 LA23_N
#set_property -dict {LOC E20 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[24]"] ;# J22.H28 LA24_P
#set_property -dict {LOC E21 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[24]"] ;# J22.H29 LA24_N
#set_property -dict {LOC D20 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[25]"] ;# J22.G27 LA25_P
#set_property -dict {LOC D21 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[25]"] ;# J22.G28 LA25_N
#set_property -dict {LOC G20 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[26]"] ;# J22.D26 LA26_P
#set_property -dict {LOC F20 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[26]"] ;# J22.D27 LA26_N
#set_property -dict {LOC H21 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[27]"] ;# J22.C26 LA27_P
#set_property -dict {LOC G21 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[27]"] ;# J22.C27 LA27_N
#set_property -dict {LOC B21 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[28]"] ;# J22.H31 LA28_P
#set_property -dict {LOC B22 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[28]"] ;# J22.H32 LA28_N
#set_property -dict {LOC B20 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[29]"] ;# J22.G30 LA29_P
#set_property -dict {LOC A20 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[29]"] ;# J22.G31 LA29_N
#set_property -dict {LOC C26 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[30]"] ;# J22.H34 LA30_P
#set_property -dict {LOC B26 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[30]"] ;# J22.H35 LA30_N
#set_property -dict {LOC B25 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[31]"] ;# J22.G33 LA31_P
#set_property -dict {LOC A25 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[31]"] ;# J22.G34 LA31_N
#set_property -dict {LOC E26 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[32]"] ;# J22.H37 LA32_P
#set_property -dict {LOC D26 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[32]"] ;# J22.H38 LA32_N
#set_property -dict {LOC A27 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_p[33]"] ;# J22.G36 LA33_P
#set_property -dict {LOC A28 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_la_n[33]"] ;# J22.G37 LA33_N
#set_property -dict {LOC G17 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[0]"] ;# J22.F4 HA00_P_CC
#set_property -dict {LOC G16 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[0]"] ;# J22.F5 HA00_N_CC
#set_property -dict {LOC E16 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[1]"] ;# J22.E2 HA01_P_CC
#set_property -dict {LOC D16 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[1]"] ;# J22.E3 HA01_N_CC
#set_property -dict {LOC H19 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[2]"] ;# J22.K7 HA02_P
#set_property -dict {LOC H18 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[2]"] ;# J22.K8 HA02_N
#set_property -dict {LOC G15 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[3]"] ;# J22.J6 HA03_P
#set_property -dict {LOC G14 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[3]"] ;# J22.J7 HA03_N
#set_property -dict {LOC G19 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[4]"] ;# J22.F7 HA04_P
#set_property -dict {LOC F19 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[4]"] ;# J22.F8 HA04_N
#set_property -dict {LOC J15 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[5]"] ;# J22.E6 HA05_P
#set_property -dict {LOC J14 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[5]"] ;# J22.E7 HA05_N
#set_property -dict {LOC L15 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[6]"] ;# J22.K10 HA06_P
#set_property -dict {LOC K15 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[6]"] ;# J22.K11 HA06_N
#set_property -dict {LOC L19 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[7]"] ;# J22.J9 HA07_P
#set_property -dict {LOC L18 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[7]"] ;# J22.J10 HA07_N
#set_property -dict {LOC K18 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[8]"] ;# J22.F10 HA08_P
#set_property -dict {LOC K17 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[8]"] ;# J22.F11 HA08_N
#set_property -dict {LOC F18 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[9]"] ;# J22.E9 HA09_P
#set_property -dict {LOC F17 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[9]"] ;# J22.E10 HA09_N
#set_property -dict {LOC H17 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[10]"] ;# J22.K13 HA10_P
#set_property -dict {LOC H16 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[10]"] ;# J22.K14 HA10_N
#set_property -dict {LOC J19 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[11]"] ;# J22.J12 HA11_P
#set_property -dict {LOC J18 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[11]"] ;# J22.J13 HA11_N
#set_property -dict {LOC K16 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[12]"] ;# J22.F13 HA12_P
#set_property -dict {LOC J16 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[12]"] ;# J22.F14 HA12_N
#set_property -dict {LOC B14 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[13]"] ;# J22.E12 HA13_P
#set_property -dict {LOC A14 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[13]"] ;# J22.E13 HA13_N
#set_property -dict {LOC F15 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[14]"] ;# J22.J15 HA14_P
#set_property -dict {LOC F14 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[14]"] ;# J22.J16 HA14_N
#set_property -dict {LOC D14 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[15]"] ;# J22.F14 HA15_P
#set_property -dict {LOC C14 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[15]"] ;# J22.F16 HA15_N
#set_property -dict {LOC A19 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[16]"] ;# J22.E15 HA16_P
#set_property -dict {LOC A18 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[16]"] ;# J22.E16 HA16_N
#set_property -dict {LOC E18 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[17]"] ;# J22.K16 HA17_P_CC
#set_property -dict {LOC E17 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[17]"] ;# J22.K17 HA17_N_CC
#set_property -dict {LOC B17 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[18]"] ;# J22.J18 HA18_P_CC
#set_property -dict {LOC B16 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[18]"] ;# J22.J19 HA18_N_CC
#set_property -dict {LOC D19 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[19]"] ;# J22.F19 HA19_P
#set_property -dict {LOC D18 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[19]"] ;# J22.F20 HA19_N
#set_property -dict {LOC C19 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[20]"] ;# J22.E18 HA20_P
#set_property -dict {LOC B19 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[20]"] ;# J22.E19 HA20_N
#set_property -dict {LOC E15 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[21]"] ;# J22.K19 HA21_P
#set_property -dict {LOC D15 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[21]"] ;# J22.K20 HA21_N
#set_property -dict {LOC C18 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[22]"] ;# J22.J21 HA22_P
#set_property -dict {LOC C17 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[22]"] ;# J22.J22 HA22_N
#set_property -dict {LOC B15 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_p[23]"] ;# J22.K22 HA23_P
#set_property -dict {LOC A15 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_ha_n[23]"] ;# J22.K23 HA23_N
#set_property -dict {LOC H12 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_clk0_m2c_p"] ;# J22.H4 CLK0_M2C_P
#set_property -dict {LOC G12 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_clk0_m2c_n"] ;# J22.H5 CLK0_M2C_N
#set_property -dict {LOC E25 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_clk1_m2c_p"] ;# J22.G2 CLK1_M2C_P
#set_property -dict {LOC D25 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_hpc_clk1_m2c_n"] ;# J22.G3 CLK1_M2C_N
#set_property -dict {LOC L27 IOSTANDARD LVCMOS18} [get_ports {fmc_hpc_pg_m2c}] ;# J22.F1 PG_M2C
#set_property -dict {LOC H24 IOSTANDARD LVCMOS18} [get_ports {fmc_hpc_prsnt_m2c_l}] ;# J22.H2 PRSNT_M2C_L
#set_property -dict {LOC F6} [get_ports {fmc_hpc_dp_c2m_p[0]}] ;# MGTHTXP0_228 GTHE3_CHANNEL_X0Y16 / GTHE3_COMMON_X0Y4 from J22.C2 DP0_C2M_P
#set_property -dict {LOC F5} [get_ports {fmc_hpc_dp_c2m_n[0]}] ;# MGTHTXN0_228 GTHE3_CHANNEL_X0Y16 / GTHE3_COMMON_X0Y4 from J22.C3 DP0_C2M_N
#set_property -dict {LOC E4} [get_ports {fmc_hpc_dp_m2c_p[0]}] ;# MGTHRXP0_228 GTHE3_CHANNEL_X0Y16 / GTHE3_COMMON_X0Y4 from J22.C6 DP0_M2C_P
#set_property -dict {LOC E3} [get_ports {fmc_hpc_dp_m2c_n[0]}] ;# MGTHRXN0_228 GTHE3_CHANNEL_X0Y16 / GTHE3_COMMON_X0Y4 from J22.C7 DP0_M2C_N
#set_property -dict {LOC D6} [get_ports {fmc_hpc_dp_c2m_p[1]}] ;# MGTHTXP1_228 GTHE3_CHANNEL_X0Y17 / GTHE3_COMMON_X0Y4 from J22.A22 DP1_C2M_P
#set_property -dict {LOC D5} [get_ports {fmc_hpc_dp_c2m_n[1]}] ;# MGTHTXN1_228 GTHE3_CHANNEL_X0Y17 / GTHE3_COMMON_X0Y4 from J22.A23 DP1_C2M_N
#set_property -dict {LOC D2} [get_ports {fmc_hpc_dp_m2c_p[1]}] ;# MGTHRXP1_228 GTHE3_CHANNEL_X0Y17 / GTHE3_COMMON_X0Y4 from J22.A2 DP1_M2C_P
#set_property -dict {LOC D1} [get_ports {fmc_hpc_dp_m2c_n[1]}] ;# MGTHRXN1_228 GTHE3_CHANNEL_X0Y17 / GTHE3_COMMON_X0Y4 from J22.A3 DP1_M2C_N
#set_property -dict {LOC C4} [get_ports {fmc_hpc_dp_c2m_p[2]}] ;# MGTHTXP2_228 GTHE3_CHANNEL_X0Y18 / GTHE3_COMMON_X0Y4 from J22.A26 DP2_C2M_P
#set_property -dict {LOC C3} [get_ports {fmc_hpc_dp_c2m_n[2]}] ;# MGTHTXN2_228 GTHE3_CHANNEL_X0Y18 / GTHE3_COMMON_X0Y4 from J22.A27 DP2_C2M_N
#set_property -dict {LOC B2} [get_ports {fmc_hpc_dp_m2c_p[2]}] ;# MGTHRXP2_228 GTHE3_CHANNEL_X0Y18 / GTHE3_COMMON_X0Y4 from J22.A6 DP2_M2C_P
#set_property -dict {LOC B1} [get_ports {fmc_hpc_dp_m2c_n[2]}] ;# MGTHRXN2_228 GTHE3_CHANNEL_X0Y18 / GTHE3_COMMON_X0Y4 from J22.A7 DP2_M2C_N
#set_property -dict {LOC B6} [get_ports {fmc_hpc_dp_c2m_p[3]}] ;# MGTHTXP3_228 GTHE3_CHANNEL_X0Y19 / GTHE3_COMMON_X0Y4 from J22.A30 DP3_C2M_P
#set_property -dict {LOC B5} [get_ports {fmc_hpc_dp_c2m_n[3]}] ;# MGTHTXN3_228 GTHE3_CHANNEL_X0Y19 / GTHE3_COMMON_X0Y4 from J22.A31 DP3_C2M_N
#set_property -dict {LOC A4} [get_ports {fmc_hpc_dp_m2c_p[3]}] ;# MGTHRXP3_228 GTHE3_CHANNEL_X0Y19 / GTHE3_COMMON_X0Y4 from J22.A10 DP3_M2C_P
#set_property -dict {LOC A3} [get_ports {fmc_hpc_dp_m2c_n[3]}] ;# MGTHRXN3_228 GTHE3_CHANNEL_X0Y19 / GTHE3_COMMON_X0Y4 from J22.A11 DP3_M2C_N
#set_property -dict {LOC K6 } [get_ports fmc_hpc_mgt_refclk_0_p] ;# MGTREFCLK0P_228 from J22.D4 GBTCLK0_M2C_P
#set_property -dict {LOC K5 } [get_ports fmc_hpc_mgt_refclk_0_n] ;# MGTREFCLK0N_228 from J22.D5 GBTCLK0_M2C_N
#set_property -dict {LOC H6 } [get_ports fmc_hpc_mgt_refclk_1_p] ;# MGTREFCLK1P_228 from J22.B20 GBTCLK1_M2C_P
#set_property -dict {LOC H5 } [get_ports fmc_hpc_mgt_refclk_1_n] ;# MGTREFCLK1N_228 from J22.B21 GBTCLK1_M2C_N
#set_property -dict {LOC N4} [get_ports {fmc_hpc_dp_c2m_p[4]}] ;# MGTHTXP0_227 GTHE3_CHANNEL_X0Y12 / GTHE3_COMMON_X0Y3 from J22.A34 DP4_C2M_P
#set_property -dict {LOC N3} [get_ports {fmc_hpc_dp_c2m_n[4]}] ;# MGTHTXN0_227 GTHE3_CHANNEL_X0Y12 / GTHE3_COMMON_X0Y3 from J22.A35 DP4_C2M_N
#set_property -dict {LOC M2} [get_ports {fmc_hpc_dp_m2c_p[4]}] ;# MGTHRXP0_227 GTHE3_CHANNEL_X0Y12 / GTHE3_COMMON_X0Y3 from J22.A14 DP4_M2C_P
#set_property -dict {LOC M1} [get_ports {fmc_hpc_dp_m2c_n[4]}] ;# MGTHRXN0_227 GTHE3_CHANNEL_X0Y12 / GTHE3_COMMON_X0Y3 from J22.A15 DP4_M2C_N
#set_property -dict {LOC J4} [get_ports {fmc_hpc_dp_c2m_p[5]}] ;# MGTHTXP2_227 GTHE3_CHANNEL_X0Y14 / GTHE3_COMMON_X0Y3 from J22.B36 DP5_C2M_P
#set_property -dict {LOC J3} [get_ports {fmc_hpc_dp_c2m_n[5]}] ;# MGTHTXN2_227 GTHE3_CHANNEL_X0Y14 / GTHE3_COMMON_X0Y3 from J22.B37 DP5_C2M_N
#set_property -dict {LOC H2} [get_ports {fmc_hpc_dp_m2c_p[5]}] ;# MGTHRXP2_227 GTHE3_CHANNEL_X0Y14 / GTHE3_COMMON_X0Y3 from J22.B16 DP5_M2C_P
#set_property -dict {LOC H1} [get_ports {fmc_hpc_dp_m2c_n[5]}] ;# MGTHRXN2_227 GTHE3_CHANNEL_X0Y14 / GTHE3_COMMON_X0Y3 from J22.B17 DP5_M2C_N
#set_property -dict {LOC L4} [get_ports {fmc_hpc_dp_c2m_p[6]}] ;# MGTHTXP1_227 GTHE3_CHANNEL_X0Y13 / GTHE3_COMMON_X0Y3 from J22.A38 DP6_C2M_P
#set_property -dict {LOC L3} [get_ports {fmc_hpc_dp_c2m_n[6]}] ;# MGTHTXN1_227 GTHE3_CHANNEL_X0Y13 / GTHE3_COMMON_X0Y3 from J22.A39 DP6_C2M_N
#set_property -dict {LOC K2} [get_ports {fmc_hpc_dp_m2c_p[6]}] ;# MGTHRXP1_227 GTHE3_CHANNEL_X0Y13 / GTHE3_COMMON_X0Y3 from J22.A18 DP6_M2C_P
#set_property -dict {LOC K1} [get_ports {fmc_hpc_dp_m2c_n[6]}] ;# MGTHRXN1_227 GTHE3_CHANNEL_X0Y13 / GTHE3_COMMON_X0Y3 from J22.A19 DP6_M2C_N
#set_property -dict {LOC G4} [get_ports {fmc_hpc_dp_c2m_p[7]}] ;# MGTHTXP3_227 GTHE3_CHANNEL_X0Y15 / GTHE3_COMMON_X0Y3 from J22.B32 DP7_C2M_P
#set_property -dict {LOC G3} [get_ports {fmc_hpc_dp_c2m_n[7]}] ;# MGTHTXN3_227 GTHE3_CHANNEL_X0Y15 / GTHE3_COMMON_X0Y3 from J22.B33 DP7_C2M_N
#set_property -dict {LOC F2} [get_ports {fmc_hpc_dp_m2c_p[7]}] ;# MGTHRXP3_227 GTHE3_CHANNEL_X0Y15 / GTHE3_COMMON_X0Y3 from J22.B12 DP7_M2C_P
#set_property -dict {LOC F1} [get_ports {fmc_hpc_dp_m2c_n[7]}] ;# MGTHRXN3_227 GTHE3_CHANNEL_X0Y15 / GTHE3_COMMON_X0Y3 from J22.B13 DP7_M2C_N
# reference clock
#create_clock -period 6.400 -name fmc_hpc_mgt_refclk_0 [get_ports fmc_hpc_mgt_refclk_0_p]
#create_clock -period 6.400 -name fmc_hpc_mgt_refclk_1 [get_ports fmc_hpc_mgt_refclk_1_p]
# FMC LPC J2
#set_property -dict {LOC W23 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[0]"] ;# J2.G9 LA00_P_CC
#set_property -dict {LOC W24 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[0]"] ;# J2.G10 LA00_N_CC
#set_property -dict {LOC W25 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[1]"] ;# J2.D8 LA01_P_CC
#set_property -dict {LOC Y25 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[1]"] ;# J2.D9 LA01_N_CC
#set_property -dict {LOC AA22 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[2]"] ;# J2.H7 LA02_P
#set_property -dict {LOC AB22 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[2]"] ;# J2.H8 LA02_N
#set_property -dict {LOC W28 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[3]"] ;# J2.G12 LA03_P
#set_property -dict {LOC Y28 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[3]"] ;# J2.G13 LA03_N
#set_property -dict {LOC U26 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[4]"] ;# J2.H10 LA04_P
#set_property -dict {LOC U27 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[4]"] ;# J2.H11 LA04_N
#set_property -dict {LOC V27 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[5]"] ;# J2.D11 LA05_P
#set_property -dict {LOC V28 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[5]"] ;# J2.D12 LA05_N
#set_property -dict {LOC V29 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[6]"] ;# J2.C10 LA06_P
#set_property -dict {LOC W29 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[6]"] ;# J2.C11 LA06_N
#set_property -dict {LOC V22 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[7]"] ;# J2.H13 LA07_P
#set_property -dict {LOC V23 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[7]"] ;# J2.H14 LA07_N
#set_property -dict {LOC U24 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[8]"] ;# J2.G12 LA08_P
#set_property -dict {LOC U25 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[8]"] ;# J2.G13 LA08_N
#set_property -dict {LOC V26 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[9]"] ;# J2.D14 LA09_P
#set_property -dict {LOC W26 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[9]"] ;# J2.D15 LA09_N
#set_property -dict {LOC T22 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[10]"] ;# J2.C14 LA10_P
#set_property -dict {LOC T23 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[10]"] ;# J2.C15 LA10_N
#set_property -dict {LOC V21 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[11]"] ;# J2.H16 LA11_P
#set_property -dict {LOC W21 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[11]"] ;# J2.H17 LA11_N
#set_property -dict {LOC AC22 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[12]"] ;# J2.G15 LA12_P
#set_property -dict {LOC AC23 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[12]"] ;# J2.G16 LA12_N
#set_property -dict {LOC AA20 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[13]"] ;# J2.D17 LA13_P
#set_property -dict {LOC AB20 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[13]"] ;# J2.D18 LA13_N
#set_property -dict {LOC U21 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[14]"] ;# J2.C18 LA14_P
#set_property -dict {LOC U22 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[14]"] ;# J2.C19 LA14_N
#set_property -dict {LOC AB25 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[15]"] ;# J2.H19 LA15_P
#set_property -dict {LOC AB26 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[15]"] ;# J2.H20 LA15_N
#set_property -dict {LOC AB21 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[16]"] ;# J2.G18 LA16_P
#set_property -dict {LOC AC21 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[16]"] ;# J2.G19 LA16_N
#set_property -dict {LOC AA32 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[17]"] ;# J2.D20 LA17_P_CC
#set_property -dict {LOC AB32 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[17]"] ;# J2.D21 LA17_N_CC
#set_property -dict {LOC AB30 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[18]"] ;# J2.C22 LA18_P_CC
#set_property -dict {LOC AB31 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[18]"] ;# J2.C23 LA18_N_CC
#set_property -dict {LOC AA29 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[19]"] ;# J2.H22 LA19_P
#set_property -dict {LOC AB29 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[19]"] ;# J2.H23 LA19_N
#set_property -dict {LOC AA34 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[20]"] ;# J2.G21 LA20_P
#set_property -dict {LOC AB34 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[20]"] ;# J2.G22 LA20_N
#set_property -dict {LOC AC33 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[21]"] ;# J2.H25 LA21_P
#set_property -dict {LOC AD33 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[21]"] ;# J2.H26 LA21_N
#set_property -dict {LOC AC34 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[22]"] ;# J2.G24 LA22_P
#set_property -dict {LOC AD34 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[22]"] ;# J2.G25 LA22_N
#set_property -dict {LOC AD30 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[23]"] ;# J2.D23 LA23_P
#set_property -dict {LOC AD31 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[23]"] ;# J2.D24 LA23_N
#set_property -dict {LOC AE32 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[24]"] ;# J2.H28 LA24_P
#set_property -dict {LOC AF32 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[24]"] ;# J2.H29 LA24_N
#set_property -dict {LOC AE33 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[25]"] ;# J2.G27 LA25_P
#set_property -dict {LOC AF34 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[25]"] ;# J2.G28 LA25_N
#set_property -dict {LOC AF33 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[26]"] ;# J2.D26 LA26_P
#set_property -dict {LOC AG34 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[26]"] ;# J2.D27 LA26_N
#set_property -dict {LOC AG31 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[27]"] ;# J2.C26 LA27_P
#set_property -dict {LOC AG32 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[27]"] ;# J2.C27 LA27_N
#set_property -dict {LOC V31 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[28]"] ;# J2.H31 LA28_P
#set_property -dict {LOC W31 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[28]"] ;# J2.H32 LA28_N
#set_property -dict {LOC U34 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[29]"] ;# J2.G30 LA29_P
#set_property -dict {LOC V34 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[29]"] ;# J2.G31 LA29_N
#set_property -dict {LOC Y31 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[30]"] ;# J2.H34 LA30_P
#set_property -dict {LOC Y32 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[30]"] ;# J2.H35 LA30_N
#set_property -dict {LOC V33 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[31]"] ;# J2.G33 LA31_P
#set_property -dict {LOC W34 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[31]"] ;# J2.G34 LA31_N
#set_property -dict {LOC W30 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[32]"] ;# J2.H37 LA32_P
#set_property -dict {LOC Y30 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[32]"] ;# J2.H38 LA32_N
#set_property -dict {LOC W33 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_p[33]"] ;# J2.G36 LA33_P
#set_property -dict {LOC Y33 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_la_n[33]"] ;# J2.G37 LA33_N
#set_property -dict {LOC AA24 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_clk0_m2c_p"] ;# J2.H4 CLK0_M2C_P
#set_property -dict {LOC AA25 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_clk0_m2c_n"] ;# J2.H5 CLK0_M2C_N
#set_property -dict {LOC AC31 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_clk1_m2c_p"] ;# J2.G2 CLK1_M2C_P
#set_property -dict {LOC AC32 IOSTANDARD LVDS DIFF_TERM TRUE} [get_ports "fmc_lpc_clk1_m2c_n"] ;# J2.G3 CLK1_M2C_N
#set_property -dict {LOC J26 IOSTANDARD LVCMOS18} [get_ports {fmc_lpc_prsnt_m2c_l}] ;# J2.H2 PRSNT_M2C_L
#set_property -dict {LOC AA4 } [get_ports {fmc_lpc_dp_c2m_p[0]}] ;# MGTHTXP0_226 GTHE3_CHANNEL_X0Y8 / GTHE3_COMMON_X0Y2 from J2.C2 DP0_C2M_P
#set_property -dict {LOC AA3 } [get_ports {fmc_lpc_dp_c2m_n[0]}] ;# MGTHTXN0_226 GTHE3_CHANNEL_X0Y8 / GTHE3_COMMON_X0Y2 from J2.C3 DP0_C2M_N
#set_property -dict {LOC Y2 } [get_ports {fmc_lpc_dp_m2c_p[0]}] ;# MGTHRXP0_226 GTHE3_CHANNEL_X0Y8 / GTHE3_COMMON_X0Y2 from J2.C6 DP0_M2C_P
#set_property -dict {LOC Y1 } [get_ports {fmc_lpc_dp_m2c_n[0]}] ;# MGTHRXN0_226 GTHE3_CHANNEL_X0Y8 / GTHE3_COMMON_X0Y2 from J2.C7 DP0_M2C_N
#set_property -dict {LOC T6 } [get_ports fmc_lpc_mgt_refclk_p] ;# MGTREFCLK1P_226 from J2.D4 GBTCLK0_M2C_P
#set_property -dict {LOC T5 } [get_ports fmc_lpc_mgt_refclk_n] ;# MGTREFCLK1N_226 from J2.D5 GBTCLK0_M2C_N
# reference clock
#create_clock -period 6.400 -name fmc_lpc_mgt_refclk [get_ports fmc_lpc_mgt_refclk_p]
# DDR4 C1
# 4x MT40A256M16GE-075E
#set_property -dict {LOC AE17 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[0]}]
#set_property -dict {LOC AH17 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[1]}]
#set_property -dict {LOC AE18 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[2]}]
#set_property -dict {LOC AJ15 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[3]}]
#set_property -dict {LOC AG16 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[4]}]
#set_property -dict {LOC AL17 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[5]}]
#set_property -dict {LOC AK18 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[6]}]
#set_property -dict {LOC AG17 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[7]}]
#set_property -dict {LOC AF18 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[8]}]
#set_property -dict {LOC AH19 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[9]}]
#set_property -dict {LOC AF15 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[10]}]
#set_property -dict {LOC AD19 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[11]}]
#set_property -dict {LOC AJ14 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[12]}]
#set_property -dict {LOC AG19 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[13]}]
#set_property -dict {LOC AD16 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[14]}]
#set_property -dict {LOC AG14 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[15]}]
#set_property -dict {LOC AF14 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[16]}]
#set_property -dict {LOC AF17 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_ba[0]}]
#set_property -dict {LOC AL15 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_ba[1]}]
#set_property -dict {LOC AG15 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_bg[0]}]
#set_property -dict {LOC AE16 IOSTANDARD DIFF_SSTL12_DCI} [get_ports {ddr4_c1_ck_t}]
#set_property -dict {LOC AE15 IOSTANDARD DIFF_SSTL12_DCI} [get_ports {ddr4_c1_ck_c}]
#set_property -dict {LOC AD15 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_cke}]
#set_property -dict {LOC AL19 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_cs_n}]
#set_property -dict {LOC AH14 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_act_n}]
#set_property -dict {LOC AJ18 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_odt}]
#set_property -dict {LOC AD18 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_par}]
#set_property -dict {LOC AL18 IOSTANDARD LVCMOS12 } [get_ports {ddr4_c1_reset_n}]
#set_property -dict {LOC AJ16 IOSTANDARD LVCMOS12 } [get_ports {ddr4_c1_alert_n}]
#set_property -dict {LOC AH16 IOSTANDARD LVCMOS12 } [get_ports {ddr4_c1_ten}]
#set_property -dict {LOC AE23 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[0]}] ;# U60.G2 DQL0
#set_property -dict {LOC AG20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[1]}] ;# U60.F7 DQL1
#set_property -dict {LOC AF22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[2]}] ;# U60.H3 DQL2
#set_property -dict {LOC AF20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[3]}] ;# U60.H7 DQL3
#set_property -dict {LOC AE22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[4]}] ;# U60.H2 DQL4
#set_property -dict {LOC AD20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[5]}] ;# U60.H8 DQL5
#set_property -dict {LOC AG22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[6]}] ;# U60.J3 DQL6
#set_property -dict {LOC AE20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[7]}] ;# U60.J7 DQL7
#set_property -dict {LOC AJ24 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[8]}] ;# U60.A3 DQU0
#set_property -dict {LOC AG24 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[9]}] ;# U60.B8 DQU1
#set_property -dict {LOC AJ23 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[10]}] ;# U60.C3 DQU2
#set_property -dict {LOC AF23 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[11]}] ;# U60.C7 DQU3
#set_property -dict {LOC AH23 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[12]}] ;# U60.C2 DQU4
#set_property -dict {LOC AF24 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[13]}] ;# U60.C8 DQU5
#set_property -dict {LOC AH22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[14]}] ;# U60.D3 DQU6
#set_property -dict {LOC AG25 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[15]}] ;# U60.D7 DQU7
#set_property -dict {LOC AG21 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_t[0]}] ;# U60.G3 DQSL_T
#set_property -dict {LOC AH21 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_c[0]}] ;# U60.F3 DQSL_C
#set_property -dict {LOC AH24 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_t[1]}] ;# U60.B7 DQSU_T
#set_property -dict {LOC AJ25 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_c[1]}] ;# U60.A7 DQSU_C
#set_property -dict {LOC AD21 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dm_dbi_n[0]}] ;# U60.E7 DML_B/DBIL_B
#set_property -dict {LOC AE25 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dm_dbi_n[1]}] ;# U60.E2 DMU_B/DBIU_B
#set_property -dict {LOC AL22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[16]}] ;# U61.G2 DQL0
#set_property -dict {LOC AL25 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[17]}] ;# U61.F7 DQL1
#set_property -dict {LOC AM20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[18]}] ;# U61.H3 DQL2
#set_property -dict {LOC AK23 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[19]}] ;# U61.H7 DQL3
#set_property -dict {LOC AK22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[20]}] ;# U61.H2 DQL4
#set_property -dict {LOC AL24 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[21]}] ;# U61.H8 DQL5
#set_property -dict {LOC AL20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[22]}] ;# U61.J3 DQL6
#set_property -dict {LOC AL23 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[23]}] ;# U61.J7 DQL7
#set_property -dict {LOC AM24 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[24]}] ;# U61.A3 DQU0
#set_property -dict {LOC AN23 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[25]}] ;# U61.B8 DQU1
#set_property -dict {LOC AN24 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[26]}] ;# U61.C3 DQU2
#set_property -dict {LOC AP23 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[27]}] ;# U61.C7 DQU3
#set_property -dict {LOC AP25 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[28]}] ;# U61.C2 DQU4
#set_property -dict {LOC AN22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[29]}] ;# U61.C8 DQU5
#set_property -dict {LOC AP24 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[30]}] ;# U61.D3 DQU6
#set_property -dict {LOC AM22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[31]}] ;# U61.D7 DQU7
#set_property -dict {LOC AJ20 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_t[2]}] ;# U61.G3 DQSL_T
#set_property -dict {LOC AK20 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_c[2]}] ;# U61.F3 DQSL_C
#set_property -dict {LOC AP20 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_t[3]}] ;# U61.B7 DQSU_T
#set_property -dict {LOC AP21 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_c[3]}] ;# U61.A7 DQSU_C
#set_property -dict {LOC AJ21 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dm_dbi_n[2]}] ;# U61.E7 DML_B/DBIL_B
#set_property -dict {LOC AM21 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dm_dbi_n[3]}] ;# U61.E2 DMU_B/DBIU_B
#set_property -dict {LOC AH28 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[32]}] ;# U62.G2 DQL0
#set_property -dict {LOC AK26 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[33]}] ;# U62.F7 DQL1
#set_property -dict {LOC AK28 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[34]}] ;# U62.H3 DQL2
#set_property -dict {LOC AM27 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[35]}] ;# U62.H7 DQL3
#set_property -dict {LOC AJ28 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[36]}] ;# U62.H2 DQL4
#set_property -dict {LOC AH27 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[37]}] ;# U62.H8 DQL5
#set_property -dict {LOC AK27 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[38]}] ;# U62.J3 DQL6
#set_property -dict {LOC AM26 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[39]}] ;# U62.J7 DQL7
#set_property -dict {LOC AL30 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[40]}] ;# U62.A3 DQU0
#set_property -dict {LOC AP29 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[41]}] ;# U62.B8 DQU1
#set_property -dict {LOC AM30 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[42]}] ;# U62.C3 DQU2
#set_property -dict {LOC AN28 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[43]}] ;# U62.C7 DQU3
#set_property -dict {LOC AL29 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[44]}] ;# U62.C2 DQU4
#set_property -dict {LOC AP28 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[45]}] ;# U62.C8 DQU5
#set_property -dict {LOC AM29 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[46]}] ;# U62.D3 DQU6
#set_property -dict {LOC AN27 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[47]}] ;# U62.D7 DQU7
#set_property -dict {LOC AL27 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_t[4]}] ;# U62.G3 DQSL_T
#set_property -dict {LOC AL28 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_c[4]}] ;# U62.F3 DQSL_C
#set_property -dict {LOC AN29 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_t[5]}] ;# U62.B7 DQSU_T
#set_property -dict {LOC AP30 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_c[5]}] ;# U62.A7 DQSU_C
#set_property -dict {LOC AH26 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dm_dbi_n[4]}] ;# U62.E7 DML_B/DBIL_B
#set_property -dict {LOC AN26 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dm_dbi_n[5]}] ;# U62.E2 DMU_B/DBIU_B
#set_property -dict {LOC AH31 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[48]}] ;# U63.G2 DQL0
#set_property -dict {LOC AH32 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[49]}] ;# U63.F7 DQL1
#set_property -dict {LOC AJ34 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[50]}] ;# U63.H3 DQL2
#set_property -dict {LOC AK31 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[51]}] ;# U63.H7 DQL3
#set_property -dict {LOC AJ31 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[52]}] ;# U63.H2 DQL4
#set_property -dict {LOC AJ30 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[53]}] ;# U63.H8 DQL5
#set_property -dict {LOC AH34 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[54]}] ;# U63.J3 DQL6
#set_property -dict {LOC AK32 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[55]}] ;# U63.J7 DQL7
#set_property -dict {LOC AN33 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[56]}] ;# U63.A3 DQU0
#set_property -dict {LOC AP33 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[57]}] ;# U63.B8 DQU1
#set_property -dict {LOC AM34 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[58]}] ;# U63.C3 DQU2
#set_property -dict {LOC AP31 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[59]}] ;# U63.C7 DQU3
#set_property -dict {LOC AM32 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[60]}] ;# U63.C2 DQU4
#set_property -dict {LOC AN31 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[61]}] ;# U63.C8 DQU5
#set_property -dict {LOC AL34 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[62]}] ;# U63.D3 DQU6
#set_property -dict {LOC AN32 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[63]}] ;# U63.D7 DQU7
#set_property -dict {LOC AH33 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_t[6]}] ;# U63.G3 DQSL_T
#set_property -dict {LOC AJ33 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_c[6]}] ;# U63.F3 DQSL_C
#set_property -dict {LOC AN34 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_t[7]}] ;# U63.B7 DQSU_T
#set_property -dict {LOC AP34 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_c[7]}] ;# U63.A7 DQSU_C
#set_property -dict {LOC AJ29 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dm_dbi_n[6]}] ;# U63.E7 DML_B/DBIL_B
#set_property -dict {LOC AL32 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dm_dbi_n[7]}] ;# U63.E2 DMU_B/DBIU_B
# QSPI flash
set_property -dict {LOC M20 IOSTANDARD LVCMOS18 DRIVE 12} [get_ports {qspi_1_dq[0]}]
set_property -dict {LOC L20 IOSTANDARD LVCMOS18 DRIVE 12} [get_ports {qspi_1_dq[1]}]
set_property -dict {LOC R21 IOSTANDARD LVCMOS18 DRIVE 12} [get_ports {qspi_1_dq[2]}]
set_property -dict {LOC R22 IOSTANDARD LVCMOS18 DRIVE 12} [get_ports {qspi_1_dq[3]}]
set_property -dict {LOC G26 IOSTANDARD LVCMOS18 DRIVE 12} [get_ports {qspi_1_cs}]
set_false_path -to [get_ports {qspi_1_dq[*] qspi_1_cs}]
set_output_delay 0 [get_ports {qspi_1_dq[*] qspi_1_cs}]
set_false_path -from [get_ports {qspi_1_dq}]
set_input_delay 0 [get_ports {qspi_1_dq}]

View File

@@ -0,0 +1,64 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
# FPGA settings
FPGA_PART = xcku040-ffva1156-2-e
FPGA_TOP = fpga
FPGA_ARCH = kintexu
RTL_DIR = ../rtl
LIB_DIR = ../lib
TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
# Files for synthesis
SYN_FILES = $(RTL_DIR)/fpga.sv
SYN_FILES += $(RTL_DIR)/fpga_core.sv
SYN_FILES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_micro_pcie_us.f
SYN_FILES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_brd_ctrl_i2c.f
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/taxi_eth_mac_1g_fifo.f
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_if_uart.f
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_switch.sv
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_i2c_master.f
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_apb.f
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_stats.f
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv
SYN_FILES += $(TAXI_SRC_DIR)/io/rtl/taxi_debounce_switch.sv
SYN_FILES += $(TAXI_SRC_DIR)/pyrite/rtl/pyrite_pcie_us_vsec_qspi.f
# XDC files
XDC_FILES = ../fpga.xdc
XDC_FILES += $(TAXI_SRC_DIR)/eth/syn/vivado/taxi_eth_mac_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/axis/syn/vivado/taxi_axis_async_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_leaf.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_phc_regs.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_rel2tod.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_reset.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_signal.tcl
# IP
IP_TCL_FILES = ../ip/sgmii_pcs_pma_0.tcl
IP_TCL_FILES += ../ip/pcie3_ultrascale_0.tcl
IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_phy_10g_us_gth_156.tcl
# Configuration
CONFIG_TCL_FILES = ./config.tcl
include ../common/vivado.mk
program: $(PROJECT).bit
echo "open_hw_manager" > program.tcl
echo "connect_hw_server" >> program.tcl
echo "open_hw_target" >> program.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> program.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> program.tcl
echo "set_property PROGRAM.FILE {$(PROJECT).bit} [current_hw_device]" >> program.tcl
echo "program_hw_devices [current_hw_device]" >> program.tcl
echo "exit" >> program.tcl
vivado -nojournal -nolog -mode batch -source program.tcl

View File

@@ -0,0 +1,131 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025-2026 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
set params [dict create]
# collect build information
set build_date [clock seconds]
set git_hash 00000000
set git_tag ""
if { [catch {set git_hash [exec git rev-parse --short=8 HEAD]}] } {
puts "Error running git or project not under version control"
}
if { [catch {set git_tag [exec git describe --tags HEAD]}] } {
puts "Error running git, project not under version control, or no tag found"
}
puts "Build date: ${build_date}"
puts "Git hash: ${git_hash}"
puts "Git tag: ${git_tag}"
if { ! [regsub {^.*(\d+\.\d+\.\d+([\.-]\d+)?).*$} $git_tag {\1} tag_ver ] } {
puts "Failed to extract version from git tag"
set tag_ver 0.0.1
}
puts "Tag version: ${tag_ver}"
# FW and board IDs
set fpga_id [expr 0x3822093]
set fw_id [expr 0x0000C001]
set fw_ver $tag_ver
set board_vendor_id [expr 0x10ee]
set board_device_id [expr 0x8069]
set board_ver 1.0
set release_info [expr 0x00000000]
# PCIe IDs
set pcie_vendor_id [expr 0x1234]
set pcie_device_id [expr 0xC001]
set pcie_class_code [expr 0x020000]
set pcie_revision_id [expr 0x00]
set pcie_subsystem_device_id $board_device_id
set pcie_subsystem_vendor_id $board_vendor_id
# FW ID
dict set params FPGA_ID [format "32'h%08x" $fpga_id]
dict set params FW_ID [format "32'h%08x" $fw_id]
dict set params FW_VER [format "32'h%03x%02x%03x" {*}[split $fw_ver .-] 0 0 0]
dict set params BOARD_ID [format "32'h%04x%04x" $board_vendor_id $board_device_id]
dict set params BOARD_VER [format "32'h%03x%02x%03x" {*}[split $board_ver .-] 0 0 0]
dict set params BUILD_DATE "32'd${build_date}"
dict set params GIT_HASH "32'h${git_hash}"
dict set params RELEASE_INFO [format "32'h%08x" $release_info]
# PTP configuration
dict set params PTP_TS_EN "1"
# AXI lite interface configuration (control)
dict set params AXIL_CTRL_DATA_W "32"
dict set params AXIL_CTRL_ADDR_W "24"
# MAC configuration
dict set params CFG_LOW_LATENCY "1"
dict set params COMBINED_MAC_PCS "1"
dict set params MAC_DATA_W "32"
# PCIe IP core settings
set pcie [get_ips pcie3_ultrascale_0]
# configure BAR settings
proc configure_bar {pcie pf bar aperture} {
set size_list {Bytes Kilobytes Megabytes Gigabytes Terabytes Petabytes Exabytes}
for { set i 0 } { $i < [llength $size_list] } { incr i } {
set scale [lindex $size_list $i]
if {$aperture > 0 && $aperture < ($i+1)*10} {
set size [expr 1 << $aperture - ($i*10)]
puts "${pcie} PF${pf} BAR${bar}: aperture ${aperture} bits ($size $scale)"
set pcie_config [dict create]
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_enabled" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_type" {Memory}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_64bit" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_prefetchable" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_scale" $scale
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_size" $size
set_property -dict $pcie_config $pcie
return
}
}
puts "${pcie} PF${pf} BAR${bar}: disabled"
set_property "CONFIG.pf${pf}_bar${bar}_enabled" {false} $pcie
}
# Control BAR (BAR 0)
configure_bar $pcie 0 0 [dict get $params AXIL_CTRL_ADDR_W]
# PCIe IP core configuration
set pcie_config [dict create]
# PCIe IDs
dict set pcie_config "CONFIG.vendor_id" [format "%04x" $pcie_vendor_id]
dict set pcie_config "CONFIG.PF0_DEVICE_ID" [format "%04x" $pcie_device_id]
dict set pcie_config "CONFIG.PF0_CLASS_CODE" [format "%06x" $pcie_class_code]
dict set pcie_config "CONFIG.PF0_REVISION_ID" [format "%02x" $pcie_revision_id]
dict set pcie_config "CONFIG.PF0_SUBSYSTEM_VENDOR_ID" [format "%04x" $pcie_subsystem_vendor_id]
dict set pcie_config "CONFIG.PF0_SUBSYSTEM_ID" [format "%04x" $pcie_subsystem_device_id]
# MSI
dict set pcie_config "CONFIG.pf0_msi_enabled" {true}
set_property -dict $pcie_config $pcie
# apply parameters to top-level
set param_list {}
dict for {name value} $params {
lappend param_list $name=$value
}
set_property generic $param_list [get_filesets sources_1]

View File

@@ -0,0 +1,29 @@
create_ip -name pcie3_ultrascale -vendor xilinx.com -library ip -module_name pcie3_ultrascale_0
set_property -dict [list \
CONFIG.PL_LINK_CAP_MAX_LINK_SPEED {8.0_GT/s} \
CONFIG.PL_LINK_CAP_MAX_LINK_WIDTH {X8} \
CONFIG.AXISTEN_IF_RC_STRADDLE {false} \
CONFIG.axisten_if_width {256_bit} \
CONFIG.extended_tag_field {true} \
CONFIG.pf0_dev_cap_max_payload {1024_bytes} \
CONFIG.axisten_freq {250} \
CONFIG.PF0_Use_Class_Code_Lookup_Assistant {false} \
CONFIG.pf0_class_code_base {02} \
CONFIG.pf0_class_code_sub {00} \
CONFIG.pf0_class_code_interface {00} \
CONFIG.PF0_DEVICE_ID {C001} \
CONFIG.PF0_SUBSYSTEM_ID {8069} \
CONFIG.PF0_SUBSYSTEM_VENDOR_ID {10ee} \
CONFIG.pf0_bar0_64bit {true} \
CONFIG.pf0_bar0_prefetchable {true} \
CONFIG.pf0_bar0_scale {Megabytes} \
CONFIG.pf0_bar0_size {16} \
CONFIG.pf0_msi_enabled {true} \
CONFIG.PF0_MSI_CAP_MULTIMSGCAP {32_vectors} \
CONFIG.en_msi_per_vec_masking {true} \
CONFIG.ext_pcie_cfg_space_enabled {true} \
CONFIG.vendor_id {1234} \
CONFIG.mode_selection {Advanced} \
] [get_ips pcie3_ultrascale_0]

View File

@@ -0,0 +1,17 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
create_ip -name gig_ethernet_pcs_pma -vendor xilinx.com -library ip -module_name sgmii_pcs_pma_0
set_property -dict [list \
CONFIG.Standard {SGMII} \
CONFIG.Physical_Interface {LVDS} \
CONFIG.Management_Interface {false} \
CONFIG.SupportLevel {Include_Shared_Logic_in_Core} \
CONFIG.LvdsRefClk {625} \
] [get_ips sgmii_pcs_pma_0]

View File

@@ -0,0 +1 @@
../../../../../../

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,77 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2020-2026 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
TOPLEVEL_LANG = verilog
SIM ?= verilator
WAVES ?= 0
COCOTB_HDL_TIMEUNIT = 1ns
COCOTB_HDL_TIMEPRECISION = 1ps
RTL_DIR = ../../rtl
LIB_DIR = ../../lib
TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
DUT = fpga_core
COCOTB_TEST_MODULES = test_$(DUT)
COCOTB_TOPLEVEL = test_$(DUT)
MODULE = $(COCOTB_TEST_MODULES)
TOPLEVEL = $(COCOTB_TOPLEVEL)
VERILOG_SOURCES += $(COCOTB_TOPLEVEL).sv
VERILOG_SOURCES += $(RTL_DIR)/$(DUT).sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_micro_pcie_us.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_brd_ctrl_i2c.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/eth/rtl/taxi_eth_mac_1g_fifo.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_if_uart.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_switch.sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_i2c_master.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_apb.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_stats.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/io/rtl/taxi_debounce_switch.sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/pyrite/rtl/pyrite_pcie_us_vsec_qspi.f
# handle file list files
process_f_file = $(call process_f_files,$(addprefix $(dir $1),$(shell cat $1)))
process_f_files = $(foreach f,$1,$(if $(filter %.f,$f),$(call process_f_file,$f),$f))
uniq_base = $(if $1,$(call uniq_base,$(foreach f,$1,$(if $(filter-out $(notdir $(lastword $1)),$(notdir $f)),$f,))) $(lastword $1))
VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES)))
# module parameters
export PARAM_SIM := "1'b1"
export PARAM_VENDOR := "\"XILINX\""
export PARAM_FAMILY := "\"kintexu\""
# PTP configuration
export PARAM_PTP_TS_EN := 1
# AXI lite interface configuration (control)
export PARAM_AXIL_CTRL_DATA_W := 32
export PARAM_AXIL_CTRL_ADDR_W := 24
# MAC configuration
export PARAM_CFG_LOW_LATENCY := 1
export PARAM_COMBINED_MAC_PCS := 1
export PARAM_MAC_DATA_W := "32"
ifeq ($(SIM), icarus)
PLUSARGS += -fst
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-P $(COCOTB_TOPLEVEL).$(subst PARAM_,,$(v))=$($(v)))
else ifeq ($(SIM), verilator)
COMPILE_ARGS += $(foreach v,$(filter PARAM_%,$(.VARIABLES)),-G$(subst PARAM_,,$(v))=$($(v)))
ifeq ($(WAVES), 1)
COMPILE_ARGS += --trace-fst
VERILATOR_TRACE = 1
endif
endif
include $(shell cocotb-config --makefiles)/Makefile.sim

View File

@@ -0,0 +1 @@
../../lib/taxi/src/eth/tb/baser.py

View File

@@ -0,0 +1 @@
../../lib/taxi/src/cndm/tb/cndm.py

View File

@@ -0,0 +1,586 @@
#!/usr/bin/env python
# SPDX-License-Identifier: MIT
"""
Copyright (c) 2020-2025 FPGA Ninja, LLC
Authors:
- Alex Forencich
"""
import logging
import os
import struct
import sys
import cocotb_test.simulator
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, FallingEdge, Timer
from cocotbext.axi import AxiStreamBus
from cocotbext.eth import GmiiFrame, GmiiSource, GmiiSink
from cocotbext.eth import XgmiiFrame
from cocotbext.uart import UartSource, UartSink
from cocotbext.i2c import I2cMemory
from cocotbext.pcie.core import RootComplex
from cocotbext.pcie.xilinx.us import UltraScalePcieDevice
try:
from baser import BaseRSerdesSource, BaseRSerdesSink
import cndm
except ImportError:
# attempt import from current directory
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
try:
from baser import BaseRSerdesSource, BaseRSerdesSink
import cndm
finally:
del sys.path[0]
class TB:
def __init__(self, dut, speed=1000e6):
self.dut = dut
self.log = logging.getLogger("cocotb.tb")
self.log.setLevel(logging.DEBUG)
# Clocks
cocotb.start_soon(Clock(dut.clk_125mhz, 8, units="ns").start())
# PCIe
self.rc = RootComplex()
self.rc.max_payload_size = 0x1 # 256 bytes
self.rc.max_read_request_size = 0x2 # 512 bytes
self.dev = UltraScalePcieDevice(
# configuration options
pcie_generation=3,
pcie_link_width=8,
user_clk_frequency=250e6,
alignment="dword",
rc_straddle=False,
pf_count=1,
max_payload_size=1024,
enable_client_tag=True,
enable_extended_tag=True,
enable_parity=False,
enable_rx_msg_interface=False,
enable_sriov=False,
enable_extended_configuration=False,
pf0_msi_enable=True,
pf0_msi_count=32,
pf1_msi_enable=False,
pf1_msi_count=1,
pf0_msix_enable=False,
pf0_msix_table_size=31,
pf0_msix_table_bir=4,
pf0_msix_table_offset=0x00000000,
pf0_msix_pba_bir=4,
pf0_msix_pba_offset=0x00008000,
pf1_msix_enable=False,
pf1_msix_table_size=0,
pf1_msix_table_bir=0,
pf1_msix_table_offset=0x00000000,
pf1_msix_pba_bir=0,
pf1_msix_pba_offset=0x00000000,
# signals
# Clock and Reset Interface
user_clk=dut.pcie_clk,
user_reset=dut.pcie_rst,
# user_lnk_up
# sys_clk
# sys_clk_gt
# sys_reset
# phy_rdy_out
# Requester reQuest Interface
rq_bus=AxiStreamBus.from_entity(dut.m_axis_pcie_rq),
pcie_rq_seq_num=dut.pcie_rq_seq_num,
pcie_rq_seq_num_vld=dut.pcie_rq_seq_num_vld,
# pcie_rq_tag
# pcie_rq_tag_av
# pcie_rq_tag_vld
# Requester Completion Interface
rc_bus=AxiStreamBus.from_entity(dut.s_axis_pcie_rc),
# Completer reQuest Interface
cq_bus=AxiStreamBus.from_entity(dut.s_axis_pcie_cq),
# pcie_cq_np_req
# pcie_cq_np_req_count
# Completer Completion Interface
cc_bus=AxiStreamBus.from_entity(dut.m_axis_pcie_cc),
# Transmit Flow Control Interface
# pcie_tfc_nph_av=dut.pcie_tfc_nph_av,
# pcie_tfc_npd_av=dut.pcie_tfc_npd_av,
# Configuration Management Interface
cfg_mgmt_addr=dut.cfg_mgmt_addr,
cfg_mgmt_write=dut.cfg_mgmt_write,
cfg_mgmt_write_data=dut.cfg_mgmt_write_data,
cfg_mgmt_byte_enable=dut.cfg_mgmt_byte_enable,
cfg_mgmt_read=dut.cfg_mgmt_read,
cfg_mgmt_read_data=dut.cfg_mgmt_read_data,
cfg_mgmt_read_write_done=dut.cfg_mgmt_read_write_done,
# cfg_mgmt_debug_access
# Configuration Status Interface
# cfg_phy_link_down
# cfg_phy_link_status
# cfg_negotiated_width
# cfg_current_speed
cfg_max_payload=dut.cfg_max_payload,
cfg_max_read_req=dut.cfg_max_read_req,
# cfg_function_status
# cfg_vf_status
# cfg_function_power_state
# cfg_vf_power_state
# cfg_link_power_state
# cfg_err_cor_out
# cfg_err_nonfatal_out
# cfg_err_fatal_out
# cfg_local_error_out
# cfg_local_error_valid
# cfg_rx_pm_state
# cfg_tx_pm_state
# cfg_ltssm_state
cfg_rcb_status=dut.cfg_rcb_status,
# cfg_obff_enable
# cfg_pl_status_change
# cfg_tph_requester_enable
# cfg_tph_st_mode
# cfg_vf_tph_requester_enable
# cfg_vf_tph_st_mode
# Configuration Received Message Interface
# cfg_msg_received
# cfg_msg_received_data
# cfg_msg_received_type
# Configuration Transmit Message Interface
# cfg_msg_transmit
# cfg_msg_transmit_type
# cfg_msg_transmit_data
# cfg_msg_transmit_done
# Configuration Flow Control Interface
cfg_fc_ph=dut.cfg_fc_ph,
cfg_fc_pd=dut.cfg_fc_pd,
cfg_fc_nph=dut.cfg_fc_nph,
cfg_fc_npd=dut.cfg_fc_npd,
cfg_fc_cplh=dut.cfg_fc_cplh,
cfg_fc_cpld=dut.cfg_fc_cpld,
cfg_fc_sel=dut.cfg_fc_sel,
# Configuration Control Interface
# cfg_hot_reset_in
# cfg_hot_reset_out
# cfg_config_space_enable
# cfg_dsn
# cfg_bus_number
# cfg_ds_port_number
# cfg_ds_bus_number
# cfg_ds_device_number
# cfg_ds_function_number
# cfg_power_state_change_ack
# cfg_power_state_change_interrupt
# cfg_err_cor_in=dut.status_error_cor,
# cfg_err_uncor_in=dut.status_error_uncor,
# cfg_flr_in_process
# cfg_flr_done
# cfg_vf_flr_in_process
# cfg_vf_flr_func_num
# cfg_vf_flr_done
# cfg_pm_aspm_l1_entry_reject
# cfg_pm_aspm_tx_l0s_entry_disable
# cfg_req_pm_transition_l23_ready
# cfg_link_training_enable
# Configuration Interrupt Controller Interface
# cfg_interrupt_int
# cfg_interrupt_sent
# cfg_interrupt_pending
cfg_interrupt_msi_enable=dut.cfg_interrupt_msi_enable,
# cfg_interrupt_msi_vf_enable=dut.cfg_interrupt_msi_vf_enable,
cfg_interrupt_msi_mmenable=dut.cfg_interrupt_msi_mmenable,
cfg_interrupt_msi_mask_update=dut.cfg_interrupt_msi_mask_update,
cfg_interrupt_msi_data=dut.cfg_interrupt_msi_data,
cfg_interrupt_msi_select=dut.cfg_interrupt_msi_select,
cfg_interrupt_msi_int=dut.cfg_interrupt_msi_int,
cfg_interrupt_msi_pending_status=dut.cfg_interrupt_msi_pending_status,
cfg_interrupt_msi_pending_status_data_enable=dut.cfg_interrupt_msi_pending_status_data_enable,
cfg_interrupt_msi_pending_status_function_num=dut.cfg_interrupt_msi_pending_status_function_num,
cfg_interrupt_msi_sent=dut.cfg_interrupt_msi_sent,
cfg_interrupt_msi_fail=dut.cfg_interrupt_msi_fail,
# cfg_interrupt_msix_enable=dut.cfg_interrupt_msix_enable,
# cfg_interrupt_msix_mask=dut.cfg_interrupt_msix_mask,
# cfg_interrupt_msix_vf_enable=dut.cfg_interrupt_msix_vf_enable,
# cfg_interrupt_msix_vf_mask=dut.cfg_interrupt_msix_vf_mask,
# cfg_interrupt_msix_address=dut.cfg_interrupt_msix_address,
# cfg_interrupt_msix_data=dut.cfg_interrupt_msix_data,
# cfg_interrupt_msix_int=dut.cfg_interrupt_msix_int,
# cfg_interrupt_msix_sent=dut.cfg_interrupt_msix_sent,
# cfg_interrupt_msix_fail=dut.cfg_interrupt_msix_fail,
cfg_interrupt_msi_attr=dut.cfg_interrupt_msi_attr,
cfg_interrupt_msi_tph_present=dut.cfg_interrupt_msi_tph_present,
cfg_interrupt_msi_tph_type=dut.cfg_interrupt_msi_tph_type,
cfg_interrupt_msi_tph_st_tag=dut.cfg_interrupt_msi_tph_st_tag,
cfg_interrupt_msi_function_number=dut.cfg_interrupt_msi_function_number,
# Configuration Extend Interface
# cfg_ext_read_received
# cfg_ext_write_received
# cfg_ext_register_number
# cfg_ext_function_number
# cfg_ext_write_data
# cfg_ext_write_byte_enable
# cfg_ext_read_data
# cfg_ext_read_data_valid
)
# self.dev.log.setLevel(logging.DEBUG)
self.rc.make_port().connect(self.dev)
self.dev.functions[0].configure_bar(0, 2**int(dut.uut.cndm_inst.axil_ctrl_bar.ADDR_W))
# Ethernet
cocotb.start_soon(Clock(dut.phy_gmii_clk, 8, units="ns").start())
cocotb.start_soon(Clock(dut.sfp_mgt_refclk_0_p, 6.4, units="ns").start())
self.gmii_source = GmiiSource(dut.phy_gmii_rxd, dut.phy_gmii_rx_er, dut.phy_gmii_rx_dv,
dut.phy_gmii_clk, dut.phy_gmii_rst, dut.phy_gmii_clk_en)
self.gmii_sink = GmiiSink(dut.phy_gmii_txd, dut.phy_gmii_tx_er, dut.phy_gmii_tx_en,
dut.phy_gmii_clk, dut.phy_gmii_rst, dut.phy_gmii_clk_en)
self.sfp_sources = []
self.sfp_sinks = []
for ch in dut.uut.sfp_mac_inst.ch:
gt_inst = ch.ch_inst.gt.gt_inst
if ch.ch_inst.CFG_LOW_LATENCY.value:
clk = 3.102
gbx_cfg = (66, [64, 65])
else:
clk = 3.2
gbx_cfg = None
cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start())
cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start())
self.sfp_sources.append(BaseRSerdesSource(
data=gt_inst.serdes_rx_data,
data_valid=gt_inst.serdes_rx_data_valid,
hdr=gt_inst.serdes_rx_hdr,
hdr_valid=gt_inst.serdes_rx_hdr_valid,
clock=gt_inst.rx_clk,
slip=gt_inst.serdes_rx_bitslip,
reverse=True,
gbx_cfg=gbx_cfg
))
self.sfp_sinks.append(BaseRSerdesSink(
data=gt_inst.serdes_tx_data,
data_valid=gt_inst.serdes_tx_data_valid,
hdr=gt_inst.serdes_tx_hdr,
hdr_valid=gt_inst.serdes_tx_hdr_valid,
gbx_sync=gt_inst.serdes_tx_gbx_sync,
clock=gt_inst.tx_clk,
reverse=True,
gbx_cfg=gbx_cfg
))
# UART
self.uart_source = UartSource(dut.uart_rxd, baud=921600, bits=8, stop_bits=1)
self.uart_sink = UartSink(dut.uart_txd, baud=921600, bits=8, stop_bits=1)
# I2C
self.i2c_eeprom = I2cMemory(sda=dut.i2c_sda_o, sda_o=dut.i2c_sda_i,
scl=dut.i2c_scl_o, scl_o=dut.i2c_scl_i, addr=0x54, size=256)
self.sfp0 = I2cMemory(sda=dut.i2c_sda_o, sda_o=dut.i2c_sda_i,
scl=dut.i2c_scl_o, scl_o=dut.i2c_scl_i, addr=0x50, size=256)
self.si570 = I2cMemory(sda=dut.i2c_sda_o, sda_o=dut.i2c_sda_i,
scl=dut.i2c_scl_o, scl_o=dut.i2c_scl_i, addr=0x5D, size=256)
self.i2c_eeprom.write_mem(0, bytes.fromhex("""
37 35 37 35 31 39 32 37 31 37 33 32 2d 36 39 39
39 36 20 20 20 20 20 20 20 20 20 20 20 20 20 20
00 0a 35 03 72 c9 00 00 00 00 00 00 00 00 00 00
54 53 53 30 31 36 35 2d 30 32 20 20 20 20 20 20
5b 31 31 31 31 31 31 31 31 31 5d 20 20 20 20 20
57 65 64 2c 20 31 36 20 41 75 67 20 32 30 31 37
31 30 3a 33 35 3a 35 36 2b 30 38 30 30 20 20 20
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
4b 43 55 31 30 35 20 20 20 20 20 20 20 20 20 20
31 2e 31 20 20 20 20 20 20 20 20 20 20 20 20 20
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
"""))
self.sfp0.write_mem(0, bytes.fromhex("""
03 04 21 00 00 00 00 00 04 00 00 00 67 00 00 00
00 00 03 00 41 6d 70 68 65 6e 6f 6c 20 20 20 20
20 20 20 20 00 41 50 48 35 37 31 35 34 30 30 30
32 20 20 20 20 20 20 20 4b 20 20 20 01 00 00 f7
00 00 00 00 41 50 46 30 39 34 38 30 30 32 30 32
37 39 20 20 30 39 31 31 32 34 20 20 00 00 00 c1
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00
""" + " ff"*128))
self.si570.write_mem(0, bytes.fromhex("""
4f 02 32 a1 3d 20 00 01 c2 bb ff 84 82 07 c2 c0
00 00 00 00 c2 c0 00 00 00 07 c2 c0 00 00 00 0c
b9 09 80 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
20 7f 86 81 7b 81 03 00 10 08 00 00 00 00 02 bb
ff 84 82 00 00 00 62 00 00 00 00 00 00 00 00 00
"""))
dut.phy_gmii_clk_en.setimmediatevalue(1)
dut.btnu.setimmediatevalue(0)
dut.btnl.setimmediatevalue(0)
dut.btnd.setimmediatevalue(0)
dut.btnr.setimmediatevalue(0)
dut.btnc.setimmediatevalue(0)
dut.sw.setimmediatevalue(0)
dut.uart_rts.setimmediatevalue(0)
self.loopback_enable = False
cocotb.start_soon(self._run_loopback())
async def init(self):
self.dut.rst_125mhz.setimmediatevalue(0)
self.dut.phy_gmii_rst.setimmediatevalue(0)
await FallingEdge(self.dut.pcie_rst)
await Timer(100, 'ns')
for k in range(10):
await RisingEdge(self.dut.clk_125mhz)
self.dut.rst_125mhz.value = 1
self.dut.phy_gmii_rst.value = 1
for k in range(10):
await RisingEdge(self.dut.clk_125mhz)
self.dut.rst_125mhz.value = 0
self.dut.phy_gmii_rst.value = 0
for k in range(10):
await RisingEdge(self.dut.clk_125mhz)
await self.rc.enumerate()
async def _run_loopback(self):
while True:
await RisingEdge(self.dut.pcie_clk)
if self.loopback_enable:
for src, snk in zip(self.sfp_sources, self.sfp_sinks):
while not snk.empty():
await src.send(await snk.recv())
@cocotb.test()
async def run_test(dut):
tb = TB(dut)
await tb.init()
tb.log.info("Init driver model")
driver = cndm.Driver()
await driver.init_pcie_dev(tb.rc.find_device(tb.dev.functions[0].pcie_id))
tb.log.info("Init complete")
tb.log.info("Read MAC address")
rsp = await driver.exec_cmd(struct.pack("<HHLHHLbbbbLLL",
0, # rsvd
cndm.CNDM_CMD_OP_HWID, # opcode
0x00000000, # flags
0, # index
cndm.CNDM_CMD_BRD_OP_HWID_MAC_RD, # board op
0, # flags
0, # rsvd
0, # dev addr offset
0, # bank
0, # page
0, # addr
0, # len
0, # rsvd
))
print(rsp)
tb.log.info("MAC address: %s", ':'.join(x.hex() for x in struct.unpack_from('6c', rsp, 32+2)))
tb.log.info("Wait for block lock")
for k in range(1200):
await RisingEdge(tb.dut.clk_125mhz)
for snk in tb.sfp_sinks:
snk.clear()
tb.log.info("Send and receive single packet on each port")
for k in range(len(driver.ports)):
data = f"Corundum rocks on port {k}!".encode('ascii')
await driver.ports[k].start_xmit(data)
pkt = await tb.sfp_sinks[k].recv()
tb.log.info("Got TX packet: %s", pkt)
assert pkt.get_payload() == data.ljust(60, b'\x00')
assert pkt.check_fcs()
await tb.sfp_sources[k].send(pkt)
pkt = await driver.ports[k].recv()
tb.log.info("Got RX packet: %s", pkt)
assert bytes(pkt) == data.ljust(60, b'\x00')
tb.log.info("Multiple small packets")
count = 64
pkts = [bytearray([(x+k) % 256 for x in range(60)]) for k in range(count)]
tb.loopback_enable = True
for p in pkts:
await driver.ports[0].start_xmit(p)
for k in range(count):
pkt = await driver.ports[0].recv()
tb.log.info("Got RX packet: %s", pkt)
assert bytes(pkt) == pkts[k].ljust(60, b'\x00')
tb.loopback_enable = False
tb.log.info("Multiple large packets")
count = 64
pkts = [bytearray([(x+k) % 256 for x in range(1514)]) for k in range(count)]
tb.loopback_enable = True
for p in pkts:
await driver.ports[0].start_xmit(p)
for k in range(count):
pkt = await driver.ports[0].recv()
tb.log.info("Got RX packet: %s", pkt)
assert bytes(pkt) == pkts[k].ljust(60, b'\x00')
tb.loopback_enable = False
await RisingEdge(dut.clk_125mhz)
await RisingEdge(dut.clk_125mhz)
# cocotb-test
tests_dir = os.path.abspath(os.path.dirname(__file__))
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
lib_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'lib'))
taxi_src_dir = os.path.abspath(os.path.join(lib_dir, 'taxi', 'src'))
def process_f_files(files):
lst = {}
for f in files:
if f[-2:].lower() == '.f':
with open(f, 'r') as fp:
l = fp.read().split()
for f in process_f_files([os.path.join(os.path.dirname(f), x) for x in l]):
lst[os.path.basename(f)] = f
else:
lst[os.path.basename(f)] = f
return list(lst.values())
def test_fpga_core(request):
dut = "fpga_core"
module = os.path.splitext(os.path.basename(__file__))[0]
toplevel = module
verilog_sources = [
os.path.join(tests_dir, f"{toplevel}.sv"),
os.path.join(rtl_dir, f"{dut}.sv"),
os.path.join(taxi_src_dir, "cndm", "rtl", "cndm_micro_pcie_us.f"),
os.path.join(taxi_src_dir, "cndm", "rtl", "cndm_brd_ctrl_i2c.f"),
os.path.join(taxi_src_dir, "eth", "rtl", "taxi_eth_mac_1g_fifo.f"),
os.path.join(taxi_src_dir, "eth", "rtl", "us", "taxi_eth_mac_25g_us.f"),
os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_if_uart.f"),
os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_switch.sv"),
os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_mod_i2c_master.f"),
os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_mod_apb.f"),
os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_mod_stats.f"),
os.path.join(taxi_src_dir, "sync", "rtl", "taxi_sync_reset.sv"),
os.path.join(taxi_src_dir, "sync", "rtl", "taxi_sync_signal.sv"),
os.path.join(taxi_src_dir, "io", "rtl", "taxi_debounce_switch.sv"),
os.path.join(taxi_src_dir, "pyrite", "rtl", "pyrite_pcie_us_vsec_qspi.f"),
]
verilog_sources = process_f_files(verilog_sources)
parameters = {}
parameters['SIM'] = "1'b1"
parameters['VENDOR'] = "\"XILINX\""
parameters['FAMILY'] = "\"kintexu\""
# PTP configuration
parameters['PTP_TS_EN'] = 1
# AXI lite interface configuration (control)
parameters['AXIL_CTRL_DATA_W'] = 32
parameters['AXIL_CTRL_ADDR_W'] = 24
# MAC configuration
parameters['CFG_LOW_LATENCY'] = 1
parameters['COMBINED_MAC_PCS'] = 1
parameters['MAC_DATA_W'] = 32
extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()}
sim_build = os.path.join(tests_dir, "sim_build",
request.node.name.replace('[', '-').replace(']', ''))
cocotb_test.simulator.run(
simulator="verilator",
python_search=[tests_dir],
verilog_sources=verilog_sources,
toplevel=toplevel,
module=module,
parameters=parameters,
sim_build=sim_build,
extra_env=extra_env,
)

View File

@@ -0,0 +1,363 @@
// SPDX-License-Identifier: MIT
/*
Copyright (c) 2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA core logic testbench
*/
module test_fpga_core #
(
/* verilator lint_off WIDTHTRUNC */
parameter logic SIM = 1'b0,
parameter string VENDOR = "XILINX",
parameter string FAMILY = "kintexu",
// FW ID
parameter FPGA_ID = 32'h3822093,
parameter FW_ID = 32'h0000C001,
parameter FW_VER = 32'h000_01_000,
parameter BOARD_ID = 32'h10ee_8069,
parameter BOARD_VER = 32'h001_00_000,
parameter BUILD_DATE = 32'd602976000,
parameter GIT_HASH = 32'h5f87c2e8,
parameter RELEASE_INFO = 32'h00000000,
// PTP configuration
parameter logic PTP_TS_EN = 1'b1,
// PCIe interface configuration
parameter AXIS_PCIE_DATA_W = 256,
parameter AXIS_PCIE_RC_USER_W = 75,
parameter AXIS_PCIE_RQ_USER_W = 60,
parameter AXIS_PCIE_CQ_USER_W = 85,
parameter AXIS_PCIE_CC_USER_W = 33,
// AXI lite interface configuration (control)
parameter AXIL_CTRL_DATA_W = 32,
parameter AXIL_CTRL_ADDR_W = 24,
// MAC configuration
parameter logic CFG_LOW_LATENCY = 1'b1,
parameter logic COMBINED_MAC_PCS = 1'b1,
parameter MAC_DATA_W = 32
/* verilator lint_on WIDTHTRUNC */
)
();
localparam AXIS_PCIE_KEEP_W = (AXIS_PCIE_DATA_W/32);
localparam RQ_SEQ_NUM_W = AXIS_PCIE_RQ_USER_W == 60 ? 4 : 6;
logic clk_125mhz;
logic rst_125mhz;
logic btnu;
logic btnl;
logic btnd;
logic btnr;
logic btnc;
logic [3:0] sw;
logic [7:0] led;
logic uart_rxd;
logic uart_txd;
logic uart_rts;
logic uart_cts;
logic i2c_scl_i;
logic i2c_scl_o;
logic i2c_sda_i;
logic i2c_sda_o;
logic phy_gmii_clk;
logic phy_gmii_rst;
logic phy_gmii_clk_en;
logic [7:0] phy_gmii_rxd;
logic phy_gmii_rx_dv;
logic phy_gmii_rx_er;
logic [7:0] phy_gmii_txd;
logic phy_gmii_tx_en;
logic phy_gmii_tx_er;
logic phy_reset_n;
logic phy_int_n;
logic sfp_mgt_refclk_0_p;
logic sfp_mgt_refclk_0_n;
logic [1:0] sfp_tx_disable_b;
logic [1:0] sfp_rx_los;
logic pcie_clk;
logic pcie_rst;
taxi_axis_if #(
.DATA_W(AXIS_PCIE_DATA_W),
.KEEP_EN(1),
.KEEP_W(AXIS_PCIE_KEEP_W),
.USER_EN(1),
.USER_W(AXIS_PCIE_CQ_USER_W)
) s_axis_pcie_cq();
taxi_axis_if #(
.DATA_W(AXIS_PCIE_DATA_W),
.KEEP_EN(1),
.KEEP_W(AXIS_PCIE_KEEP_W),
.USER_EN(1),
.USER_W(AXIS_PCIE_CC_USER_W)
) m_axis_pcie_cc();
taxi_axis_if #(
.DATA_W(AXIS_PCIE_DATA_W),
.KEEP_EN(1),
.KEEP_W(AXIS_PCIE_KEEP_W),
.USER_EN(1),
.USER_W(AXIS_PCIE_RQ_USER_W)
) m_axis_pcie_rq();
taxi_axis_if #(
.DATA_W(AXIS_PCIE_DATA_W),
.KEEP_EN(1),
.KEEP_W(AXIS_PCIE_KEEP_W),
.USER_EN(1),
.USER_W(AXIS_PCIE_RC_USER_W)
) s_axis_pcie_rc();
logic [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num;
logic pcie_rq_seq_num_vld;
logic [2:0] cfg_max_payload;
logic [2:0] cfg_max_read_req;
logic [3:0] cfg_rcb_status;
logic [18:0] cfg_mgmt_addr;
logic cfg_mgmt_write;
logic [31:0] cfg_mgmt_write_data;
logic [3:0] cfg_mgmt_byte_enable;
logic cfg_mgmt_read;
logic [31:0] cfg_mgmt_read_data;
logic cfg_mgmt_read_write_done;
logic [7:0] cfg_fc_ph;
logic [11:0] cfg_fc_pd;
logic [7:0] cfg_fc_nph;
logic [11:0] cfg_fc_npd;
logic [7:0] cfg_fc_cplh;
logic [11:0] cfg_fc_cpld;
logic [2:0] cfg_fc_sel;
logic cfg_ext_read_received;
logic cfg_ext_write_received;
logic [9:0] cfg_ext_register_number;
logic [7:0] cfg_ext_function_number;
logic [31:0] cfg_ext_write_data;
logic [3:0] cfg_ext_write_byte_enable;
logic [31:0] cfg_ext_read_data;
logic cfg_ext_read_data_valid;
logic [3:0] cfg_interrupt_msi_enable;
logic [11:0] cfg_interrupt_msi_mmenable;
logic cfg_interrupt_msi_mask_update;
logic [31:0] cfg_interrupt_msi_data;
logic [3:0] cfg_interrupt_msi_select;
logic [31:0] cfg_interrupt_msi_int;
logic [31:0] cfg_interrupt_msi_pending_status;
logic cfg_interrupt_msi_pending_status_data_enable;
logic [3:0] cfg_interrupt_msi_pending_status_function_num;
logic cfg_interrupt_msi_sent;
logic cfg_interrupt_msi_fail;
logic [2:0] cfg_interrupt_msi_attr;
logic cfg_interrupt_msi_tph_present;
logic [1:0] cfg_interrupt_msi_tph_type;
logic [8:0] cfg_interrupt_msi_tph_st_tag;
logic [3:0] cfg_interrupt_msi_function_number;
logic fpga_boot;
logic qspi_clk;
logic [3:0] qspi_0_dq_i;
logic [3:0] qspi_0_dq_o;
logic [3:0] qspi_0_dq_oe;
logic qspi_0_cs;
logic [3:0] qspi_1_dq_i;
logic [3:0] qspi_1_dq_o;
logic [3:0] qspi_1_dq_oe;
logic qspi_1_cs;
fpga_core #(
.SIM(SIM),
.VENDOR(VENDOR),
.FAMILY(FAMILY),
// FW ID
.FPGA_ID(FPGA_ID),
.FW_ID(FW_ID),
.FW_VER(FW_VER),
.BOARD_ID(BOARD_ID),
.BOARD_VER(BOARD_VER),
.BUILD_DATE(BUILD_DATE),
.GIT_HASH(GIT_HASH),
.RELEASE_INFO(RELEASE_INFO),
// PTP configuration
.PTP_TS_EN(PTP_TS_EN),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),
// AXI lite interface configuration (control)
.AXIL_CTRL_DATA_W(AXIL_CTRL_DATA_W),
.AXIL_CTRL_ADDR_W(AXIL_CTRL_ADDR_W),
// MAC configuration
.CFG_LOW_LATENCY(CFG_LOW_LATENCY),
.COMBINED_MAC_PCS(COMBINED_MAC_PCS),
.MAC_DATA_W(MAC_DATA_W)
)
uut (
/*
* Clock: 125MHz
* Synchronous reset
*/
.clk_125mhz(clk_125mhz),
.rst_125mhz(rst_125mhz),
/*
* GPIO
*/
.btnu(btnu),
.btnl(btnl),
.btnd(btnd),
.btnr(btnr),
.btnc(btnc),
.sw(sw),
.led(led),
/*
* UART: 115200 bps, 8N1
*/
.uart_rxd(uart_rxd),
.uart_txd(uart_txd),
.uart_rts(uart_rts),
.uart_cts(uart_cts),
/*
* I2C
*/
.i2c_scl_i(i2c_scl_i),
.i2c_scl_o(i2c_scl_o),
.i2c_sda_i(i2c_sda_i),
.i2c_sda_o(i2c_sda_o),
/*
* Ethernet: 1000BASE-T SGMII
*/
.phy_gmii_clk(phy_gmii_clk),
.phy_gmii_rst(phy_gmii_rst),
.phy_gmii_clk_en(phy_gmii_clk_en),
.phy_gmii_rxd(phy_gmii_rxd),
.phy_gmii_rx_dv(phy_gmii_rx_dv),
.phy_gmii_rx_er(phy_gmii_rx_er),
.phy_gmii_txd(phy_gmii_txd),
.phy_gmii_tx_en(phy_gmii_tx_en),
.phy_gmii_tx_er(phy_gmii_tx_er),
.phy_reset_n(phy_reset_n),
.phy_int_n(phy_int_n),
/*
* Ethernet: SFP+
*/
.sfp_rx_p('{2{1'b0}}),
.sfp_rx_n('{2{1'b0}}),
.sfp_tx_p(),
.sfp_tx_n(),
.sfp_mgt_refclk_0_p(sfp_mgt_refclk_0_p),
.sfp_mgt_refclk_0_n(sfp_mgt_refclk_0_n),
.sfp_tx_disable_b(sfp_tx_disable_b),
.sfp_rx_los(sfp_rx_los),
/*
* PCIe
*/
.pcie_clk(pcie_clk),
.pcie_rst(pcie_rst),
.s_axis_pcie_cq(s_axis_pcie_cq),
.m_axis_pcie_cc(m_axis_pcie_cc),
.m_axis_pcie_rq(m_axis_pcie_rq),
.s_axis_pcie_rc(s_axis_pcie_rc),
.pcie_rq_seq_num(pcie_rq_seq_num),
.pcie_rq_seq_num_vld(pcie_rq_seq_num_vld),
.cfg_max_payload(cfg_max_payload),
.cfg_max_read_req(cfg_max_read_req),
.cfg_rcb_status(cfg_rcb_status),
.cfg_mgmt_addr(cfg_mgmt_addr),
.cfg_mgmt_write(cfg_mgmt_write),
.cfg_mgmt_write_data(cfg_mgmt_write_data),
.cfg_mgmt_byte_enable(cfg_mgmt_byte_enable),
.cfg_mgmt_read(cfg_mgmt_read),
.cfg_mgmt_read_data(cfg_mgmt_read_data),
.cfg_mgmt_read_write_done(cfg_mgmt_read_write_done),
.cfg_fc_ph(cfg_fc_ph),
.cfg_fc_pd(cfg_fc_pd),
.cfg_fc_nph(cfg_fc_nph),
.cfg_fc_npd(cfg_fc_npd),
.cfg_fc_cplh(cfg_fc_cplh),
.cfg_fc_cpld(cfg_fc_cpld),
.cfg_fc_sel(cfg_fc_sel),
.cfg_ext_read_received(cfg_ext_read_received),
.cfg_ext_write_received(cfg_ext_write_received),
.cfg_ext_register_number(cfg_ext_register_number),
.cfg_ext_function_number(cfg_ext_function_number),
.cfg_ext_write_data(cfg_ext_write_data),
.cfg_ext_write_byte_enable(cfg_ext_write_byte_enable),
.cfg_ext_read_data(cfg_ext_read_data),
.cfg_ext_read_data_valid(cfg_ext_read_data_valid),
.cfg_interrupt_msi_enable(cfg_interrupt_msi_enable),
.cfg_interrupt_msi_mmenable(cfg_interrupt_msi_mmenable),
.cfg_interrupt_msi_mask_update(cfg_interrupt_msi_mask_update),
.cfg_interrupt_msi_data(cfg_interrupt_msi_data),
.cfg_interrupt_msi_select(cfg_interrupt_msi_select),
.cfg_interrupt_msi_int(cfg_interrupt_msi_int),
.cfg_interrupt_msi_pending_status(cfg_interrupt_msi_pending_status),
.cfg_interrupt_msi_pending_status_data_enable(cfg_interrupt_msi_pending_status_data_enable),
.cfg_interrupt_msi_pending_status_function_num(cfg_interrupt_msi_pending_status_function_num),
.cfg_interrupt_msi_sent(cfg_interrupt_msi_sent),
.cfg_interrupt_msi_fail(cfg_interrupt_msi_fail),
.cfg_interrupt_msi_attr(cfg_interrupt_msi_attr),
.cfg_interrupt_msi_tph_present(cfg_interrupt_msi_tph_present),
.cfg_interrupt_msi_tph_type(cfg_interrupt_msi_tph_type),
.cfg_interrupt_msi_tph_st_tag(cfg_interrupt_msi_tph_st_tag),
.cfg_interrupt_msi_function_number(cfg_interrupt_msi_function_number),
/*
* QSPI flash
*/
.fpga_boot(fpga_boot),
.qspi_clk(qspi_clk),
.qspi_0_dq_i(qspi_0_dq_i),
.qspi_0_dq_o(qspi_0_dq_o),
.qspi_0_dq_oe(qspi_0_dq_oe),
.qspi_0_cs(qspi_0_cs),
.qspi_1_dq_i(qspi_1_dq_i),
.qspi_1_dq_o(qspi_1_dq_o),
.qspi_1_dq_oe(qspi_1_dq_oe),
.qspi_1_cs(qspi_1_cs)
);
endmodule
`resetall

View File

@@ -0,0 +1,52 @@
# Corundum for NT200A01/NT200A02
## Introduction
This design targets the Napatech NT200A01/NT200A02 FPGA board.
* QSFP28
* 10GBASE-R or 25GBASE-R MACs via GTY transceivers
## Board details
* FPGA
* NT200A01: xcvu095-ffva2104-2-e
* NT200A02: xcvu5p-flva2104-2-e
* PCIe: gen 3 x16 (~128 Gbps)
* Reference oscillator: 322.265625 MHz from Si5340
* 25GBASE-R PHY: Soft PCS with GTY transceivers
## Licensing
* Toolchain
* Vivado Enterprise (requires license)
* IP
* No licensed vendor IP or 3rd party IP
## How to build
Run `make` in the appropriate `fpga*` subdirectory to build the bitstream. Ensure that the Xilinx Vivado toolchain components are in PATH.
On the host system, run `make` in `modules/cndm` to build the driver. Ensure that the headers for the running kernel are installed, otherwise the driver cannot be compiled.
## How to test
Run `make program` to program the board with Vivado. Then, reboot the machine to re-enumerate the PCIe bus. Finally, load the driver on the host system with `insmod cndm.ko`. Check `dmesg` for output from driver initialization. Run `cndm_ddcmd.sh =p` to enable all debug messages.
## JTAG pinout
Napatech boards use a non-standard connector for JTAG. There are three debug connectors, and one of them carries the JTAG signals for the FPGA.
J16 J22
FPGA AVR
TDI 7 8 GND TDI 7 8 GND
TMS 5 6 HALT TMS 5 6
TDO 3 4 Vref TDO 3 4 Vref
TCK 1 2 GND TCK 1 2 GND
J17
GND 2 1
4 3
6 5
Note: J18.6 HALT must be driven low to access the JTAG chain. So, either tie to to ground, or connect it to the HALT signal on DLC9/DLC10 cables.

View File

@@ -0,0 +1,153 @@
# SPDX-License-Identifier: MIT
###################################################################
#
# Xilinx Vivado FPGA Makefile
#
# Copyright (c) 2016-2025 Alex Forencich
#
###################################################################
#
# Parameters:
# FPGA_TOP - Top module name
# FPGA_FAMILY - FPGA family (e.g. VirtexUltrascale)
# FPGA_DEVICE - FPGA device (e.g. xcvu095-ffva2104-2-e)
# SYN_FILES - list of source files
# INC_FILES - list of include files
# XDC_FILES - list of timing constraint files
# XCI_FILES - list of IP XCI files
# IP_TCL_FILES - list of IP TCL files (sourced during project creation)
# CONFIG_TCL_FILES - list of config TCL files (sourced before each build)
#
# Note: both SYN_FILES and INC_FILES support file list files. File list
# files are files with a .f extension that contain a list of additional
# files to include, one path relative to the .f file location per line.
# The .f files are processed recursively, and then the complete file list
# is de-duplicated, with later files in the list taking precedence.
#
# Example:
#
# FPGA_TOP = fpga
# FPGA_FAMILY = VirtexUltrascale
# FPGA_DEVICE = xcvu095-ffva2104-2-e
# SYN_FILES = rtl/fpga.v
# XDC_FILES = fpga.xdc
# XCI_FILES = ip/pcspma.xci
# include ../common/vivado.mk
#
###################################################################
# phony targets
.PHONY: fpga vivado tmpclean clean distclean
# prevent make from deleting intermediate files and reports
.PRECIOUS: %.xpr %.bit %.bin %.ltx %.xsa %.mcs %.prm
.SECONDARY:
CONFIG ?= config.mk
-include $(CONFIG)
FPGA_TOP ?= fpga
PROJECT ?= $(FPGA_TOP)
XDC_FILES ?= $(PROJECT).xdc
# handle file list files
process_f_file = $(call process_f_files,$(addprefix $(dir $1),$(shell cat $1)))
process_f_files = $(foreach f,$1,$(if $(filter %.f,$f),$(call process_f_file,$f),$f))
uniq_base = $(if $1,$(call uniq_base,$(foreach f,$1,$(if $(filter-out $(notdir $(lastword $1)),$(notdir $f)),$f,))) $(lastword $1))
SYN_FILES := $(call uniq_base,$(call process_f_files,$(SYN_FILES)))
INC_FILES := $(call uniq_base,$(call process_f_files,$(INC_FILES)))
###################################################################
# Main Targets
#
# all: build everything (fpga)
# fpga: build FPGA config
# vivado: open project in Vivado
# tmpclean: remove intermediate files
# clean: remove output files and project files
# distclean: remove archived output files
###################################################################
all: fpga
fpga: $(PROJECT).bit
vivado: $(PROJECT).xpr
vivado $(PROJECT).xpr
tmpclean::
-rm -rf *.log *.jou *.cache *.gen *.hbs *.hw *.ip_user_files *.runs *.xpr *.html *.xml *.sim *.srcs *.str .Xil defines.v
-rm -rf create_project.tcl update_config.tcl run_synth.tcl run_impl.tcl generate_bit.tcl
clean:: tmpclean
-rm -rf *.bit *.bin *.ltx *.xsa program.tcl generate_mcs.tcl *.mcs *.prm flash.tcl
-rm -rf *_utilization.rpt *_utilization_hierarchical.rpt
distclean:: clean
-rm -rf rev
###################################################################
# Target implementations
###################################################################
# Vivado project file
# create fresh project if Makefile or IP files have changed
create_project.tcl: Makefile $(XCI_FILES) $(IP_TCL_FILES)
rm -rf defines.v
touch defines.v
for x in $(DEFS); do echo '`define' $$x >> defines.v; done
echo "create_project -force -part $(FPGA_PART) $(PROJECT)" > $@
echo "add_files -fileset sources_1 defines.v $(SYN_FILES)" >> $@
echo "set_property top $(FPGA_TOP) [current_fileset]" >> $@
echo "add_files -fileset constrs_1 $(XDC_FILES)" >> $@
for x in $(XCI_FILES); do echo "import_ip $$x" >> $@; done
for x in $(IP_TCL_FILES); do echo "source $$x" >> $@; done
for x in $(CONFIG_TCL_FILES); do echo "source $$x" >> $@; done
# source config TCL scripts if any source file has changed
update_config.tcl: $(CONFIG_TCL_FILES) $(SYN_FILES) $(INC_FILES) $(XDC_FILES)
echo "open_project -quiet $(PROJECT).xpr" > $@
for x in $(CONFIG_TCL_FILES); do echo "source $$x" >> $@; done
$(PROJECT).xpr: create_project.tcl update_config.tcl
vivado -nojournal -nolog -mode batch $(foreach x,$?,-source $x)
# synthesis run
$(PROJECT).runs/synth_1/$(PROJECT).dcp: create_project.tcl update_config.tcl $(SYN_FILES) $(INC_FILES) $(XDC_FILES) | $(PROJECT).xpr
echo "open_project $(PROJECT).xpr" > run_synth.tcl
echo "reset_run synth_1" >> run_synth.tcl
echo "launch_runs -jobs 4 synth_1" >> run_synth.tcl
echo "wait_on_run synth_1" >> run_synth.tcl
vivado -nojournal -nolog -mode batch -source run_synth.tcl
# implementation run
$(PROJECT).runs/impl_1/$(PROJECT)_routed.dcp: $(PROJECT).runs/synth_1/$(PROJECT).dcp
echo "open_project $(PROJECT).xpr" > run_impl.tcl
echo "reset_run impl_1" >> run_impl.tcl
echo "launch_runs -jobs 4 impl_1" >> run_impl.tcl
echo "wait_on_run impl_1" >> run_impl.tcl
echo "open_run impl_1" >> run_impl.tcl
echo "report_utilization -file $(PROJECT)_utilization.rpt" >> run_impl.tcl
echo "report_utilization -hierarchical -file $(PROJECT)_utilization_hierarchical.rpt" >> run_impl.tcl
vivado -nojournal -nolog -mode batch -source run_impl.tcl
# output files (including potentially bit, bin, ltx, and xsa)
$(PROJECT).bit $(PROJECT).bin $(PROJECT).ltx $(PROJECT).xsa: $(PROJECT).runs/impl_1/$(PROJECT)_routed.dcp
echo "open_project $(PROJECT).xpr" > generate_bit.tcl
echo "open_run impl_1" >> generate_bit.tcl
echo "write_bitstream -force -bin_file $(PROJECT).runs/impl_1/$(PROJECT).bit" >> generate_bit.tcl
echo "write_debug_probes -force $(PROJECT).runs/impl_1/$(PROJECT).ltx" >> generate_bit.tcl
echo "write_hw_platform -fixed -force -include_bit $(PROJECT).xsa" >> generate_bit.tcl
vivado -nojournal -nolog -mode batch -source generate_bit.tcl
ln -f -s $(PROJECT).runs/impl_1/$(PROJECT).bit .
ln -f -s $(PROJECT).runs/impl_1/$(PROJECT).bin .
if [ -e $(PROJECT).runs/impl_1/$(PROJECT).ltx ]; then ln -f -s $(PROJECT).runs/impl_1/$(PROJECT).ltx .; fi
mkdir -p rev
COUNT=100; \
while [ -e rev/$(PROJECT)_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
cp -pv $(PROJECT).runs/impl_1/$(PROJECT).bit rev/$(PROJECT)_rev$$COUNT.bit; \
cp -pv $(PROJECT).runs/impl_1/$(PROJECT).bin rev/$(PROJECT)_rev$$COUNT.bin; \
if [ -e $(PROJECT).runs/impl_1/$(PROJECT).ltx ]; then cp -pv $(PROJECT).runs/impl_1/$(PROJECT).ltx rev/$(PROJECT)_rev$$COUNT.ltx; fi; \
if [ -e $(PROJECT).xsa ]; then cp -pv $(PROJECT).xsa rev/$(PROJECT)_rev$$COUNT.xsa; fi

View File

@@ -0,0 +1,163 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
# FPGA settings
FPGA_PART = xcvu095-ffva2104-2-e
FPGA_TOP = fpga
FPGA_ARCH = virtexu
RTL_DIR = ../rtl
LIB_DIR = ../lib
TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
# Files for synthesis
SYN_FILES = $(RTL_DIR)/fpga_nt200a01.sv
SYN_FILES += $(RTL_DIR)/fpga_core.sv
SYN_FILES += $(RTL_DIR)/../pll/si5340_i2c_init.sv
SYN_FILES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_micro_pcie_us.f
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
SYN_FILES += $(TAXI_SRC_DIR)/lss/rtl/taxi_i2c_master.sv
SYN_FILES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv
SYN_FILES += $(TAXI_SRC_DIR)/pyrite/rtl/pyrite_pcie_us_vsec_qspi.f
# XDC files
XDC_FILES = ../fpga_nt200a01.xdc
XDC_FILES += $(TAXI_SRC_DIR)/eth/syn/vivado/taxi_eth_mac_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/axis/syn/vivado/taxi_axis_async_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_leaf.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_phc_regs.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_rel2tod.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_reset.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_signal.tcl
# IP
IP_TCL_FILES = ../ip/pcie3_ultrascale_0.tcl
IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_322.tcl
# Configuration
CONFIG_TCL_FILES = config.tcl
include ../common/vivado.mk
%_fallback.bit: %.bit
echo "open_project $*.xpr" > generate_fallback_bit.tcl
echo "open_run impl_1" >> generate_fallback_bit.tcl
echo "startgroup" >> generate_fallback_bit.tcl
echo "set_property BITSTREAM.CONFIG.SPI_32BIT_ADDR NO [current_design]" >> generate_fallback_bit.tcl
echo "endgroup" >> generate_fallback_bit.tcl
echo "write_bitstream -verbose -force $*_fallback.bit" >> generate_fallback_bit.tcl
echo "undo" >> generate_fallback_bit.tcl
echo "exit" >> generate_fallback_bit.tcl
vivado -nojournal -nolog -mode batch -source generate_fallback_bit.tcl
mkdir -p rev
EXT=bit; COUNT=100; \
while [ -e rev/$*_rev$$COUNT.$$EXT ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
cp $@ rev/$*_fallback_rev$$COUNT.$$EXT; \
echo "Output: rev/$*_fallback_rev$$COUNT.$$EXT";
program: $(FPGA_TOP).bit
echo "open_hw_manager" > program.tcl
echo "connect_hw_server" >> program.tcl
echo "open_hw_target" >> program.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> program.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> program.tcl
echo "set_property PROGRAM.FILE {$(FPGA_TOP).bit} [current_hw_device]" >> program.tcl
echo "program_hw_devices [current_hw_device]" >> program.tcl
echo "exit" >> program.tcl
vivado -nojournal -nolog -mode batch -source program.tcl
%.mcs %.prm: %.bit
echo "write_cfgmem -force -format mcs -size 64 -interface SPIx4 -loadbit {up 0x00000000 $*.bit} -checksum -file $*.mcs" > generate_mcs.tcl
echo "exit" >> generate_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*$$x rev/$*_rev$$COUNT$$x; \
echo "Output: rev/$*_rev$$COUNT$$x"; done;
%_fallback.mcs %_fallback.prm: %_fallback.bit
echo "write_cfgmem -force -format mcs -size 64 -interface SPIx4 -loadbit {up 0x03000000 $*_fallback.bit} -checksum -file $*_fallback.mcs" > generate_fallback_mcs.tcl
echo "exit" >> generate_fallback_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_fallback_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*_fallback$$x rev/$*_fallback_rev$$COUNT$$x; \
echo "Output: rev/$*_fallback_rev$$COUNT$$x"; done;
%_full.mcs %_full.prm: %_fallback.bit %.bit
echo "write_cfgmem -force -format mcs -size 64 -interface SPIx4 -loadbit {up 0x00000000 $*.bit up 0x03000000 $*_fallback.bit} -checksum -file $*_full.mcs" > generate_full_mcs.tcl
echo "exit" >> generate_full_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_full_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*_full$$x rev/$*_full_rev$$COUNT$$x; \
echo "Output: rev/$*_full_rev$$COUNT$$x"; done;
flash: $(FPGA_TOP).mcs $(FPGA_TOP).prm
echo "open_hw_manager" > flash.tcl
echo "connect_hw_server" >> flash.tcl
echo "open_hw_target" >> flash.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> flash.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> flash.tcl
echo "create_hw_cfgmem -hw_device [current_hw_device] [lindex [get_cfgmem_parts {mt25ql512-spi-x1_x2_x4}] 0]" >> flash.tcl
echo "current_hw_cfgmem -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM [current_hw_device]]" >> flash.tcl
echo "set_property PROGRAM.FILES [list \"$(FPGA_TOP).mcs\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP).prm\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.ERASE 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.CFG_PROGRAM 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.VERIFY 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.CHECKSUM 0 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.ADDRESS_RANGE {use_file} [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [current_hw_cfgmem]" >> flash.tcl
echo "create_hw_bitstream -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM_BITFILE [current_hw_device]]" >> flash.tcl
echo "program_hw_devices [current_hw_device]" >> flash.tcl
echo "refresh_hw_device [current_hw_device]" >> flash.tcl
echo "program_hw_cfgmem -hw_cfgmem [current_hw_cfgmem]" >> flash.tcl
echo "boot_hw_device [current_hw_device]" >> flash.tcl
echo "exit" >> flash.tcl
vivado -nojournal -nolog -mode batch -source flash.tcl
flash%: $(FPGA_TOP)%.mcs $(FPGA_TOP)%.prm
echo "open_hw_manager" > flash$*.tcl
echo "connect_hw_server" >> flash$*.tcl
echo "open_hw_target" >> flash$*.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> flash$*.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> flash$*.tcl
echo "create_hw_cfgmem -hw_device [current_hw_device] [lindex [get_cfgmem_parts {mt25ql512-spi-x1_x2_x4}] 0]" >> flash$*.tcl
echo "current_hw_cfgmem -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM [current_hw_device]]" >> flash$*.tcl
echo "set_property PROGRAM.FILES [list \"$(FPGA_TOP)$*.mcs\"] [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP)$*.prm\"] [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.ERASE 1 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.CFG_PROGRAM 1 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.VERIFY 1 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.CHECKSUM 0 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.ADDRESS_RANGE {use_file} [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [current_hw_cfgmem]" >> flash$*.tcl
echo "create_hw_bitstream -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM_BITFILE [current_hw_device]]" >> flash$*.tcl
echo "program_hw_devices [current_hw_device]" >> flash$*.tcl
echo "refresh_hw_device [current_hw_device]" >> flash$*.tcl
echo "program_hw_cfgmem -hw_cfgmem [current_hw_cfgmem]" >> flash$*.tcl
echo "boot_hw_device [current_hw_device]" >> flash$*.tcl
echo "exit" >> flash$*.tcl
vivado -nojournal -nolog -mode batch -source flash$*.tcl

View File

@@ -0,0 +1,131 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025-2026 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
set params [dict create]
# collect build information
set build_date [clock seconds]
set git_hash 00000000
set git_tag ""
if { [catch {set git_hash [exec git rev-parse --short=8 HEAD]}] } {
puts "Error running git or project not under version control"
}
if { [catch {set git_tag [exec git describe --tags HEAD]}] } {
puts "Error running git, project not under version control, or no tag found"
}
puts "Build date: ${build_date}"
puts "Git hash: ${git_hash}"
puts "Git tag: ${git_tag}"
if { ! [regsub {^.*(\d+\.\d+\.\d+([\.-]\d+)?).*$} $git_tag {\1} tag_ver ] } {
puts "Failed to extract version from git tag"
set tag_ver 0.0.1
}
puts "Tag version: ${tag_ver}"
# FW and board IDs
set fpga_id [expr 0x3842093]
set fw_id [expr 0x0000C001]
set fw_ver $tag_ver
set board_vendor_id [expr 0x18f4]
set board_device_id [expr 0x01a5]
set board_ver 1.0
set release_info [expr 0x00000000]
# PCIe IDs
set pcie_vendor_id [expr 0x1234]
set pcie_device_id [expr 0xC001]
set pcie_class_code [expr 0x020000]
set pcie_revision_id [expr 0x00]
set pcie_subsystem_device_id $board_device_id
set pcie_subsystem_vendor_id $board_vendor_id
# FW ID
dict set params FPGA_ID [format "32'h%08x" $fpga_id]
dict set params FW_ID [format "32'h%08x" $fw_id]
dict set params FW_VER [format "32'h%03x%02x%03x" {*}[split $fw_ver .-] 0 0 0]
dict set params BOARD_ID [format "32'h%04x%04x" $board_vendor_id $board_device_id]
dict set params BOARD_VER [format "32'h%03x%02x%03x" {*}[split $board_ver .-] 0 0 0]
dict set params BUILD_DATE "32'd${build_date}"
dict set params GIT_HASH "32'h${git_hash}"
dict set params RELEASE_INFO [format "32'h%08x" $release_info]
# PTP configuration
dict set params PTP_TS_EN "1"
# AXI lite interface configuration (control)
dict set params AXIL_CTRL_DATA_W "32"
dict set params AXIL_CTRL_ADDR_W "24"
# MAC configuration
dict set params CFG_LOW_LATENCY "1"
dict set params COMBINED_MAC_PCS "1"
dict set params MAC_DATA_W "64"
# PCIe IP core settings
set pcie [get_ips pcie3_ultrascale_0]
# configure BAR settings
proc configure_bar {pcie pf bar aperture} {
set size_list {Bytes Kilobytes Megabytes Gigabytes Terabytes Petabytes Exabytes}
for { set i 0 } { $i < [llength $size_list] } { incr i } {
set scale [lindex $size_list $i]
if {$aperture > 0 && $aperture < ($i+1)*10} {
set size [expr 1 << $aperture - ($i*10)]
puts "${pcie} PF${pf} BAR${bar}: aperture ${aperture} bits ($size $scale)"
set pcie_config [dict create]
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_enabled" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_type" {Memory}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_64bit" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_prefetchable" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_scale" $scale
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_size" $size
set_property -dict $pcie_config $pcie
return
}
}
puts "${pcie} PF${pf} BAR${bar}: disabled"
set_property "CONFIG.pf${pf}_bar${bar}_enabled" {false} $pcie
}
# Control BAR (BAR 0)
configure_bar $pcie 0 0 [dict get $params AXIL_CTRL_ADDR_W]
# PCIe IP core configuration
set pcie_config [dict create]
# PCIe IDs
dict set pcie_config "CONFIG.vendor_id" [format "%04x" $pcie_vendor_id]
dict set pcie_config "CONFIG.PF0_DEVICE_ID" [format "%04x" $pcie_device_id]
dict set pcie_config "CONFIG.PF0_CLASS_CODE" [format "%06x" $pcie_class_code]
dict set pcie_config "CONFIG.PF0_REVISION_ID" [format "%02x" $pcie_revision_id]
dict set pcie_config "CONFIG.PF0_SUBSYSTEM_VENDOR_ID" [format "%04x" $pcie_subsystem_vendor_id]
dict set pcie_config "CONFIG.PF0_SUBSYSTEM_ID" [format "%04x" $pcie_subsystem_device_id]
# MSI
dict set pcie_config "CONFIG.pf0_msi_enabled" {true}
set_property -dict $pcie_config $pcie
# apply parameters to top-level
set param_list {}
dict for {name value} $params {
lappend param_list $name=$value
}
set_property generic $param_list [get_filesets sources_1]

View File

@@ -0,0 +1,163 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
# FPGA settings
FPGA_PART = xcvu095-ffva2104-2-e
FPGA_TOP = fpga
FPGA_ARCH = virtexu
RTL_DIR = ../rtl
LIB_DIR = ../lib
TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
# Files for synthesis
SYN_FILES = $(RTL_DIR)/fpga_nt200a01.sv
SYN_FILES += $(RTL_DIR)/fpga_core.sv
SYN_FILES += $(RTL_DIR)/../pll/si5340_i2c_init.sv
SYN_FILES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_micro_pcie_us.f
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
SYN_FILES += $(TAXI_SRC_DIR)/lss/rtl/taxi_i2c_master.sv
SYN_FILES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv
SYN_FILES += $(TAXI_SRC_DIR)/pyrite/rtl/pyrite_pcie_us_vsec_qspi.f
# XDC files
XDC_FILES = ../fpga_nt200a01.xdc
XDC_FILES += $(TAXI_SRC_DIR)/eth/syn/vivado/taxi_eth_mac_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/axis/syn/vivado/taxi_axis_async_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_leaf.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_phc_regs.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_rel2tod.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_reset.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_signal.tcl
# IP
IP_TCL_FILES = ../ip/pcie3_ultrascale_0.tcl
IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_phy_10g_us_gty_322.tcl
# Configuration
CONFIG_TCL_FILES = config.tcl
include ../common/vivado.mk
%_fallback.bit: %.bit
echo "open_project $*.xpr" > generate_fallback_bit.tcl
echo "open_run impl_1" >> generate_fallback_bit.tcl
echo "startgroup" >> generate_fallback_bit.tcl
echo "set_property BITSTREAM.CONFIG.SPI_32BIT_ADDR NO [current_design]" >> generate_fallback_bit.tcl
echo "endgroup" >> generate_fallback_bit.tcl
echo "write_bitstream -verbose -force $*_fallback.bit" >> generate_fallback_bit.tcl
echo "undo" >> generate_fallback_bit.tcl
echo "exit" >> generate_fallback_bit.tcl
vivado -nojournal -nolog -mode batch -source generate_fallback_bit.tcl
mkdir -p rev
EXT=bit; COUNT=100; \
while [ -e rev/$*_rev$$COUNT.$$EXT ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
cp $@ rev/$*_fallback_rev$$COUNT.$$EXT; \
echo "Output: rev/$*_fallback_rev$$COUNT.$$EXT";
program: $(FPGA_TOP).bit
echo "open_hw_manager" > program.tcl
echo "connect_hw_server" >> program.tcl
echo "open_hw_target" >> program.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> program.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> program.tcl
echo "set_property PROGRAM.FILE {$(FPGA_TOP).bit} [current_hw_device]" >> program.tcl
echo "program_hw_devices [current_hw_device]" >> program.tcl
echo "exit" >> program.tcl
vivado -nojournal -nolog -mode batch -source program.tcl
%.mcs %.prm: %.bit
echo "write_cfgmem -force -format mcs -size 64 -interface SPIx4 -loadbit {up 0x00000000 $*.bit} -checksum -file $*.mcs" > generate_mcs.tcl
echo "exit" >> generate_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*$$x rev/$*_rev$$COUNT$$x; \
echo "Output: rev/$*_rev$$COUNT$$x"; done;
%_fallback.mcs %_fallback.prm: %_fallback.bit
echo "write_cfgmem -force -format mcs -size 64 -interface SPIx4 -loadbit {up 0x03000000 $*_fallback.bit} -checksum -file $*_fallback.mcs" > generate_fallback_mcs.tcl
echo "exit" >> generate_fallback_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_fallback_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*_fallback$$x rev/$*_fallback_rev$$COUNT$$x; \
echo "Output: rev/$*_fallback_rev$$COUNT$$x"; done;
%_full.mcs %_full.prm: %_fallback.bit %.bit
echo "write_cfgmem -force -format mcs -size 64 -interface SPIx4 -loadbit {up 0x00000000 $*.bit up 0x03000000 $*_fallback.bit} -checksum -file $*_full.mcs" > generate_full_mcs.tcl
echo "exit" >> generate_full_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_full_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*_full$$x rev/$*_full_rev$$COUNT$$x; \
echo "Output: rev/$*_full_rev$$COUNT$$x"; done;
flash: $(FPGA_TOP).mcs $(FPGA_TOP).prm
echo "open_hw_manager" > flash.tcl
echo "connect_hw_server" >> flash.tcl
echo "open_hw_target" >> flash.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> flash.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> flash.tcl
echo "create_hw_cfgmem -hw_device [current_hw_device] [lindex [get_cfgmem_parts {mt25ql512-spi-x1_x2_x4}] 0]" >> flash.tcl
echo "current_hw_cfgmem -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM [current_hw_device]]" >> flash.tcl
echo "set_property PROGRAM.FILES [list \"$(FPGA_TOP).mcs\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP).prm\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.ERASE 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.CFG_PROGRAM 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.VERIFY 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.CHECKSUM 0 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.ADDRESS_RANGE {use_file} [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [current_hw_cfgmem]" >> flash.tcl
echo "create_hw_bitstream -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM_BITFILE [current_hw_device]]" >> flash.tcl
echo "program_hw_devices [current_hw_device]" >> flash.tcl
echo "refresh_hw_device [current_hw_device]" >> flash.tcl
echo "program_hw_cfgmem -hw_cfgmem [current_hw_cfgmem]" >> flash.tcl
echo "boot_hw_device [current_hw_device]" >> flash.tcl
echo "exit" >> flash.tcl
vivado -nojournal -nolog -mode batch -source flash.tcl
flash%: $(FPGA_TOP)%.mcs $(FPGA_TOP)%.prm
echo "open_hw_manager" > flash$*.tcl
echo "connect_hw_server" >> flash$*.tcl
echo "open_hw_target" >> flash$*.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> flash$*.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> flash$*.tcl
echo "create_hw_cfgmem -hw_device [current_hw_device] [lindex [get_cfgmem_parts {mt25ql512-spi-x1_x2_x4}] 0]" >> flash$*.tcl
echo "current_hw_cfgmem -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM [current_hw_device]]" >> flash$*.tcl
echo "set_property PROGRAM.FILES [list \"$(FPGA_TOP)$*.mcs\"] [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP)$*.prm\"] [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.ERASE 1 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.CFG_PROGRAM 1 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.VERIFY 1 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.CHECKSUM 0 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.ADDRESS_RANGE {use_file} [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [current_hw_cfgmem]" >> flash$*.tcl
echo "create_hw_bitstream -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM_BITFILE [current_hw_device]]" >> flash$*.tcl
echo "program_hw_devices [current_hw_device]" >> flash$*.tcl
echo "refresh_hw_device [current_hw_device]" >> flash$*.tcl
echo "program_hw_cfgmem -hw_cfgmem [current_hw_cfgmem]" >> flash$*.tcl
echo "boot_hw_device [current_hw_device]" >> flash$*.tcl
echo "exit" >> flash$*.tcl
vivado -nojournal -nolog -mode batch -source flash$*.tcl

View File

@@ -0,0 +1,131 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025-2026 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
set params [dict create]
# collect build information
set build_date [clock seconds]
set git_hash 00000000
set git_tag ""
if { [catch {set git_hash [exec git rev-parse --short=8 HEAD]}] } {
puts "Error running git or project not under version control"
}
if { [catch {set git_tag [exec git describe --tags HEAD]}] } {
puts "Error running git, project not under version control, or no tag found"
}
puts "Build date: ${build_date}"
puts "Git hash: ${git_hash}"
puts "Git tag: ${git_tag}"
if { ! [regsub {^.*(\d+\.\d+\.\d+([\.-]\d+)?).*$} $git_tag {\1} tag_ver ] } {
puts "Failed to extract version from git tag"
set tag_ver 0.0.1
}
puts "Tag version: ${tag_ver}"
# FW and board IDs
set fpga_id [expr 0x3842093]
set fw_id [expr 0x0000C001]
set fw_ver $tag_ver
set board_vendor_id [expr 0x18f4]
set board_device_id [expr 0x01a5]
set board_ver 1.0
set release_info [expr 0x00000000]
# PCIe IDs
set pcie_vendor_id [expr 0x1234]
set pcie_device_id [expr 0xC001]
set pcie_class_code [expr 0x020000]
set pcie_revision_id [expr 0x00]
set pcie_subsystem_device_id $board_device_id
set pcie_subsystem_vendor_id $board_vendor_id
# FW ID
dict set params FPGA_ID [format "32'h%08x" $fpga_id]
dict set params FW_ID [format "32'h%08x" $fw_id]
dict set params FW_VER [format "32'h%03x%02x%03x" {*}[split $fw_ver .-] 0 0 0]
dict set params BOARD_ID [format "32'h%04x%04x" $board_vendor_id $board_device_id]
dict set params BOARD_VER [format "32'h%03x%02x%03x" {*}[split $board_ver .-] 0 0 0]
dict set params BUILD_DATE "32'd${build_date}"
dict set params GIT_HASH "32'h${git_hash}"
dict set params RELEASE_INFO [format "32'h%08x" $release_info]
# PTP configuration
dict set params PTP_TS_EN "1"
# AXI lite interface configuration (control)
dict set params AXIL_CTRL_DATA_W "32"
dict set params AXIL_CTRL_ADDR_W "24"
# MAC configuration
dict set params CFG_LOW_LATENCY "1"
dict set params COMBINED_MAC_PCS "1"
dict set params MAC_DATA_W "32"
# PCIe IP core settings
set pcie [get_ips pcie3_ultrascale_0]
# configure BAR settings
proc configure_bar {pcie pf bar aperture} {
set size_list {Bytes Kilobytes Megabytes Gigabytes Terabytes Petabytes Exabytes}
for { set i 0 } { $i < [llength $size_list] } { incr i } {
set scale [lindex $size_list $i]
if {$aperture > 0 && $aperture < ($i+1)*10} {
set size [expr 1 << $aperture - ($i*10)]
puts "${pcie} PF${pf} BAR${bar}: aperture ${aperture} bits ($size $scale)"
set pcie_config [dict create]
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_enabled" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_type" {Memory}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_64bit" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_prefetchable" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_scale" $scale
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_size" $size
set_property -dict $pcie_config $pcie
return
}
}
puts "${pcie} PF${pf} BAR${bar}: disabled"
set_property "CONFIG.pf${pf}_bar${bar}_enabled" {false} $pcie
}
# Control BAR (BAR 0)
configure_bar $pcie 0 0 [dict get $params AXIL_CTRL_ADDR_W]
# PCIe IP core configuration
set pcie_config [dict create]
# PCIe IDs
dict set pcie_config "CONFIG.vendor_id" [format "%04x" $pcie_vendor_id]
dict set pcie_config "CONFIG.PF0_DEVICE_ID" [format "%04x" $pcie_device_id]
dict set pcie_config "CONFIG.PF0_CLASS_CODE" [format "%06x" $pcie_class_code]
dict set pcie_config "CONFIG.PF0_REVISION_ID" [format "%02x" $pcie_revision_id]
dict set pcie_config "CONFIG.PF0_SUBSYSTEM_VENDOR_ID" [format "%04x" $pcie_subsystem_vendor_id]
dict set pcie_config "CONFIG.PF0_SUBSYSTEM_ID" [format "%04x" $pcie_subsystem_device_id]
# MSI
dict set pcie_config "CONFIG.pf0_msi_enabled" {true}
set_property -dict $pcie_config $pcie
# apply parameters to top-level
set param_list {}
dict for {name value} $params {
lappend param_list $name=$value
}
set_property generic $param_list [get_filesets sources_1]

View File

@@ -0,0 +1,163 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
# FPGA settings
FPGA_PART = xcvu5p-flva2104-2-e
FPGA_TOP = fpga
FPGA_ARCH = virtexuplus
RTL_DIR = ../rtl
LIB_DIR = ../lib
TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
# Files for synthesis
SYN_FILES = $(RTL_DIR)/fpga_nt200a02.sv
SYN_FILES += $(RTL_DIR)/fpga_core.sv
SYN_FILES += $(RTL_DIR)/../pll/si5340_i2c_init.sv
SYN_FILES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_micro_pcie_us.f
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
SYN_FILES += $(TAXI_SRC_DIR)/lss/rtl/taxi_i2c_master.sv
SYN_FILES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv
SYN_FILES += $(TAXI_SRC_DIR)/pyrite/rtl/pyrite_pcie_us_vsec_qspi.f
# XDC files
XDC_FILES = ../fpga_nt200a02.xdc
XDC_FILES += $(TAXI_SRC_DIR)/eth/syn/vivado/taxi_eth_mac_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/axis/syn/vivado/taxi_axis_async_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_leaf.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_phc_regs.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_rel2tod.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_reset.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_signal.tcl
# IP
IP_TCL_FILES = ../ip/pcie4_uscale_plus_0.tcl
IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_322.tcl
# Configuration
CONFIG_TCL_FILES = config.tcl
include ../common/vivado.mk
%_fallback.bit: %.bit
echo "open_project $*.xpr" > generate_fallback_bit.tcl
echo "open_run impl_1" >> generate_fallback_bit.tcl
echo "startgroup" >> generate_fallback_bit.tcl
echo "set_property BITSTREAM.CONFIG.SPI_32BIT_ADDR NO [current_design]" >> generate_fallback_bit.tcl
echo "endgroup" >> generate_fallback_bit.tcl
echo "write_bitstream -verbose -force $*_fallback.bit" >> generate_fallback_bit.tcl
echo "undo" >> generate_fallback_bit.tcl
echo "exit" >> generate_fallback_bit.tcl
vivado -nojournal -nolog -mode batch -source generate_fallback_bit.tcl
mkdir -p rev
EXT=bit; COUNT=100; \
while [ -e rev/$*_rev$$COUNT.$$EXT ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
cp $@ rev/$*_fallback_rev$$COUNT.$$EXT; \
echo "Output: rev/$*_fallback_rev$$COUNT.$$EXT";
program: $(FPGA_TOP).bit
echo "open_hw_manager" > program.tcl
echo "connect_hw_server" >> program.tcl
echo "open_hw_target" >> program.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> program.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> program.tcl
echo "set_property PROGRAM.FILE {$(FPGA_TOP).bit} [current_hw_device]" >> program.tcl
echo "program_hw_devices [current_hw_device]" >> program.tcl
echo "exit" >> program.tcl
vivado -nojournal -nolog -mode batch -source program.tcl
%.mcs %.prm: %.bit
echo "write_cfgmem -force -format mcs -size 256 -interface SPIx4 -loadbit {up 0x00000000 $*.bit} -checksum -file $*.mcs" > generate_mcs.tcl
echo "exit" >> generate_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*$$x rev/$*_rev$$COUNT$$x; \
echo "Output: rev/$*_rev$$COUNT$$x"; done;
%_fallback.mcs %_fallback.prm: %_fallback.bit
echo "write_cfgmem -force -format mcs -size 256 -interface SPIx4 -loadbit {up 0x0C000000 $*_fallback.bit} -checksum -file $*_fallback.mcs" > generate_fallback_mcs.tcl
echo "exit" >> generate_fallback_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_fallback_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*_fallback$$x rev/$*_fallback_rev$$COUNT$$x; \
echo "Output: rev/$*_fallback_rev$$COUNT$$x"; done;
%_full.mcs %_full.prm: %_fallback.bit %.bit
echo "write_cfgmem -force -format mcs -size 256 -interface SPIx4 -loadbit {up 0x00000000 $*.bit up 0x0C000000 $*_fallback.bit} -checksum -file $*_full.mcs" > generate_full_mcs.tcl
echo "exit" >> generate_full_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_full_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*_full$$x rev/$*_full_rev$$COUNT$$x; \
echo "Output: rev/$*_full_rev$$COUNT$$x"; done;
flash: $(FPGA_TOP).mcs $(FPGA_TOP).prm
echo "open_hw_manager" > flash.tcl
echo "connect_hw_server" >> flash.tcl
echo "open_hw_target" >> flash.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> flash.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> flash.tcl
echo "create_hw_cfgmem -hw_device [current_hw_device] [lindex [get_cfgmem_parts {mt25qu02g-spi-x1_x2_x4}] 0]" >> flash.tcl
echo "current_hw_cfgmem -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM [current_hw_device]]" >> flash.tcl
echo "set_property PROGRAM.FILES [list \"$(FPGA_TOP).mcs\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP).prm\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.ERASE 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.CFG_PROGRAM 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.VERIFY 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.CHECKSUM 0 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.ADDRESS_RANGE {use_file} [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [current_hw_cfgmem]" >> flash.tcl
echo "create_hw_bitstream -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM_BITFILE [current_hw_device]]" >> flash.tcl
echo "program_hw_devices [current_hw_device]" >> flash.tcl
echo "refresh_hw_device [current_hw_device]" >> flash.tcl
echo "program_hw_cfgmem -hw_cfgmem [current_hw_cfgmem]" >> flash.tcl
echo "boot_hw_device [current_hw_device]" >> flash.tcl
echo "exit" >> flash.tcl
vivado -nojournal -nolog -mode batch -source flash.tcl
flash%: $(FPGA_TOP)%.mcs $(FPGA_TOP)%.prm
echo "open_hw_manager" > flash$*.tcl
echo "connect_hw_server" >> flash$*.tcl
echo "open_hw_target" >> flash$*.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> flash$*.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> flash$*.tcl
echo "create_hw_cfgmem -hw_device [current_hw_device] [lindex [get_cfgmem_parts {mt25qu02g-spi-x1_x2_x4}] 0]" >> flash$*.tcl
echo "current_hw_cfgmem -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM [current_hw_device]]" >> flash$*.tcl
echo "set_property PROGRAM.FILES [list \"$(FPGA_TOP)$*.mcs\"] [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP)$*.prm\"] [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.ERASE 1 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.CFG_PROGRAM 1 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.VERIFY 1 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.CHECKSUM 0 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.ADDRESS_RANGE {use_file} [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [current_hw_cfgmem]" >> flash$*.tcl
echo "create_hw_bitstream -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM_BITFILE [current_hw_device]]" >> flash$*.tcl
echo "program_hw_devices [current_hw_device]" >> flash$*.tcl
echo "refresh_hw_device [current_hw_device]" >> flash$*.tcl
echo "program_hw_cfgmem -hw_cfgmem [current_hw_cfgmem]" >> flash$*.tcl
echo "boot_hw_device [current_hw_device]" >> flash$*.tcl
echo "exit" >> flash$*.tcl
vivado -nojournal -nolog -mode batch -source flash$*.tcl

View File

@@ -0,0 +1,131 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025-2026 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
set params [dict create]
# collect build information
set build_date [clock seconds]
set git_hash 00000000
set git_tag ""
if { [catch {set git_hash [exec git rev-parse --short=8 HEAD]}] } {
puts "Error running git or project not under version control"
}
if { [catch {set git_tag [exec git describe --tags HEAD]}] } {
puts "Error running git, project not under version control, or no tag found"
}
puts "Build date: ${build_date}"
puts "Git hash: ${git_hash}"
puts "Git tag: ${git_tag}"
if { ! [regsub {^.*(\d+\.\d+\.\d+([\.-]\d+)?).*$} $git_tag {\1} tag_ver ] } {
puts "Failed to extract version from git tag"
set tag_ver 0.0.1
}
puts "Tag version: ${tag_ver}"
# FW and board IDs
set fpga_id [expr 0x4B2B093]
set fw_id [expr 0x0000C001]
set fw_ver $tag_ver
set board_vendor_id [expr 0x18f4]
set board_device_id [expr 0x01c5]
set board_ver 1.0
set release_info [expr 0x00000000]
# PCIe IDs
set pcie_vendor_id [expr 0x1234]
set pcie_device_id [expr 0xC001]
set pcie_class_code [expr 0x020000]
set pcie_revision_id [expr 0x00]
set pcie_subsystem_device_id $board_device_id
set pcie_subsystem_vendor_id $board_vendor_id
# FW ID
dict set params FPGA_ID [format "32'h%08x" $fpga_id]
dict set params FW_ID [format "32'h%08x" $fw_id]
dict set params FW_VER [format "32'h%03x%02x%03x" {*}[split $fw_ver .-] 0 0 0]
dict set params BOARD_ID [format "32'h%04x%04x" $board_vendor_id $board_device_id]
dict set params BOARD_VER [format "32'h%03x%02x%03x" {*}[split $board_ver .-] 0 0 0]
dict set params BUILD_DATE "32'd${build_date}"
dict set params GIT_HASH "32'h${git_hash}"
dict set params RELEASE_INFO [format "32'h%08x" $release_info]
# PTP configuration
dict set params PTP_TS_EN "1"
# AXI lite interface configuration (control)
dict set params AXIL_CTRL_DATA_W "32"
dict set params AXIL_CTRL_ADDR_W "24"
# MAC configuration
dict set params CFG_LOW_LATENCY "1"
dict set params COMBINED_MAC_PCS "1"
dict set params MAC_DATA_W "64"
# PCIe IP core settings
set pcie [get_ips pcie4_uscale_plus_0]
# configure BAR settings
proc configure_bar {pcie pf bar aperture} {
set size_list {Bytes Kilobytes Megabytes Gigabytes Terabytes Petabytes Exabytes}
for { set i 0 } { $i < [llength $size_list] } { incr i } {
set scale [lindex $size_list $i]
if {$aperture > 0 && $aperture < ($i+1)*10} {
set size [expr 1 << $aperture - ($i*10)]
puts "${pcie} PF${pf} BAR${bar}: aperture ${aperture} bits ($size $scale)"
set pcie_config [dict create]
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_enabled" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_type" {Memory}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_64bit" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_prefetchable" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_scale" $scale
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_size" $size
set_property -dict $pcie_config $pcie
return
}
}
puts "${pcie} PF${pf} BAR${bar}: disabled"
set_property "CONFIG.pf${pf}_bar${bar}_enabled" {false} $pcie
}
# Control BAR (BAR 0)
configure_bar $pcie 0 0 [dict get $params AXIL_CTRL_ADDR_W]
# PCIe IP core configuration
set pcie_config [dict create]
# PCIe IDs
dict set pcie_config "CONFIG.vendor_id" [format "%04x" $pcie_vendor_id]
dict set pcie_config "CONFIG.PF0_DEVICE_ID" [format "%04x" $pcie_device_id]
dict set pcie_config "CONFIG.PF0_CLASS_CODE" [format "%06x" $pcie_class_code]
dict set pcie_config "CONFIG.PF0_REVISION_ID" [format "%02x" $pcie_revision_id]
dict set pcie_config "CONFIG.PF0_SUBSYSTEM_VENDOR_ID" [format "%04x" $pcie_subsystem_vendor_id]
dict set pcie_config "CONFIG.PF0_SUBSYSTEM_ID" [format "%04x" $pcie_subsystem_device_id]
# MSI
dict set pcie_config "CONFIG.pf0_msi_enabled" {true}
set_property -dict $pcie_config $pcie
# apply parameters to top-level
set param_list {}
dict for {name value} $params {
lappend param_list $name=$value
}
set_property generic $param_list [get_filesets sources_1]

View File

@@ -0,0 +1,163 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
# FPGA settings
FPGA_PART = xcvu5p-flva2104-2-e
FPGA_TOP = fpga
FPGA_ARCH = virtexuplus
RTL_DIR = ../rtl
LIB_DIR = ../lib
TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
# Files for synthesis
SYN_FILES = $(RTL_DIR)/fpga_nt200a02.sv
SYN_FILES += $(RTL_DIR)/fpga_core.sv
SYN_FILES += $(RTL_DIR)/../pll/si5340_i2c_init.sv
SYN_FILES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_micro_pcie_us.f
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
SYN_FILES += $(TAXI_SRC_DIR)/lss/rtl/taxi_i2c_master.sv
SYN_FILES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv
SYN_FILES += $(TAXI_SRC_DIR)/pyrite/rtl/pyrite_pcie_us_vsec_qspi.f
# XDC files
XDC_FILES = ../fpga_nt200a02.xdc
XDC_FILES += $(TAXI_SRC_DIR)/eth/syn/vivado/taxi_eth_mac_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/axis/syn/vivado/taxi_axis_async_fifo.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_leaf.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_phc_regs.tcl
XDC_FILES += $(TAXI_SRC_DIR)/ptp/syn/vivado/taxi_ptp_td_rel2tod.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_reset.tcl
XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_signal.tcl
# IP
IP_TCL_FILES = ../ip/pcie4_uscale_plus_0.tcl
IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_phy_10g_us_gty_322.tcl
# Configuration
CONFIG_TCL_FILES = config.tcl
include ../common/vivado.mk
%_fallback.bit: %.bit
echo "open_project $*.xpr" > generate_fallback_bit.tcl
echo "open_run impl_1" >> generate_fallback_bit.tcl
echo "startgroup" >> generate_fallback_bit.tcl
echo "set_property BITSTREAM.CONFIG.SPI_32BIT_ADDR NO [current_design]" >> generate_fallback_bit.tcl
echo "endgroup" >> generate_fallback_bit.tcl
echo "write_bitstream -verbose -force $*_fallback.bit" >> generate_fallback_bit.tcl
echo "undo" >> generate_fallback_bit.tcl
echo "exit" >> generate_fallback_bit.tcl
vivado -nojournal -nolog -mode batch -source generate_fallback_bit.tcl
mkdir -p rev
EXT=bit; COUNT=100; \
while [ -e rev/$*_rev$$COUNT.$$EXT ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
cp $@ rev/$*_fallback_rev$$COUNT.$$EXT; \
echo "Output: rev/$*_fallback_rev$$COUNT.$$EXT";
program: $(FPGA_TOP).bit
echo "open_hw_manager" > program.tcl
echo "connect_hw_server" >> program.tcl
echo "open_hw_target" >> program.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> program.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> program.tcl
echo "set_property PROGRAM.FILE {$(FPGA_TOP).bit} [current_hw_device]" >> program.tcl
echo "program_hw_devices [current_hw_device]" >> program.tcl
echo "exit" >> program.tcl
vivado -nojournal -nolog -mode batch -source program.tcl
%.mcs %.prm: %.bit
echo "write_cfgmem -force -format mcs -size 256 -interface SPIx4 -loadbit {up 0x00000000 $*.bit} -checksum -file $*.mcs" > generate_mcs.tcl
echo "exit" >> generate_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*$$x rev/$*_rev$$COUNT$$x; \
echo "Output: rev/$*_rev$$COUNT$$x"; done;
%_fallback.mcs %_fallback.prm: %_fallback.bit
echo "write_cfgmem -force -format mcs -size 256 -interface SPIx4 -loadbit {up 0x0C000000 $*_fallback.bit} -checksum -file $*_fallback.mcs" > generate_fallback_mcs.tcl
echo "exit" >> generate_fallback_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_fallback_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*_fallback$$x rev/$*_fallback_rev$$COUNT$$x; \
echo "Output: rev/$*_fallback_rev$$COUNT$$x"; done;
%_full.mcs %_full.prm: %_fallback.bit %.bit
echo "write_cfgmem -force -format mcs -size 256 -interface SPIx4 -loadbit {up 0x00000000 $*.bit up 0x0C000000 $*_fallback.bit} -checksum -file $*_full.mcs" > generate_full_mcs.tcl
echo "exit" >> generate_full_mcs.tcl
vivado -nojournal -nolog -mode batch -source generate_full_mcs.tcl
mkdir -p rev
COUNT=100; \
while [ -e rev/$*_rev$$COUNT.bit ]; \
do COUNT=$$((COUNT+1)); done; \
COUNT=$$((COUNT-1)); \
for x in .mcs .prm; \
do cp $*_full$$x rev/$*_full_rev$$COUNT$$x; \
echo "Output: rev/$*_full_rev$$COUNT$$x"; done;
flash: $(FPGA_TOP).mcs $(FPGA_TOP).prm
echo "open_hw_manager" > flash.tcl
echo "connect_hw_server" >> flash.tcl
echo "open_hw_target" >> flash.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> flash.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> flash.tcl
echo "create_hw_cfgmem -hw_device [current_hw_device] [lindex [get_cfgmem_parts {mt25qu02g-spi-x1_x2_x4}] 0]" >> flash.tcl
echo "current_hw_cfgmem -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM [current_hw_device]]" >> flash.tcl
echo "set_property PROGRAM.FILES [list \"$(FPGA_TOP).mcs\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP).prm\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.ERASE 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.CFG_PROGRAM 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.VERIFY 1 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.CHECKSUM 0 [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.ADDRESS_RANGE {use_file} [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [current_hw_cfgmem]" >> flash.tcl
echo "create_hw_bitstream -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM_BITFILE [current_hw_device]]" >> flash.tcl
echo "program_hw_devices [current_hw_device]" >> flash.tcl
echo "refresh_hw_device [current_hw_device]" >> flash.tcl
echo "program_hw_cfgmem -hw_cfgmem [current_hw_cfgmem]" >> flash.tcl
echo "boot_hw_device [current_hw_device]" >> flash.tcl
echo "exit" >> flash.tcl
vivado -nojournal -nolog -mode batch -source flash.tcl
flash%: $(FPGA_TOP)%.mcs $(FPGA_TOP)%.prm
echo "open_hw_manager" > flash$*.tcl
echo "connect_hw_server" >> flash$*.tcl
echo "open_hw_target" >> flash$*.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> flash$*.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> flash$*.tcl
echo "create_hw_cfgmem -hw_device [current_hw_device] [lindex [get_cfgmem_parts {mt25qu02g-spi-x1_x2_x4}] 0]" >> flash$*.tcl
echo "current_hw_cfgmem -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM [current_hw_device]]" >> flash$*.tcl
echo "set_property PROGRAM.FILES [list \"$(FPGA_TOP)$*.mcs\"] [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(FPGA_TOP)$*.prm\"] [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.ERASE 1 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.CFG_PROGRAM 1 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.VERIFY 1 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.CHECKSUM 0 [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.ADDRESS_RANGE {use_file} [current_hw_cfgmem]" >> flash$*.tcl
echo "set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [current_hw_cfgmem]" >> flash$*.tcl
echo "create_hw_bitstream -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM_BITFILE [current_hw_device]]" >> flash$*.tcl
echo "program_hw_devices [current_hw_device]" >> flash$*.tcl
echo "refresh_hw_device [current_hw_device]" >> flash$*.tcl
echo "program_hw_cfgmem -hw_cfgmem [current_hw_cfgmem]" >> flash$*.tcl
echo "boot_hw_device [current_hw_device]" >> flash$*.tcl
echo "exit" >> flash$*.tcl
vivado -nojournal -nolog -mode batch -source flash$*.tcl

View File

@@ -0,0 +1,131 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025-2026 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
set params [dict create]
# collect build information
set build_date [clock seconds]
set git_hash 00000000
set git_tag ""
if { [catch {set git_hash [exec git rev-parse --short=8 HEAD]}] } {
puts "Error running git or project not under version control"
}
if { [catch {set git_tag [exec git describe --tags HEAD]}] } {
puts "Error running git, project not under version control, or no tag found"
}
puts "Build date: ${build_date}"
puts "Git hash: ${git_hash}"
puts "Git tag: ${git_tag}"
if { ! [regsub {^.*(\d+\.\d+\.\d+([\.-]\d+)?).*$} $git_tag {\1} tag_ver ] } {
puts "Failed to extract version from git tag"
set tag_ver 0.0.1
}
puts "Tag version: ${tag_ver}"
# FW and board IDs
set fpga_id [expr 0x4B2B093]
set fw_id [expr 0x0000C001]
set fw_ver $tag_ver
set board_vendor_id [expr 0x18f4]
set board_device_id [expr 0x01c5]
set board_ver 1.0
set release_info [expr 0x00000000]
# PCIe IDs
set pcie_vendor_id [expr 0x1234]
set pcie_device_id [expr 0xC001]
set pcie_class_code [expr 0x020000]
set pcie_revision_id [expr 0x00]
set pcie_subsystem_device_id $board_device_id
set pcie_subsystem_vendor_id $board_vendor_id
# FW ID
dict set params FPGA_ID [format "32'h%08x" $fpga_id]
dict set params FW_ID [format "32'h%08x" $fw_id]
dict set params FW_VER [format "32'h%03x%02x%03x" {*}[split $fw_ver .-] 0 0 0]
dict set params BOARD_ID [format "32'h%04x%04x" $board_vendor_id $board_device_id]
dict set params BOARD_VER [format "32'h%03x%02x%03x" {*}[split $board_ver .-] 0 0 0]
dict set params BUILD_DATE "32'd${build_date}"
dict set params GIT_HASH "32'h${git_hash}"
dict set params RELEASE_INFO [format "32'h%08x" $release_info]
# PTP configuration
dict set params PTP_TS_EN "1"
# AXI lite interface configuration (control)
dict set params AXIL_CTRL_DATA_W "32"
dict set params AXIL_CTRL_ADDR_W "24"
# MAC configuration
dict set params CFG_LOW_LATENCY "1"
dict set params COMBINED_MAC_PCS "1"
dict set params MAC_DATA_W "32"
# PCIe IP core settings
set pcie [get_ips pcie4_uscale_plus_0]
# configure BAR settings
proc configure_bar {pcie pf bar aperture} {
set size_list {Bytes Kilobytes Megabytes Gigabytes Terabytes Petabytes Exabytes}
for { set i 0 } { $i < [llength $size_list] } { incr i } {
set scale [lindex $size_list $i]
if {$aperture > 0 && $aperture < ($i+1)*10} {
set size [expr 1 << $aperture - ($i*10)]
puts "${pcie} PF${pf} BAR${bar}: aperture ${aperture} bits ($size $scale)"
set pcie_config [dict create]
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_enabled" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_type" {Memory}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_64bit" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_prefetchable" {true}
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_scale" $scale
dict set pcie_config "CONFIG.pf${pf}_bar${bar}_size" $size
set_property -dict $pcie_config $pcie
return
}
}
puts "${pcie} PF${pf} BAR${bar}: disabled"
set_property "CONFIG.pf${pf}_bar${bar}_enabled" {false} $pcie
}
# Control BAR (BAR 0)
configure_bar $pcie 0 0 [dict get $params AXIL_CTRL_ADDR_W]
# PCIe IP core configuration
set pcie_config [dict create]
# PCIe IDs
dict set pcie_config "CONFIG.vendor_id" [format "%04x" $pcie_vendor_id]
dict set pcie_config "CONFIG.PF0_DEVICE_ID" [format "%04x" $pcie_device_id]
dict set pcie_config "CONFIG.PF0_CLASS_CODE" [format "%06x" $pcie_class_code]
dict set pcie_config "CONFIG.PF0_REVISION_ID" [format "%02x" $pcie_revision_id]
dict set pcie_config "CONFIG.PF0_SUBSYSTEM_VENDOR_ID" [format "%04x" $pcie_subsystem_vendor_id]
dict set pcie_config "CONFIG.PF0_SUBSYSTEM_ID" [format "%04x" $pcie_subsystem_device_id]
# MSI
dict set pcie_config "CONFIG.pf0_msi_enabled" {true}
set_property -dict $pcie_config $pcie
# apply parameters to top-level
set param_list {}
dict for {name value} $params {
lappend param_list $name=$value
}
set_property generic $param_list [get_filesets sources_1]

Some files were not shown because too many files have changed in this diff Show More