Compare commits

..

210 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
Alex Forencich
962950a1e3 cndm: Use event queues in driver
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-10 13:06:40 -07:00
Alex Forencich
d7eb1b21a2 cndm: Use event queues in driver model
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-10 00:58:52 -07:00
Alex Forencich
c7279a1ea2 cndm: Add support for event queues
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-10 00:57:20 -07:00
Alex Forencich
ed61857bc3 cndm: Move interrupt handling out of CQ
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-09 22:23:56 -07:00
Alex Forencich
2ea3c204de cndm: Rework queue notification mechanism to eliminate ream race
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-09 21:41:36 -07:00
Alex Forencich
c37d967de9 cndm: Add consumer pointer and arm bit to completion queue
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-09 14:50:07 -07:00
Alex Forencich
e514869d70 cndm: Clean up resource handling in datapath manager
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-09 00:56:27 -07:00
Alex Forencich
50ba1d4c89 cndm: Make IRQ assignments configurable, add IRQ rate limiter
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 21:21:09 -07:00
Alex Forencich
8773672f26 cndm: Board-level parameter cleanup
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 21:20:41 -07:00
Alex Forencich
9af793edc6 cndm: Parameter cleanup
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 17:39:28 -07:00
Alex Forencich
2bb2710bbd pcie: Add IRQ rate limit module and testbench
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 17:38:04 -07:00
Alex Forencich
86b9947794 stats: Clean up array init
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 14:43:31 -07:00
Alex Forencich
9ec5bd0190 ptp: Clean up array init
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 14:43:14 -07:00
Alex Forencich
3ac7484e16 pcie: Clean up array init
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 14:42:31 -07:00
Alex Forencich
bb278958b2 eth: Clean up array init
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 14:42:08 -07:00
Alex Forencich
4b7ca2a569 dma: Clean up array init
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 14:41:24 -07:00
Alex Forencich
9d701c9186 axi: Clean up array init
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 14:40:38 -07:00
Alex Forencich
f9a5d08365 apb: Clean up array init
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 14:40:11 -07:00
Alex Forencich
a59a4dfd84 cndm: Remove port count registers
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 01:22:52 -08:00
Alex Forencich
438c082f73 cndm: Read config in driver
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 01:22:36 -08:00
Alex Forencich
283ef97cec cndm: Initialize ID ROM differently to make Vivado happy
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 01:01:44 -08:00
Alex Forencich
e2823a65ef cndm: Read config in driver model
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-08 00:08:05 -08:00
Alex Forencich
dde401e095 cndm: Add config command to read config data from HW
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-07 23:12:40 -08:00
Alex Forencich
09f1b278e8 cndm: Make scratch registers more generic in datapath manager
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-07 23:12:02 -08:00
Alex Forencich
2e8f9f8731 cndm: Copy cndm-micro core logic as cndm-lite
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-06 21:07:25 -08:00
Alex Forencich
4a2b9dd10c dma: Fix incorrect width cast
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-06 20:39:10 -08:00
Alex Forencich
798756ac89 dma: Fix incorrect width cast
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-06 19:38:59 -08:00
Alex Forencich
41b87dc65c cndm: Set MAC clock frequency and rate in core testbench, remove commented out code
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-06 19:20:03 -08:00
Alex Forencich
f464a21e1d cndm: Parametrize core tests over PCIe interface width
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-06 19:19:53 -08:00
Alex Forencich
96630b8f61 cndm: Remove extraneous files from testbench file lists
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-06 18:04:14 -08:00
Alex Forencich
ce8da1bc59 cndm: Fully share SQ/RQ HW resources
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-06 15:23:20 -08:00
Alex Forencich
d0c9ae0637 cndm: Avoid using parameters from interfaces defined in the same module
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-06 15:06:12 -08:00
Alex Forencich
a46b012c91 cndm: Widen internal datapath to prevent CDC-related bottlenecks
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-06 15:04:12 -08:00
Alex Forencich
595d744aa4 cndm: Add qtype field to queue state to enable sharing
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-05 22:12:39 -08:00
Alex Forencich
8263ebab24 cndm: Move SQ/RQ state into distributed RAM
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-05 20:49:35 -08:00
Alex Forencich
7dbe6df56a cndm: Peel off queue management logic, store queue state in distributed RAM
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-05 18:04:43 -08:00
Alex Forencich
8f1c082174 cndm: Rework driver model to support multiple queues
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-05 16:50:33 -08:00
Alex Forencich
39c9dce0fa cndm: Check for queue allocation failures in the driver
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-05 15:47:03 -08:00
Alex Forencich
f8764d581d cndm: Check for queue allocation failures in the driver model
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-05 15:46:30 -08:00
Alex Forencich
cce4c4525e cndm: Move queue setup/teardown into netdev open/close
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-04 16:47:30 -08:00
Alex Forencich
f8f73ea570 cndm: Reorganize driver
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-04 01:19:37 -08:00
Alex Forencich
9f56b9febd cndm: Reorganize driver model
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-03 20:43:09 -08:00
Alex Forencich
6bf7240686 cndm: Rework desc/cpl mux/demux logic, add support for CQNs, implement queue allocation
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-03 18:09:38 -08:00
Alex Forencich
8494e734a8 axis: Add TID_ROUTE parameter to taxi_axis_demux to faciliate routing replies by TID
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-03 16:14:32 -08:00
Alex Forencich
4d8f0cfece cndm: Move control registers out of port module
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-03 13:31:16 -08:00
Alex Forencich
191f7940b3 cndm_proto: Use SV enums for state machines
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-03 12:05:35 -08:00
Alex Forencich
0ab7538e24 cndm: Use SV enums for state machines
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-03 12:05:14 -08:00
Alex Forencich
902996e3bd cndm: Add wmb to ensure command is fully written in mailbox before executing it
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-03 00:46:15 -08:00
Alex Forencich
0d4a030e3f cndm: Add PTP command
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-02 18:27:33 -08:00
Alex Forencich
14d35dd75f cndm: Add mutex for the command mailbox
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-02 15:30:43 -08:00
Alex Forencich
0f09b8bdaa cndm: Add register access command
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-02 00:33:31 -08:00
Alex Forencich
a3ef71ae87 cndm: Fix testbench command structs
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-01 23:33:51 -08:00
Alex Forencich
499a70982f prim: Fix single-clock TDP RAM inference
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-01 20:43:13 -08:00
Alex Forencich
32b073ade9 cndm: Fix widths
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-01 14:02:39 -08:00
Alex Forencich
e27b5c0b94 cndm: Initial implementation of command interface
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-03-01 13:16:24 -08:00
Alex Forencich
0ff8e5fb9e prim: Add RAM primitives
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 22:08:14 -08:00
Alex Forencich
901606a64d dma: Use SV enums in DMA components
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 20:12:47 -08:00
Alex Forencich
ee204d1665 axi: Fix width
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 18:11:55 -08:00
Alex Forencich
f8d2c26663 zircon: Fix types
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 17:16:04 -08:00
Alex Forencich
aee0483835 axi: Use SV enums in AXI components
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 17:12:21 -08:00
Alex Forencich
1530f8cecf axis: Use SV enums in AXI stream components
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 17:11:30 -08:00
Alex Forencich
450960c564 apb: Use SV enums in APB components
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 17:11:22 -08:00
Alex Forencich
d055cb7857 xfcp: Use SV enums in XFCP
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 16:13:16 -08:00
Alex Forencich
b7aa9623c4 zircon: Use SV enums in zircon
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 16:08:57 -08:00
Alex Forencich
08f6586c2e lss: Use SV enums in low-speed serial logic
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 16:05:06 -08:00
Alex Forencich
bc0f8c0df2 stats: Use SV enums in statistics logic
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 15:57:05 -08:00
Alex Forencich
6cf03d6435 pcie: Use SV enums in PCIe logic
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 15:55:34 -08:00
Alex Forencich
1740e09a8a hip: Use SV enums in transceiver support logic
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 15:45:22 -08:00
Alex Forencich
5df2aa3cfd eth: Use SV enums in MAC logic
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 15:04:08 -08:00
Alex Forencich
8d7cdaa689 pcie: Fix parametrization issues in MSI-X modules
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 10:42:07 -08:00
Alex Forencich
a39c62f85a pcie: Add MSI-X module with APB interface
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 00:06:42 -08:00
Alex Forencich
896dff2fd1 pcie: Add MSI-X module with AXI lite interface
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-27 00:06:20 -08:00
Alex Forencich
442eb06868 pyrite: Support older micron flash chips
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-26 01:23:50 -08:00
Alex Forencich
ae3fa375f4 cndm: Add support for VCU118
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-26 00:39:15 -08:00
Alex Forencich
b4eb645007 pyrite: Print some more flash registers
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-25 23:25:32 -08:00
Alex Forencich
64d5f02cd9 pyrite: Add missing include
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-25 23:24:35 -08:00
Alex Forencich
8567f91ef6 cndm: Add support for Silicom fb2CG@KU15P
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-25 00:52:42 -08:00
Alex Forencich
2659fec26b cndm: Add support for ZCU106
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-24 18:33:41 -08:00
Alex Forencich
6827f619f7 cndm: Clean up unused MMCM outputs
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-24 17:51:57 -08:00
Alex Forencich
39638ab4d3 eth/example: Clean up unused MMCM outputs
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-24 17:51:40 -08:00
Alex Forencich
146fc78a2f eth/example: XDC cleanup
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-24 17:50:10 -08:00
Alex Forencich
3fc54f0384 cndm: Add missing testbench connections
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-24 17:49:26 -08:00
Alex Forencich
37393ca112 cndm_proto: Add missing testbench connections
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-24 17:49:10 -08:00
Alex Forencich
6f43d2b454 eth/example: Clean up hardware server commands
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-24 17:48:32 -08:00
Alex Forencich
34408521cc cndm: Add support for VCU108
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-24 15:23:32 -08:00
Alex Forencich
5545602a26 pcie: Fix width cast
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-24 14:26:42 -08:00
Alex Forencich
8b925954ef pyrite: Add support for flashing via PCIe VSEC
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-24 12:33:55 -08:00
Alex Forencich
5d3aff95cc pcie: Add VSEC AXIL register access extended capability implementation for UltraScale
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-24 12:20:02 -08:00
Alex Forencich
7bb3f18fa3 pcie: Add VSEC APB register access extended capability implementation for UltraScale
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-24 12:19:54 -08:00
Alex Forencich
842d39faca pyrite: Fix compiler warning
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-24 12:02:55 -08:00
Alex Forencich
d627de2c15 pyrite: Ensure APB IF is included
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-24 11:47:59 -08:00
Alex Forencich
0519318ea0 cndm: Alveo testbench cleanup
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-23 20:55:51 -08:00
Alex Forencich
b1d66f36fb cndm: AS02MC04 testbench cleanup
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-23 20:55:36 -08:00
Alex Forencich
e33bac67d7 cndm: Add support for Alpha Data ADM-PCIE-9V3
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-23 20:53:30 -08:00
Alex Forencich
781b7902a6 cndm: Add support for Alveo U280
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-23 14:47:18 -08:00
Alex Forencich
a404a2c0ba cndm: Add support for Alveo U50
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-23 14:13:26 -08:00
Alex Forencich
d09efd9a5a cndm: Add support for RK-XCKU5P-F
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-23 00:51:13 -08:00
Alex Forencich
329b9a99be cndm: Add support for Alveo X3/X3522
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-23 00:47:08 -08:00
Alex Forencich
0ccd136c15 cndm: Add support for Alveo U45N/SN1000
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-23 00:45:49 -08:00
Alex Forencich
5b7b0bc35e cndm: Add support for Alveo AU55N/AU55C
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-23 00:45:03 -08:00
Alex Forencich
7f55a956f4 cndm: Add support for Alveo AU250
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-22 18:32:10 -08:00
Alex Forencich
d1aa3013c6 cndm: Add support for Alveo AU200/VCU1525
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-22 16:49:55 -08:00
Alex Forencich
09665325bc eth: Update readme
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-22 15:13:04 -08:00
Alex Forencich
4b3319ff0c eth: Add Ethernet example design for XEM8320 board
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-22 13:58:24 -08:00
Alex Forencich
9ace50f723 eth: Support artixuplus in MAC wrappers
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-22 13:14:59 -08:00
Alex Forencich
d8719efbee cndm: Fix device IDs
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-21 15:57:34 -08:00
Alex Forencich
ca5f9b045d dma: Add workaround for verilator linter bug
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-21 14:03:37 -08:00
Alex Forencich
69c2a1e896 pyrite: Cast widths
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-21 13:56:13 -08:00
Alex Forencich
427aabe5d7 eth: RK-XCKU5P-F XDC cleanup
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-21 02:49:01 -08:00
Alex Forencich
be80d4e964 pcie: Tie off AXIL user signals in PCIe AXI lite master module
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-21 02:48:18 -08:00
Alex Forencich
1e6f5531d1 eth: Fix typo
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-20 22:15:01 -08:00
Alex Forencich
c37b4cbbfa pyrite: Cast widths
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-20 22:14:20 -08:00
Alex Forencich
9b55a08465 pcie: Cast widths in VPD implementation
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-20 22:14:01 -08:00
Alex Forencich
63c9544c3f cndm: Clean up parameters, add flashing support via pyrite
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-20 22:05:50 -08:00
Alex Forencich
b68be72e70 cndm: Fix readme
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-20 21:34:06 -08:00
Alex Forencich
5a439c7e8e pyrite: Add flash access modules for UltraScale PCIe VPD
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-20 21:33:09 -08:00
Alex Forencich
2387aa793e eth: Add Ethernet example design for RK-XCKU5P-F board
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-20 21:31:46 -08:00
Alex Forencich
add1c7aec2 eth: Fix path
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-20 21:10:04 -08:00
Alex Forencich
8fe55a6aae eth: Minor example design cleanup
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-20 13:54:48 -08:00
Alex Forencich
2b2450da54 cndm: Fix path
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-20 12:41:10 -08:00
Alex Forencich
589a80f582 pyrite: Initial commit of pyrite flashing utility
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-19 21:46:09 -08:00
Alex Forencich
8f40d3a426 cndm_proto: Fix PCIe class code
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-18 13:21:35 -08:00
Alex Forencich
43de83de89 cndm: Fix PCIe class code
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-18 13:21:24 -08:00
Alex Forencich
8b13e7a1ea ptp: Ensure reads are consistent
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-16 20:37:37 -08:00
Alex Forencich
45d7b1d77c ptp: Fix signal name
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-16 17:47:29 -08:00
Alex Forencich
dc70c7247a ptp: Fix parameter name
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-16 16:54:56 -08:00
Alex Forencich
9630afce1d pcie: Add VPD capability implementation for UltraScale+
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-16 13:37:35 -08:00
Alex Forencich
d6744bc99b cndm_proto: Clean up ports
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-16 12:34:37 -08:00
Alex Forencich
ab01a1ba42 cndm: Clean up ports
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-16 12:34:28 -08:00
Alex Forencich
5951547d11 apb: Add APB to AXI lite adapter module and testbench
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2026-02-15 12:49:30 -08:00
575 changed files with 94915 additions and 3439 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.
@@ -77,6 +77,7 @@ The Taxi transport library contains many smaller components that can be composed
* APB * APB
* SV interface for APB * SV interface for APB
* APB to AXI lite adapter
* Interconnect * Interconnect
* Width converter * Width converter
* Single-port RAM * Single-port RAM
@@ -90,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
@@ -182,6 +185,8 @@ The Taxi transport library contains many smaller components that can be composed
* PCIe AXI lite master * PCIe AXI lite master
* PCIe AXI lite master for Xilinx UltraScale * PCIe AXI lite master for Xilinx UltraScale
* MSI shim for Xilinx UltraScale * MSI shim for Xilinx UltraScale
* MSI-X with AXI lite control interface
* MSI-X with APB control interface
* Primitives * Primitives
* Arbiter * Arbiter
* Priority encoder * Priority encoder
@@ -219,12 +224,18 @@ Example designs are provided for several different FPGA boards, showcasing many
* Cisco Nexus K3P-S/ExaNIC X25 (Xilinx Kintex UltraScale+ XCKU3P) * Cisco Nexus K3P-S/ExaNIC X25 (Xilinx Kintex UltraScale+ XCKU3P)
* Cisco Nexus K3P-Q/ExaNIC X100 (Xilinx Kintex UltraScale+ XCKU3P) * Cisco Nexus K3P-Q/ExaNIC X100 (Xilinx Kintex UltraScale+ XCKU3P)
* Alibaba AS02MC04 (Xilinx Kintex UltraScale+ XCKU3P) * Alibaba AS02MC04 (Xilinx Kintex UltraScale+ XCKU3P)
* RK-XCKU5P-F (Xilinx Kintex UltraScale+ XCKU5P)
* Digilent Arty A7 (Xilinx Artix 7 XC7A35T) * Digilent Arty A7 (Xilinx Artix 7 XC7A35T)
* Digilent NetFPGA SUME (Xilinx Virtex 7 XC7V690T) * Digilent NetFPGA SUME (Xilinx Virtex 7 XC7V690T)
* HiTech Global HTG-940 (Xilinx Virtex UltraScale+ XCVU9P/XCVU13P) * HiTech Global HTG-940 (Xilinx Virtex UltraScale+ XCVU9P/XCVU13P)
* HiTech Global HTG-9200 (Xilinx Virtex UltraScale+ XCVU9P/XCVU13P) * HiTech Global HTG-9200 (Xilinx Virtex UltraScale+ XCVU9P/XCVU13P)
* 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)
* 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

@@ -93,11 +93,12 @@ if (M_BYTE_LANES == S_BYTE_LANES) begin : bypass
end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize
// output is wider; upsize // output is wider; upsize
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic s_apb_pready_reg = 1'b0, s_apb_pready_next; logic s_apb_pready_reg = 1'b0, s_apb_pready_next;
logic [S_DATA_W-1:0] s_apb_prdata_reg = '0, s_apb_prdata_next; logic [S_DATA_W-1:0] s_apb_prdata_reg = '0, s_apb_prdata_next;
@@ -161,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
@@ -232,11 +233,12 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT; localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic [DATA_W-1:0] data_reg = '0, data_next; logic [DATA_W-1:0] data_reg = '0, data_next;
logic [STRB_W-1:0] strb_reg = '0, strb_next; logic [STRB_W-1:0] strb_reg = '0, strb_next;
@@ -315,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

@@ -0,0 +1,604 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* APB to AXI4 lite adapter
*/
module taxi_apb_axil_adapter
(
input wire logic clk,
input wire logic rst,
/*
* APB slave interface
*/
taxi_apb_if.slv s_apb,
/*
* AXI4-Lite master interface
*/
taxi_axil_if.wr_mst m_axil_wr,
taxi_axil_if.rd_mst m_axil_rd
);
// extract parameters
localparam APB_DATA_W = s_apb.DATA_W;
localparam APB_ADDR_W = s_apb.ADDR_W;
localparam APB_STRB_W = s_apb.STRB_W;
localparam logic PAUSER_EN = (m_axil_wr.AWUSER_EN || m_axil_wr.ARUSER_EN) && s_apb.PAUSER_EN;
localparam PAUSER_W = s_apb.PAUSER_W;
localparam logic PWUSER_EN = m_axil_wr.WUSER_EN && s_apb.PWUSER_EN;
localparam PWUSER_W = s_apb.PWUSER_W;
localparam logic PRUSER_EN = m_axil_rd.RUSER_EN && s_apb.PRUSER_EN;
localparam PRUSER_W = s_apb.PRUSER_W;
localparam logic PBUSER_EN = m_axil_wr.BUSER_EN && s_apb.PBUSER_EN;
localparam PBUSER_W = s_apb.PBUSER_W;
localparam AXIL_DATA_W = m_axil_rd.DATA_W;
localparam AXIL_ADDR_W = m_axil_rd.ADDR_W;
localparam AXIL_STRB_W = m_axil_rd.STRB_W;
localparam logic AWUSER_EN = m_axil_wr.AWUSER_EN && s_apb.PAUSER_EN;
localparam AWUSER_W = m_axil_wr.AWUSER_W;
localparam logic WUSER_EN = m_axil_wr.WUSER_EN && s_apb.PWUSER_EN;
localparam WUSER_W = m_axil_wr.WUSER_W;
localparam logic BUSER_EN = m_axil_wr.BUSER_EN && s_apb.PBUSER_EN;
localparam BUSER_W = m_axil_wr.BUSER_W;
localparam logic ARUSER_EN = m_axil_rd.ARUSER_EN && s_apb.PAUSER_EN;
localparam ARUSER_W = m_axil_rd.ARUSER_W;
localparam logic RUSER_EN = m_axil_rd.RUSER_EN && s_apb.PRUSER_EN;
localparam RUSER_W = m_axil_rd.RUSER_W;
localparam AUSER_W = ARUSER_W > AWUSER_W ? ARUSER_W : AWUSER_W;
localparam APB_ADDR_BIT_OFFSET = $clog2(APB_STRB_W);
localparam AXIL_ADDR_BIT_OFFSET = $clog2(AXIL_STRB_W);
localparam APB_BYTE_LANES = APB_STRB_W;
localparam AXIL_BYTE_LANES = AXIL_STRB_W;
localparam APB_BYTE_W = APB_DATA_W/APB_BYTE_LANES;
localparam AXIL_BYTE_W = AXIL_DATA_W/AXIL_BYTE_LANES;
localparam APB_ADDR_MASK = {APB_ADDR_W{1'b1}} << APB_ADDR_BIT_OFFSET;
localparam AXIL_ADDR_MASK = {AXIL_ADDR_W{1'b1}} << AXIL_ADDR_BIT_OFFSET;
// check configuration
if (APB_BYTE_W * APB_STRB_W != APB_DATA_W)
$fatal(0, "Error: APB interface data width not evenly divisible (instance %m)");
if (AXIL_BYTE_W * AXIL_STRB_W != AXIL_DATA_W)
$fatal(0, "Error: AXI lite interface data width not evenly divisible (instance %m)");
if (APB_BYTE_W != AXIL_BYTE_W)
$fatal(0, "Error: byte size mismatch (instance %m)");
if (2**$clog2(APB_BYTE_LANES) != APB_BYTE_LANES)
$fatal(0, "Error: APB interface byte lane count must be even power of two (instance %m)");
if (2**$clog2(AXIL_BYTE_LANES) != AXIL_BYTE_LANES)
$fatal(0, "Error: AXI lite interface byte lane count must be even power of two (instance %m)");
if (m_axil_wr.DATA_W != m_axil_rd.DATA_W)
$fatal(0, "Error: AXI interface configuration mismatch (instance %m)");
if (AXIL_BYTE_LANES == APB_BYTE_LANES) begin : bypass
// same width; translate
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
state_t state_reg = STATE_IDLE, state_next;
logic s_apb_pready_reg = 1'b0, s_apb_pready_next;
logic [APB_DATA_W-1:0] s_apb_prdata_reg = '0, s_apb_prdata_next;
logic s_apb_pslverr_reg = 1'b0, s_apb_pslverr_next;
logic [PRUSER_W-1:0] s_apb_pruser_reg = '0, s_apb_pruser_next;
logic [PBUSER_W-1:0] s_apb_pbuser_reg = '0, s_apb_pbuser_next;
logic [AXIL_ADDR_W-1:0] m_axil_addr_reg = '0, m_axil_addr_next;
logic [2:0] m_axil_prot_reg = 3'd0, m_axil_prot_next;
logic [AUSER_W-1:0] m_axil_auser_reg = '0, m_axil_auser_next;
logic m_axil_awvalid_reg = 1'b0, m_axil_awvalid_next;
logic [AXIL_DATA_W-1:0] m_axil_wdata_reg = '0, m_axil_wdata_next;
logic [AXIL_STRB_W-1:0] m_axil_wstrb_reg = '0, m_axil_wstrb_next;
logic [WUSER_W-1:0] m_axil_wuser_reg = '0, m_axil_wuser_next;
logic m_axil_wvalid_reg = 1'b0, m_axil_wvalid_next;
logic m_axil_bready_reg = 1'b0, m_axil_bready_next;
logic m_axil_arvalid_reg = 1'b0, m_axil_arvalid_next;
logic m_axil_rready_reg = 1'b0, m_axil_rready_next;
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;
assign m_axil_wr.awaddr = m_axil_addr_reg;
assign m_axil_wr.awprot = m_axil_prot_reg;
assign m_axil_wr.awuser = AWUSER_EN ? m_axil_auser_reg : '0;
assign m_axil_wr.awvalid = m_axil_awvalid_reg;
assign m_axil_wr.wdata = m_axil_wdata_reg;
assign m_axil_wr.wstrb = m_axil_wstrb_reg;
assign m_axil_wr.wuser = WUSER_EN ? m_axil_wuser_reg : '0;
assign m_axil_wr.wvalid = m_axil_wvalid_reg;
assign m_axil_wr.bready = m_axil_bready_reg;
assign m_axil_rd.araddr = m_axil_addr_reg;
assign m_axil_rd.arprot = m_axil_prot_reg;
assign m_axil_rd.aruser = ARUSER_EN ? m_axil_auser_reg : '0;
assign m_axil_rd.arvalid = m_axil_arvalid_reg;
assign m_axil_rd.rready = m_axil_rready_reg;
always_comb begin
state_next = STATE_IDLE;
s_apb_pready_next = 1'b0;
s_apb_prdata_next = s_apb_prdata_reg;
s_apb_pslverr_next = s_apb_pslverr_reg;
s_apb_pruser_next = s_apb_pruser_reg;
s_apb_pbuser_next = s_apb_pbuser_reg;
m_axil_addr_next = m_axil_addr_reg;
m_axil_prot_next = m_axil_prot_reg;
m_axil_auser_next = m_axil_auser_reg;
m_axil_awvalid_next = m_axil_awvalid_reg && !m_axil_wr.awready;
m_axil_wdata_next = m_axil_wdata_reg;
m_axil_wstrb_next = m_axil_wstrb_reg;
m_axil_wuser_next = m_axil_wuser_reg;
m_axil_wvalid_next = m_axil_wvalid_reg && !m_axil_wr.wready;
m_axil_bready_next = 1'b0;
m_axil_arvalid_next = m_axil_arvalid_reg && !m_axil_rd.arready;
m_axil_rready_next = 1'b0;
case (state_reg)
STATE_IDLE: begin
m_axil_addr_next = s_apb.paddr;
m_axil_prot_next = s_apb.pprot;
m_axil_wdata_next = s_apb.pwdata;
m_axil_wstrb_next = s_apb.pstrb;
m_axil_auser_next = s_apb.pauser;
m_axil_wuser_next = s_apb.pwuser;
if (s_apb.psel && !s_apb.pready) begin
if (s_apb.pwrite) begin
m_axil_awvalid_next = 1'b1;
m_axil_wvalid_next = 1'b1;
m_axil_bready_next = 1'b1;
end else begin
m_axil_arvalid_next = 1'b1;
m_axil_rready_next = 1'b1;
end
state_next = STATE_DATA;
end else begin
state_next = STATE_IDLE;
end
end
STATE_DATA: begin
if (s_apb.pwrite) begin
m_axil_bready_next = 1'b1;
end else begin
m_axil_rready_next = 1'b1;
end
s_apb_pready_next = 1'b0;
s_apb_prdata_next = m_axil_rd.rdata;
s_apb_pslverr_next = s_apb.pwrite ? m_axil_wr.bresp[1] : m_axil_rd.rresp[1];
s_apb_pruser_next = m_axil_rd.ruser;
s_apb_pbuser_next = m_axil_wr.buser;
if (s_apb.pwrite ? (m_axil_wr.bready && m_axil_wr.bvalid) : (m_axil_rd.rready && m_axil_rd.rvalid)) begin
m_axil_bready_next = 1'b0;
m_axil_rready_next = 1'b0;
s_apb_pready_next = 1'b1;
state_next = STATE_IDLE;
end else begin
state_next = STATE_DATA;
end
end
endcase
end
always_ff @(posedge clk) begin
state_reg <= state_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_axil_addr_reg <= m_axil_addr_next;
m_axil_prot_reg <= m_axil_prot_next;
m_axil_auser_reg <= m_axil_auser_next;
m_axil_awvalid_reg <= m_axil_awvalid_next;
m_axil_wdata_reg <= m_axil_wdata_next;
m_axil_wstrb_reg <= m_axil_wstrb_next;
m_axil_wuser_reg <= m_axil_wuser_next;
m_axil_wvalid_reg <= m_axil_wvalid_next;
m_axil_bready_reg <= m_axil_bready_next;
m_axil_arvalid_reg <= m_axil_arvalid_next;
m_axil_rready_reg <= m_axil_rready_next;
if (rst) begin
state_reg <= STATE_IDLE;
s_apb_pready_reg <= 1'b0;
m_axil_awvalid_reg <= 1'b0;
m_axil_wvalid_reg <= 1'b0;
m_axil_bready_reg <= 1'b0;
m_axil_arvalid_reg <= 1'b0;
m_axil_rready_reg <= 1'b0;
end
end
end else if (AXIL_BYTE_LANES > APB_BYTE_LANES) begin : upsize
// output is wider; upsize
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
state_t state_reg = STATE_IDLE, state_next;
logic s_apb_pready_reg = 1'b0, s_apb_pready_next;
logic [APB_DATA_W-1:0] s_apb_prdata_reg = '0, s_apb_prdata_next;
logic s_apb_pslverr_reg = 1'b0, s_apb_pslverr_next;
logic [PRUSER_W-1:0] s_apb_pruser_reg = '0, s_apb_pruser_next;
logic [PBUSER_W-1:0] s_apb_pbuser_reg = '0, s_apb_pbuser_next;
logic [AXIL_ADDR_W-1:0] m_axil_addr_reg = '0, m_axil_addr_next;
logic [2:0] m_axil_prot_reg = 3'd0, m_axil_prot_next;
logic [AUSER_W-1:0] m_axil_auser_reg = '0, m_axil_auser_next;
logic m_axil_awvalid_reg = 1'b0, m_axil_awvalid_next;
logic [AXIL_DATA_W-1:0] m_axil_wdata_reg = '0, m_axil_wdata_next;
logic [AXIL_STRB_W-1:0] m_axil_wstrb_reg = '0, m_axil_wstrb_next;
logic [WUSER_W-1:0] m_axil_wuser_reg = '0, m_axil_wuser_next;
logic m_axil_wvalid_reg = 1'b0, m_axil_wvalid_next;
logic m_axil_bready_reg = 1'b0, m_axil_bready_next;
logic m_axil_arvalid_reg = 1'b0, m_axil_arvalid_next;
logic m_axil_rready_reg = 1'b0, m_axil_rready_next;
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;
assign m_axil_wr.awaddr = m_axil_addr_reg;
assign m_axil_wr.awprot = m_axil_prot_reg;
assign m_axil_wr.awuser = AWUSER_EN ? m_axil_auser_reg : '0;
assign m_axil_wr.awvalid = m_axil_awvalid_reg;
assign m_axil_wr.wdata = m_axil_wdata_reg;
assign m_axil_wr.wstrb = m_axil_wstrb_reg;
assign m_axil_wr.wuser = WUSER_EN ? m_axil_wuser_reg : '0;
assign m_axil_wr.wvalid = m_axil_wvalid_reg;
assign m_axil_wr.bready = m_axil_bready_reg;
assign m_axil_rd.araddr = m_axil_addr_reg;
assign m_axil_rd.arprot = m_axil_prot_reg;
assign m_axil_rd.aruser = ARUSER_EN ? m_axil_auser_reg : '0;
assign m_axil_rd.arvalid = m_axil_arvalid_reg;
assign m_axil_rd.rready = m_axil_rready_reg;
always_comb begin
state_next = STATE_IDLE;
s_apb_pready_next = 1'b0;
s_apb_prdata_next = s_apb_prdata_reg;
s_apb_pslverr_next = s_apb_pslverr_reg;
s_apb_pruser_next = s_apb_pruser_reg;
s_apb_pbuser_next = s_apb_pbuser_reg;
m_axil_addr_next = m_axil_addr_reg;
m_axil_prot_next = m_axil_prot_reg;
m_axil_auser_next = m_axil_auser_reg;
m_axil_awvalid_next = m_axil_awvalid_reg && !m_axil_wr.awready;
m_axil_wdata_next = m_axil_wdata_reg;
m_axil_wstrb_next = m_axil_wstrb_reg;
m_axil_wuser_next = m_axil_wuser_reg;
m_axil_wvalid_next = m_axil_wvalid_reg && !m_axil_wr.wready;
m_axil_bready_next = 1'b0;
m_axil_arvalid_next = m_axil_arvalid_reg && !m_axil_rd.arready;
m_axil_rready_next = 1'b0;
case (state_reg)
STATE_IDLE: begin
m_axil_addr_next = s_apb.paddr;
m_axil_prot_next = s_apb.pprot;
m_axil_wdata_next = {(AXIL_BYTE_LANES/APB_BYTE_LANES){s_apb.pwdata}};
m_axil_wstrb_next = '0;
m_axil_wstrb_next[s_apb.paddr[AXIL_ADDR_BIT_OFFSET - 1:APB_ADDR_BIT_OFFSET] * APB_STRB_W +: APB_STRB_W] = s_apb.pstrb;
m_axil_auser_next = s_apb.pauser;
m_axil_wuser_next = s_apb.pwuser;
if (s_apb.psel && !s_apb.pready) begin
if (s_apb.pwrite) begin
m_axil_awvalid_next = 1'b1;
m_axil_wvalid_next = 1'b1;
m_axil_bready_next = 1'b1;
end else begin
m_axil_arvalid_next = 1'b1;
m_axil_rready_next = 1'b1;
end
state_next = STATE_DATA;
end else begin
state_next = STATE_IDLE;
end
end
STATE_DATA: begin
if (s_apb.pwrite) begin
m_axil_bready_next = 1'b1;
end else begin
m_axil_rready_next = 1'b1;
end
s_apb_pready_next = 1'b0;
s_apb_prdata_next = m_axil_rd.rdata[m_axil_addr_reg[AXIL_ADDR_BIT_OFFSET - 1:APB_ADDR_BIT_OFFSET] * APB_DATA_W +: APB_DATA_W];
s_apb_pslverr_next = s_apb.pwrite ? m_axil_wr.bresp[1] : m_axil_rd.rresp[1];
s_apb_pruser_next = m_axil_rd.ruser;
s_apb_pbuser_next = m_axil_wr.buser;
if (s_apb.pwrite ? (m_axil_wr.bready && m_axil_wr.bvalid) : (m_axil_rd.rready && m_axil_rd.rvalid)) begin
m_axil_bready_next = 1'b0;
m_axil_rready_next = 1'b0;
s_apb_pready_next = 1'b1;
state_next = STATE_IDLE;
end else begin
state_next = STATE_DATA;
end
end
endcase
end
always_ff @(posedge clk) begin
state_reg <= state_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_axil_addr_reg <= m_axil_addr_next;
m_axil_prot_reg <= m_axil_prot_next;
m_axil_auser_reg <= m_axil_auser_next;
m_axil_awvalid_reg <= m_axil_awvalid_next;
m_axil_wdata_reg <= m_axil_wdata_next;
m_axil_wstrb_reg <= m_axil_wstrb_next;
m_axil_wuser_reg <= m_axil_wuser_next;
m_axil_wvalid_reg <= m_axil_wvalid_next;
m_axil_bready_reg <= m_axil_bready_next;
m_axil_arvalid_reg <= m_axil_arvalid_next;
m_axil_rready_reg <= m_axil_rready_next;
if (rst) begin
state_reg <= STATE_IDLE;
s_apb_pready_reg <= 1'b0;
m_axil_awvalid_reg <= 1'b0;
m_axil_wvalid_reg <= 1'b0;
m_axil_bready_reg <= 1'b0;
m_axil_arvalid_reg <= 1'b0;
m_axil_rready_reg <= 1'b0;
end
end
end else begin : downsize
// output is narrower; downsize
// output bus is wider
localparam DATA_W = APB_DATA_W;
localparam STRB_W = APB_STRB_W;
// required number of segments in wider bus
localparam SEG_COUNT = APB_BYTE_LANES / AXIL_BYTE_LANES;
localparam SEG_COUNT_W = $clog2(SEG_COUNT);
// data width and keep width per segment
localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT;
typedef enum logic [0:0] {
STATE_IDLE,
STATE_DATA
} state_t;
state_t state_reg = STATE_IDLE, state_next;
logic [DATA_W-1:0] data_reg = '0, data_next;
logic [STRB_W-1:0] strb_reg = '0, strb_next;
logic [SEG_COUNT_W-1:0] current_seg_reg = '0, current_seg_next;
logic s_apb_pready_reg = 1'b0, s_apb_pready_next;
logic [APB_DATA_W-1:0] s_apb_prdata_reg = '0, s_apb_prdata_next;
logic s_apb_pslverr_reg = 1'b0, s_apb_pslverr_next;
logic [PRUSER_W-1:0] s_apb_pruser_reg = '0, s_apb_pruser_next;
logic [PBUSER_W-1:0] s_apb_pbuser_reg = '0, s_apb_pbuser_next;
logic [AXIL_ADDR_W-1:0] m_axil_addr_reg = '0, m_axil_addr_next;
logic [2:0] m_axil_prot_reg = 3'd0, m_axil_prot_next;
logic [AUSER_W-1:0] m_axil_auser_reg = '0, m_axil_auser_next;
logic m_axil_awvalid_reg = 1'b0, m_axil_awvalid_next;
logic [AXIL_DATA_W-1:0] m_axil_wdata_reg = '0, m_axil_wdata_next;
logic [AXIL_STRB_W-1:0] m_axil_wstrb_reg = '0, m_axil_wstrb_next;
logic [WUSER_W-1:0] m_axil_wuser_reg = '0, m_axil_wuser_next;
logic m_axil_wvalid_reg = 1'b0, m_axil_wvalid_next;
logic m_axil_bready_reg = 1'b0, m_axil_bready_next;
logic m_axil_arvalid_reg = 1'b0, m_axil_arvalid_next;
logic m_axil_rready_reg = 1'b0, m_axil_rready_next;
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;
assign m_axil_wr.awaddr = m_axil_addr_reg;
assign m_axil_wr.awprot = m_axil_prot_reg;
assign m_axil_wr.awuser = AWUSER_EN ? m_axil_auser_reg : '0;
assign m_axil_wr.awvalid = m_axil_awvalid_reg;
assign m_axil_wr.wdata = m_axil_wdata_reg;
assign m_axil_wr.wstrb = m_axil_wstrb_reg;
assign m_axil_wr.wuser = WUSER_EN ? m_axil_wuser_reg : '0;
assign m_axil_wr.wvalid = m_axil_wvalid_reg;
assign m_axil_wr.bready = m_axil_bready_reg;
assign m_axil_rd.araddr = m_axil_addr_reg;
assign m_axil_rd.arprot = m_axil_prot_reg;
assign m_axil_rd.aruser = ARUSER_EN ? m_axil_auser_reg : '0;
assign m_axil_rd.arvalid = m_axil_arvalid_reg;
assign m_axil_rd.rready = m_axil_rready_reg;
always_comb begin
state_next = STATE_IDLE;
data_next = data_reg;
strb_next = strb_reg;
current_seg_next = current_seg_reg;
s_apb_pready_next = 1'b0;
s_apb_prdata_next = s_apb_prdata_reg;
s_apb_pslverr_next = s_apb_pslverr_reg;
s_apb_pruser_next = s_apb_pruser_reg;
s_apb_pbuser_next = s_apb_pbuser_reg;
m_axil_addr_next = m_axil_addr_reg;
m_axil_prot_next = m_axil_prot_reg;
m_axil_auser_next = m_axil_auser_reg;
m_axil_awvalid_next = m_axil_awvalid_reg && !m_axil_wr.awready;
m_axil_wdata_next = m_axil_wdata_reg;
m_axil_wstrb_next = m_axil_wstrb_reg;
m_axil_wuser_next = m_axil_wuser_reg;
m_axil_wvalid_next = m_axil_wvalid_reg && !m_axil_wr.wready;
m_axil_bready_next = 1'b0;
m_axil_arvalid_next = m_axil_arvalid_reg && !m_axil_rd.arready;
m_axil_rready_next = 1'b0;
case (state_reg)
STATE_IDLE: begin
current_seg_next = s_apb.paddr[AXIL_ADDR_BIT_OFFSET +: SEG_COUNT_W];
m_axil_addr_next = s_apb.paddr;
m_axil_prot_next = s_apb.pprot;
data_next = s_apb.pwdata;
strb_next = s_apb.pstrb;
m_axil_wdata_next = data_next[current_seg_next*SEG_DATA_W +: SEG_DATA_W];
m_axil_wstrb_next = strb_next[current_seg_next*SEG_STRB_W +: SEG_STRB_W];
m_axil_auser_next = s_apb.pauser;
m_axil_wuser_next = s_apb.pwuser;
s_apb_pslverr_next = 1'b0;
if (s_apb.psel && !s_apb.pready) begin
if (s_apb.pwrite) begin
m_axil_awvalid_next = 1'b1;
m_axil_wvalid_next = 1'b1;
m_axil_bready_next = 1'b1;
end else begin
m_axil_arvalid_next = 1'b1;
m_axil_rready_next = 1'b1;
end
state_next = STATE_DATA;
end else begin
state_next = STATE_IDLE;
end
end
STATE_DATA: begin
if (s_apb.pwrite) begin
m_axil_bready_next = 1'b1;
end else begin
m_axil_rready_next = 1'b1;
end
s_apb_pready_next = 1'b0;
s_apb_prdata_next[current_seg_reg*SEG_DATA_W +: SEG_DATA_W] = m_axil_rd.rdata;
if (s_apb.pwrite ? m_axil_wr.bresp[1] : m_axil_rd.rresp[1]) begin
s_apb_pslverr_next = 1'b1;
end
s_apb_pruser_next = m_axil_rd.ruser;
s_apb_pbuser_next = m_axil_wr.buser;
if (s_apb.pwrite ? (m_axil_wr.bready && m_axil_wr.bvalid) : (m_axil_rd.rready && m_axil_rd.rvalid)) begin
m_axil_bready_next = 1'b0;
m_axil_rready_next = 1'b0;
current_seg_next = current_seg_reg + 1;
m_axil_addr_next = (m_axil_addr_reg & AXIL_ADDR_MASK) + SEG_STRB_W;
m_axil_wdata_next = data_next[current_seg_next*SEG_DATA_W +: SEG_DATA_W];
m_axil_wstrb_next = strb_next[current_seg_next*SEG_STRB_W +: SEG_STRB_W];
if (current_seg_reg == SEG_COUNT_W'(SEG_COUNT-1)) begin
s_apb_pready_next = 1'b1;
state_next = STATE_IDLE;
end else begin
if (s_apb.pwrite) begin
m_axil_awvalid_next = 1'b1;
m_axil_wvalid_next = 1'b1;
m_axil_bready_next = 1'b1;
end else begin
m_axil_arvalid_next = 1'b1;
m_axil_rready_next = 1'b1;
end
state_next = STATE_DATA;
end
end else begin
state_next = STATE_DATA;
end
end
endcase
end
always_ff @(posedge clk) begin
state_reg <= state_next;
data_reg <= data_next;
strb_reg <= strb_next;
current_seg_reg <= current_seg_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_axil_addr_reg <= m_axil_addr_next;
m_axil_prot_reg <= m_axil_prot_next;
m_axil_auser_reg <= m_axil_auser_next;
m_axil_awvalid_reg <= m_axil_awvalid_next;
m_axil_wdata_reg <= m_axil_wdata_next;
m_axil_wstrb_reg <= m_axil_wstrb_next;
m_axil_wuser_reg <= m_axil_wuser_next;
m_axil_wvalid_reg <= m_axil_wvalid_next;
m_axil_bready_reg <= m_axil_bready_next;
m_axil_arvalid_reg <= m_axil_arvalid_next;
m_axil_rready_reg <= m_axil_rready_next;
if (rst) begin
state_reg <= STATE_IDLE;
s_apb_pready_reg <= 1'b0;
m_axil_awvalid_reg <= 1'b0;
m_axil_wvalid_reg <= 1'b0;
m_axil_bready_reg <= 1'b0;
m_axil_arvalid_reg <= 1'b0;
m_axil_rready_reg <= 1'b0;
end
end
end
endmodule
`resetall

View File

@@ -77,7 +77,7 @@ logic [DATA_W-1:0] s_apb_b_prdata_pipe_reg = '0;
// verilator lint_off MULTIDRIVEN // verilator lint_off MULTIDRIVEN
// (* RAM_STYLE="BLOCK" *) // (* RAM_STYLE="BLOCK" *)
logic [DATA_W-1:0] mem[2**VALID_ADDR_W]; logic [DATA_W-1:0] mem[2**VALID_ADDR_W] = '{default: '0};
// verilator lint_on MULTIDRIVEN // verilator lint_on MULTIDRIVEN
wire [VALID_ADDR_W-1:0] s_apb_a_paddr_valid = VALID_ADDR_W'(s_apb_a.paddr >> (ADDR_W - VALID_ADDR_W)); wire [VALID_ADDR_W-1:0] s_apb_a_paddr_valid = VALID_ADDR_W'(s_apb_a.paddr >> (ADDR_W - VALID_ADDR_W));
@@ -95,23 +95,13 @@ assign s_apb_b.pslverr = 1'b0;
assign s_apb_b.pruser = '0; assign s_apb_b.pruser = '0;
assign s_apb_b.pbuser = '0; assign s_apb_b.pbuser = '0;
initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (integer i = 0; i < 2**VALID_ADDR_W; i = i + 2**(VALID_ADDR_W/2)) begin
for (integer j = i; j < i + 2**(VALID_ADDR_W/2); j = j + 1) begin
mem[j] = '0;
end
end
end
always_comb begin always_comb begin
mem_wr_en_a = 1'b0; mem_wr_en_a = 1'b0;
mem_rd_en_a = 1'b0; mem_rd_en_a = 1'b0;
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
@@ -149,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

@@ -59,7 +59,7 @@ logic [DATA_W-1:0] s_apb_prdata_reg = '0, s_apb_prdata_next;
logic [DATA_W-1:0] s_apb_prdata_pipe_reg = '0; logic [DATA_W-1:0] s_apb_prdata_pipe_reg = '0;
// (* RAM_STYLE="BLOCK" *) // (* RAM_STYLE="BLOCK" *)
logic [DATA_W-1:0] mem[2**VALID_ADDR_W]; logic [DATA_W-1:0] mem[2**VALID_ADDR_W] = '{default: '0};
wire [VALID_ADDR_W-1:0] s_apb_paddr_valid = VALID_ADDR_W'(s_apb.paddr >> (ADDR_W - VALID_ADDR_W)); wire [VALID_ADDR_W-1:0] s_apb_paddr_valid = VALID_ADDR_W'(s_apb.paddr >> (ADDR_W - VALID_ADDR_W));
@@ -69,23 +69,13 @@ assign s_apb.pslverr = 1'b0;
assign s_apb.pruser = '0; assign s_apb.pruser = '0;
assign s_apb.pbuser = '0; assign s_apb.pbuser = '0;
initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (integer i = 0; i < 2**VALID_ADDR_W; i = i + 2**(VALID_ADDR_W/2)) begin
for (integer j = i; j < i + 2**(VALID_ADDR_W/2); j = j + 1) begin
mem[j] = '0;
end
end
end
always_comb begin always_comb begin
mem_wr_en = 1'b0; mem_wr_en = 1'b0;
mem_rd_en = 1'b0; mem_rd_en = 1'b0;
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

@@ -0,0 +1,64 @@
# 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_apb_axil_adapter
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
VERILOG_SOURCES += $(TAXI_SRC_DIR)/axi/rtl/taxi_axil_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_ADDR_W := 32
export PARAM_APB_DATA_W := 32
export PARAM_APB_STRB_W := $(shell expr $(PARAM_APB_DATA_W) / 8 )
export PARAM_AXIL_DATA_W := 32
export PARAM_AXIL_STRB_W := $(shell expr $(PARAM_AXIL_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 += $(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,239 @@
#!/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 ApbBus, ApbMaster, AxiLiteBus, AxiLiteRam
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.axil_ram = AxiLiteRam(AxiLiteBus.from_entity(dut.m_axil), dut.clk, dut.rst, size=2**16)
def set_idle_generator(self, generator=None):
if generator:
self.apb_master.set_pause_generator(generator())
self.axil_ram.write_if.b_channel.set_pause_generator(generator())
self.axil_ram.read_if.r_channel.set_pause_generator(generator())
def set_backpressure_generator(self, generator=None):
if generator:
self.axil_ram.write_if.aw_channel.set_pause_generator(generator())
self.axil_ram.write_if.w_channel.set_pause_generator(generator())
self.axil_ram.read_if.ar_channel.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):
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)
addr = offset+0x1000
test_data = bytearray([x % 256 for x in range(length)])
tb.axil_ram.write(addr-128, b'\xaa'*(length+256))
await tb.apb_master.write(addr, test_data)
tb.log.debug("%s", tb.axil_ram.hexdump_str((addr & ~0xf)-16, (((addr & 0xf)+length-1) & ~0xf)+48))
assert tb.axil_ram.read(addr, length) == test_data
assert tb.axil_ram.read(addr-1, 1) == b'\xaa'
assert tb.axil_ram.read(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):
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)
addr = offset+0x1000
test_data = bytearray([x % 256 for x in range(length)])
tb.axil_ram.write(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):
length = random.randint(1, min(32, 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.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:
for test in [run_test_write, run_test_read, run_stress_test]:
factory = TestFactory(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("axil_data_w", [8, 16, 32])
@pytest.mark.parametrize("apb_data_w", [8, 16, 32])
def test_taxi_apb_axil_adapter(request, apb_data_w, axil_data_w):
dut = "taxi_apb_axil_adapter"
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"),
os.path.join(taxi_src_dir, "axi", "rtl", "taxi_axil_if.sv"),
]
verilog_sources = process_f_files(verilog_sources)
parameters = {}
parameters['ADDR_W'] = 32
parameters['APB_DATA_W'] = apb_data_w
parameters['APB_STRB_W'] = parameters['APB_DATA_W'] // 8
parameters['AXIL_DATA_W'] = axil_data_w
parameters['AXIL_STRB_W'] = parameters['AXIL_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,90 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2026 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* APB to AXI4 lite adapter testbench
*/
module test_taxi_apb_axil_adapter #
(
/* verilator lint_off WIDTHTRUNC */
parameter ADDR_W = 32,
parameter APB_DATA_W = 32,
parameter APB_STRB_W = (APB_DATA_W/8),
parameter AXIL_DATA_W = 32,
parameter AXIL_STRB_W = (AXIL_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
/* verilator lint_on WIDTHTRUNC */
)
();
logic clk;
logic rst;
taxi_apb_if #(
.DATA_W(APB_DATA_W),
.ADDR_W(ADDR_W),
.STRB_W(APB_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();
taxi_axil_if #(
.DATA_W(AXIL_DATA_W),
.ADDR_W(ADDR_W),
.STRB_W(AXIL_STRB_W),
.AWUSER_EN(PAUSER_EN),
.AWUSER_W(PAUSER_W),
.WUSER_EN(PWUSER_EN),
.WUSER_W(PWUSER_W),
.BUSER_EN(PBUSER_EN),
.BUSER_W(PBUSER_W),
.ARUSER_EN(PAUSER_EN),
.ARUSER_W(PAUSER_W),
.RUSER_EN(PRUSER_EN),
.RUSER_W(PRUSER_W)
) m_axil();
taxi_apb_axil_adapter
uut (
.clk(clk),
.rst(rst),
/*
* APB slave interface
*/
.s_apb(s_apb),
/*
* AXI4-Lite master interface
*/
.m_axil_wr(m_axil),
.m_axil_rd(m_axil)
);
endmodule
`resetall

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

@@ -115,13 +115,14 @@ end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT; localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DATA = 2'd1, STATE_DATA,
STATE_DATA_READ = 2'd2, STATE_DATA_READ,
STATE_DATA_SPLIT = 2'd3; STATE_DATA_SPLIT
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic [ID_W-1:0] id_reg = '0, id_next; logic [ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next; logic [ADDR_W-1:0] addr_reg = '0, addr_next;
@@ -480,11 +481,12 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT; localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic [ID_W-1:0] id_reg = '0, id_next; logic [ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next; logic [ADDR_W-1:0] addr_reg = '0, addr_next;

View File

@@ -122,13 +122,14 @@ end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT; localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DATA = 2'd1, STATE_DATA,
STATE_DATA_2 = 2'd2, STATE_DATA_2,
STATE_RESP = 2'd3; STATE_RESP
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic [ID_W-1:0] id_reg = '0, id_next; logic [ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next; logic [ADDR_W-1:0] addr_reg = '0, addr_next;
@@ -505,13 +506,14 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT; localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DATA = 2'd1, STATE_DATA,
STATE_DATA_2 = 2'd2, STATE_DATA_2,
STATE_RESP = 2'd3; STATE_RESP
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic [ID_W-1:0] id_reg = '0, id_next; logic [ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next; logic [ADDR_W-1:0] addr_reg = '0, addr_next;

View File

@@ -89,11 +89,12 @@ if (AXIL_BYTE_LANES == AXI_BYTE_LANES) begin : translate
localparam SEG_DATA_W = DATA_W / SEG_COUNT; localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic [AXI_ID_W-1:0] id_reg = '0, id_next; logic [AXI_ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next; logic [ADDR_W-1:0] addr_reg = '0, addr_next;
@@ -251,13 +252,14 @@ end else if (AXIL_BYTE_LANES > AXI_BYTE_LANES) begin : upsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT; localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DATA = 2'd1, STATE_DATA,
STATE_DATA_READ = 2'd2, STATE_DATA_READ,
STATE_DATA_SPLIT = 2'd3; STATE_DATA_SPLIT
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic [AXI_ID_W-1:0] id_reg = '0, id_next; logic [AXI_ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next; logic [ADDR_W-1:0] addr_reg = '0, addr_next;
@@ -483,11 +485,12 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT; localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic [AXI_ID_W-1:0] id_reg = '0, id_next; logic [AXI_ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next; logic [ADDR_W-1:0] addr_reg = '0, addr_next;

View File

@@ -91,12 +91,13 @@ if (AXIL_BYTE_LANES == AXI_BYTE_LANES) begin : translate
localparam SEG_DATA_W = DATA_W / SEG_COUNT; localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DATA = 2'd1, STATE_DATA,
STATE_RESP = 2'd2; STATE_RESP
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic [AXI_ID_W-1:0] id_reg = '0, id_next; logic [AXI_ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next; logic [ADDR_W-1:0] addr_reg = '0, addr_next;
@@ -295,13 +296,14 @@ end else if (AXIL_BYTE_LANES > AXI_BYTE_LANES) begin : upsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT; localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DATA = 2'd1, STATE_DATA,
STATE_DATA_2 = 2'd2, STATE_DATA_2,
STATE_RESP = 2'd3; STATE_RESP
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic [AXI_ID_W-1:0] id_reg = '0, id_next; logic [AXI_ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next; logic [ADDR_W-1:0] addr_reg = '0, addr_next;
@@ -547,13 +549,14 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT; localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DATA = 2'd1, STATE_DATA,
STATE_DATA_2 = 2'd2, STATE_DATA_2,
STATE_RESP = 2'd3; STATE_RESP
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic [AXI_ID_W-1:0] id_reg = '0, id_next; logic [AXI_ID_W-1:0] id_reg = '0, id_next;
logic [ADDR_W-1:0] addr_reg = '0, addr_next; logic [ADDR_W-1:0] addr_reg = '0, addr_next;

View File

@@ -213,11 +213,12 @@ initial begin
end end
end end
localparam logic [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DECODE = 1'd1; STATE_DECODE
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic s_axi_aready_reg = 1'b0, s_axi_aready_next; logic s_axi_aready_reg = 1'b0, s_axi_aready_next;
@@ -250,10 +251,10 @@ logic [TR_CNT_W-1:0] trans_count_reg = 0;
wire trans_limit = trans_count_reg >= TR_CNT_W'(S_ACCEPT) && !trans_complete; wire trans_limit = trans_count_reg >= TR_CNT_W'(S_ACCEPT) && !trans_complete;
// transfer ID thread tracking // transfer ID thread tracking
logic [ID_W-1:0] thread_id_reg[S_INT_THREADS-1:0]; logic [ID_W-1:0] thread_id_reg[S_INT_THREADS-1:0] = '{default: '0};
logic [SEL_W-1:0] thread_m_reg[S_INT_THREADS-1:0]; logic [SEL_W-1:0] thread_m_reg[S_INT_THREADS-1:0] = '{default: '0};
logic [3:0] thread_region_reg[S_INT_THREADS-1:0]; logic [3:0] thread_region_reg[S_INT_THREADS-1:0] = '{default: '0};
logic [$clog2(S_ACCEPT+1)-1:0] thread_count_reg[S_INT_THREADS-1:0]; logic [$clog2(S_ACCEPT+1)-1:0] thread_count_reg[S_INT_THREADS-1:0] = '{default: '0};
// TODO fix loop // TODO fix loop
/* verilator lint_off UNOPTFLAT */ /* verilator lint_off UNOPTFLAT */
@@ -265,10 +266,6 @@ wire [S_INT_THREADS-1:0] thread_trans_start;
wire [S_INT_THREADS-1:0] thread_trans_complete; wire [S_INT_THREADS-1:0] thread_trans_complete;
for (genvar n = 0; n < S_INT_THREADS; n = n + 1) begin for (genvar n = 0; n < S_INT_THREADS; n = n + 1) begin
initial begin
thread_count_reg[n] = '0;
end
assign thread_active[n] = thread_count_reg[n] != 0; assign thread_active[n] = thread_count_reg[n] != 0;
assign thread_match[n] = thread_active[n] && thread_id_reg[n] == s_axi_aid; assign thread_match[n] = thread_active[n] && thread_id_reg[n] == s_axi_aid;
assign thread_match_dest[n] = thread_match[n] && thread_m_reg[n] == m_select_next && (M_REGIONS < 2 || thread_region_reg[n] == m_axi_aregion_next); assign thread_match_dest[n] = thread_match[n] && thread_m_reg[n] == m_select_next && (M_REGIONS < 2 || thread_region_reg[n] == m_axi_aregion_next);

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

@@ -100,11 +100,12 @@ if (FIFO_DELAY) begin
localparam COUNT_W = (FIFO_AW > 8 ? FIFO_AW : 8) + 1; localparam COUNT_W = (FIFO_AW > 8 ? FIFO_AW : 8) + 1;
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_WAIT = 1'd1; STATE_WAIT
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic [COUNT_W-1:0] count_reg = 0, count_next; logic [COUNT_W-1:0] count_reg = 0, count_next;

View File

@@ -99,12 +99,13 @@ if (WUSER_EN) assign s_axi_w[WUSER_OFFSET +: WUSER_W] = s_axi_wr.wuser;
if (FIFO_DELAY) begin if (FIFO_DELAY) begin
// store AW channel value until W channel burst is stored in FIFO or FIFO is full // store AW channel value until W channel burst is stored in FIFO or FIFO is full
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_TRANSFER_IN = 2'd1, STATE_TRANSFER_IN,
STATE_TRANSFER_OUT = 2'd2; STATE_TRANSFER_OUT
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic hold_reg = 1'b1, hold_next; logic hold_reg = 1'b1, hold_next;
logic [8:0] count_reg = 9'd0, count_next; logic [8:0] count_reg = 9'd0, count_next;

View File

@@ -182,14 +182,15 @@ initial begin
end end
end end
localparam logic [2:0] typedef enum logic [2:0] {
STATE_IDLE = 3'd0, STATE_IDLE,
STATE_DECODE = 3'd1, STATE_DECODE,
STATE_READ = 3'd2, STATE_READ,
STATE_READ_DROP = 3'd3, STATE_READ_DROP,
STATE_WAIT_IDLE = 3'd4; STATE_WAIT_IDLE
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic match; logic match;

View File

@@ -186,15 +186,16 @@ initial begin
end end
end end
localparam logic [2:0] typedef enum logic [2:0] {
STATE_IDLE = 3'd0, STATE_IDLE,
STATE_DECODE = 3'd1, STATE_DECODE,
STATE_WRITE = 3'd2, STATE_WRITE,
STATE_WRITE_RESP = 3'd3, STATE_WRITE_RESP,
STATE_WRITE_DROP = 3'd4, STATE_WRITE_DROP,
STATE_WAIT_IDLE = 3'd5; STATE_WAIT_IDLE
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic match; logic match;

View File

@@ -56,18 +56,20 @@ if (s_axi_wr.DATA_W != s_axi_rd.DATA_W)
if (s_axi_wr.ADDR_W < ADDR_W || s_axi_rd.ADDR_W < ADDR_W) if (s_axi_wr.ADDR_W < ADDR_W || s_axi_rd.ADDR_W < ADDR_W)
$fatal(0, "Error: AXI address width is insufficient (instance %m)"); $fatal(0, "Error: AXI address width is insufficient (instance %m)");
localparam [0:0] typedef enum logic [0:0] {
READ_STATE_IDLE = 1'd0, READ_STATE_IDLE,
READ_STATE_BURST = 1'd1; READ_STATE_BURST
} read_state_t;
logic [0:0] read_state_reg = READ_STATE_IDLE, read_state_next; read_state_t read_state_reg = READ_STATE_IDLE, read_state_next;
localparam [1:0] typedef enum logic [1:0] {
WRITE_STATE_IDLE = 2'd0, WRITE_STATE_IDLE,
WRITE_STATE_BURST = 2'd1, WRITE_STATE_BURST,
WRITE_STATE_RESP = 2'd2; WRITE_STATE_RESP
} write_state_t;
logic [1:0] write_state_reg = WRITE_STATE_IDLE, write_state_next; write_state_t write_state_reg = WRITE_STATE_IDLE, write_state_next;
logic mem_wr_en; logic mem_wr_en;
logic mem_rd_en; logic mem_rd_en;
@@ -98,7 +100,7 @@ logic s_axi_rlast_pipe_reg = 1'b0;
logic s_axi_rvalid_pipe_reg = 1'b0; logic s_axi_rvalid_pipe_reg = 1'b0;
// (* RAM_STYLE="BLOCK" *) // (* RAM_STYLE="BLOCK" *)
logic [DATA_W-1:0] mem[2**VALID_ADDR_W]; logic [DATA_W-1:0] mem[2**VALID_ADDR_W] = '{default: '0};
wire [VALID_ADDR_W-1:0] read_addr_valid = VALID_ADDR_W'(read_addr_reg >> (ADDR_W - VALID_ADDR_W)); wire [VALID_ADDR_W-1:0] read_addr_valid = VALID_ADDR_W'(read_addr_reg >> (ADDR_W - VALID_ADDR_W));
wire [VALID_ADDR_W-1:0] write_addr_valid = VALID_ADDR_W'(write_addr_reg >> (ADDR_W - VALID_ADDR_W)); wire [VALID_ADDR_W-1:0] write_addr_valid = VALID_ADDR_W'(write_addr_reg >> (ADDR_W - VALID_ADDR_W));
@@ -118,16 +120,6 @@ assign s_axi_rd.rlast = PIPELINE_OUTPUT ? s_axi_rlast_pipe_reg : s_axi_rlast_reg
assign s_axi_rd.ruser = '0; assign s_axi_rd.ruser = '0;
assign s_axi_rd.rvalid = PIPELINE_OUTPUT ? s_axi_rvalid_pipe_reg : s_axi_rvalid_reg; assign s_axi_rd.rvalid = PIPELINE_OUTPUT ? s_axi_rvalid_pipe_reg : s_axi_rvalid_reg;
initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (integer i = 0; i < 2**VALID_ADDR_W; i = i + 2**(VALID_ADDR_W/2)) begin
for (integer j = i; j < i + 2**(VALID_ADDR_W/2); j = j + 1) begin
mem[j] = '0;
end
end
end
always_comb begin always_comb begin
write_state_next = WRITE_STATE_IDLE; write_state_next = WRITE_STATE_IDLE;

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

@@ -86,11 +86,12 @@ if (M_BYTE_LANES == S_BYTE_LANES) begin : bypass
end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize
// output is wider; upsize // output is wider; upsize
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic s_axil_arready_reg = 1'b0, s_axil_arready_next; logic s_axil_arready_reg = 1'b0, s_axil_arready_next;
logic [S_DATA_W-1:0] s_axil_rdata_reg = '0, s_axil_rdata_next; logic [S_DATA_W-1:0] s_axil_rdata_reg = '0, s_axil_rdata_next;
@@ -203,11 +204,12 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT; localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic [SEG_COUNT_W-1:0] current_seg_reg = '0, current_seg_next; logic [SEG_COUNT_W-1:0] current_seg_reg = '0, current_seg_next;

View File

@@ -93,11 +93,12 @@ if (M_BYTE_LANES == S_BYTE_LANES) begin : bypass
end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize
// output is wider; upsize // output is wider; upsize
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic s_axil_awready_reg = 1'b0, s_axil_awready_next; logic s_axil_awready_reg = 1'b0, s_axil_awready_next;
logic s_axil_wready_reg = 1'b0, s_axil_wready_next; logic s_axil_wready_reg = 1'b0, s_axil_wready_next;
@@ -220,12 +221,13 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT; localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DATA = 2'd1, STATE_DATA,
STATE_RESP = 2'd3; STATE_RESP
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic [DATA_W-1:0] data_reg = '0, data_next; logic [DATA_W-1:0] data_reg = '0, data_next;
logic [STRB_W-1:0] strb_reg = '0, strb_next; logic [STRB_W-1:0] strb_reg = '0, strb_next;

View File

@@ -96,11 +96,12 @@ localparam [1:0]
if (APB_BYTE_LANES == AXIL_BYTE_LANES) begin : translate if (APB_BYTE_LANES == AXIL_BYTE_LANES) begin : translate
// same width; translate // same width; translate
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic last_read_reg = 1'b0, last_read_next; logic last_read_reg = 1'b0, last_read_next;
@@ -294,11 +295,12 @@ if (APB_BYTE_LANES == AXIL_BYTE_LANES) begin : translate
end else if (APB_BYTE_LANES > AXIL_BYTE_LANES) begin : upsize end else if (APB_BYTE_LANES > AXIL_BYTE_LANES) begin : upsize
// output is wider; upsize // output is wider; upsize
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic last_read_reg = 1'b0, last_read_next; logic last_read_reg = 1'b0, last_read_next;
@@ -418,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;
@@ -503,11 +508,12 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT; localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic last_read_reg = 1'b0, last_read_next; logic last_read_reg = 1'b0, last_read_next;
@@ -600,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;
@@ -643,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

@@ -95,11 +95,12 @@ if (AXI_BYTE_LANES == AXIL_BYTE_LANES) begin : bypass
end else if (AXI_BYTE_LANES > AXIL_BYTE_LANES) begin : upsize end else if (AXI_BYTE_LANES > AXIL_BYTE_LANES) begin : upsize
// output is wider; upsize // output is wider; upsize
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic s_axil_arready_reg = 1'b0, s_axil_arready_next; logic s_axil_arready_reg = 1'b0, s_axil_arready_next;
logic [AXIL_DATA_W-1:0] s_axil_rdata_reg = '0, s_axil_rdata_next; logic [AXIL_DATA_W-1:0] s_axil_rdata_reg = '0, s_axil_rdata_next;
@@ -220,11 +221,12 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT; localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic [SEG_COUNT_W-1:0] current_seg_reg = '0, current_seg_next; logic [SEG_COUNT_W-1:0] current_seg_reg = '0, current_seg_next;

View File

@@ -103,11 +103,12 @@ if (M_BYTE_LANES == S_BYTE_LANES) begin : bypass
end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize
// output is wider; upsize // output is wider; upsize
localparam [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DATA = 1'd1; STATE_DATA
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic s_axil_awready_reg = 1'b0, s_axil_awready_next; logic s_axil_awready_reg = 1'b0, s_axil_awready_next;
logic s_axil_wready_reg = 1'b0, s_axil_wready_next; logic s_axil_wready_reg = 1'b0, s_axil_wready_next;
@@ -239,12 +240,13 @@ end else begin : downsize
localparam SEG_DATA_W = DATA_W / SEG_COUNT; localparam SEG_DATA_W = DATA_W / SEG_COUNT;
localparam SEG_STRB_W = STRB_W / SEG_COUNT; localparam SEG_STRB_W = STRB_W / SEG_COUNT;
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DATA = 2'd1, STATE_DATA,
STATE_RESP = 2'd3; STATE_RESP
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic [DATA_W-1:0] data_reg = '0, data_next; logic [DATA_W-1:0] data_reg = '0, data_next;
logic [STRB_W-1:0] strb_reg = '0, strb_next; logic [STRB_W-1:0] strb_reg = '0, strb_next;

View File

@@ -189,11 +189,12 @@ initial begin
end end
end end
localparam logic [0:0] typedef enum logic [0:0] {
STATE_IDLE = 1'd0, STATE_IDLE,
STATE_DECODE = 1'd1; STATE_DECODE
} state_t;
logic [0:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic s_axil_aready_reg = 1'b0, s_axil_aready_next; logic s_axil_aready_reg = 1'b0, s_axil_aready_next;

View File

@@ -155,9 +155,9 @@ for (genvar m = 0; m < S_COUNT; m = m + 1) begin : s_ifaces
logic [FIFO_AW+1-1:0] fifo_rd_ptr_reg = 0; logic [FIFO_AW+1-1:0] fifo_rd_ptr_reg = 0;
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *) (* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [CL_M_COUNT_INT-1:0] fifo_select[2**FIFO_AW]; logic [CL_M_COUNT_INT-1:0] fifo_select[2**FIFO_AW] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *) (* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic fifo_decerr[2**FIFO_AW]; logic fifo_decerr[2**FIFO_AW] = '{default: '0};
wire [CL_M_COUNT_INT-1:0] fifo_wr_select; wire [CL_M_COUNT_INT-1:0] fifo_wr_select;
wire fifo_wr_decerr; wire fifo_wr_decerr;
@@ -171,15 +171,6 @@ for (genvar m = 0; m < S_COUNT; m = m + 1) begin : s_ifaces
wire fifo_empty = fifo_rd_ptr_reg == fifo_wr_ptr_reg; wire fifo_empty = fifo_rd_ptr_reg == fifo_wr_ptr_reg;
integer i;
initial begin
for (i = 0; i < 2**FIFO_AW; i = i + 1) begin
fifo_select[i] = 0;
fifo_decerr[i] = 0;
end
end
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
if (fifo_wr_en) begin if (fifo_wr_en) begin
fifo_select[fifo_wr_ptr_reg[FIFO_AW-1:0]] <= fifo_wr_select; fifo_select[fifo_wr_ptr_reg[FIFO_AW-1:0]] <= fifo_wr_select;
@@ -321,7 +312,7 @@ for (genvar n = 0; n < M_COUNT; n = n + 1) begin : m_ifaces
logic [FIFO_AW+1-1:0] fifo_rd_ptr_reg = '0; logic [FIFO_AW+1-1:0] fifo_rd_ptr_reg = '0;
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *) (* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [CL_S_COUNT_INT-1:0] fifo_select[2**FIFO_AW]; logic [CL_S_COUNT_INT-1:0] fifo_select[2**FIFO_AW] = '{default: '0};
wire [CL_S_COUNT_INT-1:0] fifo_wr_select; wire [CL_S_COUNT_INT-1:0] fifo_wr_select;
wire fifo_wr_en; wire fifo_wr_en;
wire fifo_rd_en; wire fifo_rd_en;
@@ -329,12 +320,6 @@ for (genvar n = 0; n < M_COUNT; n = n + 1) begin : m_ifaces
wire fifo_empty = fifo_rd_ptr_reg == fifo_wr_ptr_reg; wire fifo_empty = fifo_rd_ptr_reg == fifo_wr_ptr_reg;
initial begin
for (integer i = 0; i < 2**FIFO_AW; i = i + 1) begin
fifo_select[i] = '0;
end
end
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
if (fifo_wr_en) begin if (fifo_wr_en) begin
fifo_select[fifo_wr_ptr_reg[FIFO_AW-1:0]] <= fifo_wr_select; fifo_select[fifo_wr_ptr_reg[FIFO_AW-1:0]] <= fifo_wr_select;

View File

@@ -172,9 +172,9 @@ for (genvar m = 0; m < S_COUNT; m = m + 1) begin : s_ifaces
logic [FIFO_AW+1-1:0] fifo_rd_ptr_reg = '0; logic [FIFO_AW+1-1:0] fifo_rd_ptr_reg = '0;
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *) (* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [CL_M_COUNT_INT-1:0] fifo_select[2**FIFO_AW]; logic [CL_M_COUNT_INT-1:0] fifo_select[2**FIFO_AW] = '{default: '0};
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *) (* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic fifo_decerr[2**FIFO_AW]; logic fifo_decerr[2**FIFO_AW] = '{default: '0};
wire [CL_M_COUNT_INT-1:0] fifo_wr_select; wire [CL_M_COUNT_INT-1:0] fifo_wr_select;
wire fifo_wr_decerr; wire fifo_wr_decerr;
@@ -188,13 +188,6 @@ for (genvar m = 0; m < S_COUNT; m = m + 1) begin : s_ifaces
wire fifo_empty = fifo_rd_ptr_reg == fifo_wr_ptr_reg; wire fifo_empty = fifo_rd_ptr_reg == fifo_wr_ptr_reg;
initial begin
for (integer i = 0; i < 2**FIFO_AW; i = i + 1) begin
fifo_select[i] = '0;
fifo_decerr[i] = '0;
end
end
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
if (fifo_wr_en) begin if (fifo_wr_en) begin
fifo_select[fifo_wr_ptr_reg[FIFO_AW-1:0]] <= fifo_wr_select; fifo_select[fifo_wr_ptr_reg[FIFO_AW-1:0]] <= fifo_wr_select;
@@ -382,7 +375,7 @@ for (genvar n = 0; n < M_COUNT; n = n + 1) begin : m_ifaces
logic [FIFO_AW+1-1:0] fifo_rd_ptr_reg = '0; logic [FIFO_AW+1-1:0] fifo_rd_ptr_reg = '0;
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *) (* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
logic [CL_S_COUNT_INT-1:0] fifo_select[2**FIFO_AW]; logic [CL_S_COUNT_INT-1:0] fifo_select[2**FIFO_AW] = '{default: '0};
wire [CL_S_COUNT_INT-1:0] fifo_wr_select; wire [CL_S_COUNT_INT-1:0] fifo_wr_select;
wire fifo_wr_en; wire fifo_wr_en;
wire fifo_rd_en; wire fifo_rd_en;
@@ -390,12 +383,6 @@ for (genvar n = 0; n < M_COUNT; n = n + 1) begin : m_ifaces
wire fifo_empty = fifo_rd_ptr_reg == fifo_wr_ptr_reg; wire fifo_empty = fifo_rd_ptr_reg == fifo_wr_ptr_reg;
initial begin
for (integer i = 0; i < 2**FIFO_AW; i = i + 1) begin
fifo_select[i] = '0;
end
end
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
if (fifo_wr_en) begin if (fifo_wr_en) begin
fifo_select[fifo_wr_ptr_reg[FIFO_AW-1:0]] <= fifo_wr_select; fifo_select[fifo_wr_ptr_reg[FIFO_AW-1:0]] <= fifo_wr_select;

View File

@@ -96,7 +96,7 @@ logic s_axil_b_rvalid_pipe_reg = 1'b0;
// verilator lint_off MULTIDRIVEN // verilator lint_off MULTIDRIVEN
// (* RAM_STYLE="BLOCK" *) // (* RAM_STYLE="BLOCK" *)
logic [DATA_W-1:0] mem[2**VALID_ADDR_W]; logic [DATA_W-1:0] mem[2**VALID_ADDR_W] = '{default: '0};
// verilator lint_on MULTIDRIVEN // verilator lint_on MULTIDRIVEN
wire [VALID_ADDR_W-1:0] s_axil_a_awaddr_valid = VALID_ADDR_W'(s_axil_wr_a.awaddr >> (ADDR_W - VALID_ADDR_W)); wire [VALID_ADDR_W-1:0] s_axil_a_awaddr_valid = VALID_ADDR_W'(s_axil_wr_a.awaddr >> (ADDR_W - VALID_ADDR_W));
@@ -129,16 +129,6 @@ assign s_axil_rd_b.rresp = 2'b00;
assign s_axil_rd_b.ruser = '0; assign s_axil_rd_b.ruser = '0;
assign s_axil_rd_b.rvalid = PIPELINE_OUTPUT ? s_axil_b_rvalid_pipe_reg : s_axil_b_rvalid_reg; assign s_axil_rd_b.rvalid = PIPELINE_OUTPUT ? s_axil_b_rvalid_pipe_reg : s_axil_b_rvalid_reg;
initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (integer i = 0; i < 2**VALID_ADDR_W; i = i + 2**(VALID_ADDR_W/2)) begin
for (integer j = i; j < i + 2**(VALID_ADDR_W/2); j = j + 1) begin
mem[j] = 0;
end
end
end
always_comb begin always_comb begin
mem_wr_en_a = 1'b0; mem_wr_en_a = 1'b0;
mem_rd_en_a = 1'b0; mem_rd_en_a = 1'b0;

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

@@ -177,13 +177,14 @@ initial begin
end end
end end
localparam logic [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_DECODE = 2'd1, STATE_DECODE,
STATE_READ = 2'd2, STATE_READ,
STATE_WAIT_IDLE = 2'd3; STATE_WAIT_IDLE
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic match; logic match;

View File

@@ -179,15 +179,16 @@ initial begin
end end
end end
localparam logic [2:0] typedef enum logic [2:0] {
STATE_IDLE = 3'd0, STATE_IDLE,
STATE_DECODE = 3'd1, STATE_DECODE,
STATE_WRITE = 3'd2, STATE_WRITE,
STATE_WRITE_RESP = 3'd3, STATE_WRITE_RESP,
STATE_WRITE_DROP = 3'd4, STATE_WRITE_DROP,
STATE_WAIT_IDLE = 3'd5; STATE_WAIT_IDLE
} state_t;
logic [2:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic match; logic match;

View File

@@ -67,7 +67,7 @@ logic [DATA_W-1:0] s_axil_rdata_pipe_reg = '0;
logic s_axil_rvalid_pipe_reg = 1'b0; logic s_axil_rvalid_pipe_reg = 1'b0;
// (* RAM_STYLE="BLOCK" *) // (* RAM_STYLE="BLOCK" *)
logic [DATA_W-1:0] mem[2**VALID_ADDR_W]; logic [DATA_W-1:0] mem[2**VALID_ADDR_W] = '{default: '0};
wire [VALID_ADDR_W-1:0] s_axil_awaddr_valid = VALID_ADDR_W'(s_axil_wr.awaddr >> (ADDR_W - VALID_ADDR_W)); wire [VALID_ADDR_W-1:0] s_axil_awaddr_valid = VALID_ADDR_W'(s_axil_wr.awaddr >> (ADDR_W - VALID_ADDR_W));
wire [VALID_ADDR_W-1:0] s_axil_araddr_valid = VALID_ADDR_W'(s_axil_rd.araddr >> (ADDR_W - VALID_ADDR_W)); wire [VALID_ADDR_W-1:0] s_axil_araddr_valid = VALID_ADDR_W'(s_axil_rd.araddr >> (ADDR_W - VALID_ADDR_W));
@@ -84,16 +84,6 @@ assign s_axil_rd.rresp = 2'b00;
assign s_axil_rd.ruser = '0; assign s_axil_rd.ruser = '0;
assign s_axil_rd.rvalid = PIPELINE_OUTPUT ? s_axil_rvalid_pipe_reg : s_axil_rvalid_reg; assign s_axil_rd.rvalid = PIPELINE_OUTPUT ? s_axil_rvalid_pipe_reg : s_axil_rvalid_reg;
initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (integer i = 0; i < 2**VALID_ADDR_W; i = i + 2**(VALID_ADDR_W/2)) begin
for (integer j = i; j < i + 2**(VALID_ADDR_W/2); j = j + 1) begin
mem[j] = '0;
end
end
end
always_comb begin always_comb begin
mem_wr_en = 1'b0; mem_wr_en = 1'b0;

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

@@ -36,12 +36,13 @@ if (m_axis.DATA_W != 8 || s_axis.DATA_W != 8)
$fatal(0, "Error: Interface DATA_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface DATA_W parameter mismatch (instance %m)");
// state register // state register
localparam [1:0] typedef enum logic [1:0] {
STATE_IDLE = 2'd0, STATE_IDLE,
STATE_SEGMENT = 2'd1, STATE_SEGMENT,
STATE_NEXT_SEGMENT = 2'd2; STATE_NEXT_SEGMENT
} state_t;
logic [1:0] state_reg = STATE_IDLE, state_next; state_t state_reg = STATE_IDLE, state_next;
logic [7:0] count_reg = 8'd0, count_next; logic [7:0] count_reg = 8'd0, count_next;
logic suppress_zero_reg = 1'b0, suppress_zero_next; logic suppress_zero_reg = 1'b0, suppress_zero_next;

View File

@@ -40,19 +40,21 @@ if (m_axis.DATA_W != 8 || s_axis.DATA_W != 8)
$fatal(0, "Error: Interface DATA_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface DATA_W parameter mismatch (instance %m)");
// state register // state register
localparam [1:0] typedef enum logic [1:0] {
INPUT_STATE_IDLE = 2'd0, INPUT_STATE_IDLE,
INPUT_STATE_SEGMENT = 2'd1, INPUT_STATE_SEGMENT,
INPUT_STATE_FINAL_ZERO = 2'd2, INPUT_STATE_FINAL_ZERO,
INPUT_STATE_APPEND_ZERO = 2'd3; INPUT_STATE_APPEND_ZERO
} input_state_t;
logic [1:0] input_state_reg = INPUT_STATE_IDLE, input_state_next; input_state_t input_state_reg = INPUT_STATE_IDLE, input_state_next;
localparam [0:0] typedef enum logic [0:0] {
OUTPUT_STATE_IDLE = 1'd0, OUTPUT_STATE_IDLE,
OUTPUT_STATE_SEGMENT = 1'd1; OUTPUT_STATE_SEGMENT
} output_state_t;
logic [0:0] output_state_reg = OUTPUT_STATE_IDLE, output_state_next; output_state_t output_state_reg = OUTPUT_STATE_IDLE, output_state_next;
logic [7:0] input_count_reg = 8'd0, input_count_next; logic [7:0] input_count_reg = 8'd0, input_count_next;
logic [7:0] output_count_reg = 8'd0, output_count_next; logic [7:0] output_count_reg = 8'd0, output_count_next;

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: CERN-OHL-S-2.0 // SPDX-License-Identifier: CERN-OHL-S-2.0
/* /*
Copyright (c) 2018-2025 FPGA Ninja, LLC Copyright (c) 2018-2026 FPGA Ninja, LLC
Authors: Authors:
- Alex Forencich - Alex Forencich
@@ -19,6 +19,8 @@ module taxi_axis_demux #
( (
// Number of AXI stream outputs // Number of AXI stream outputs
parameter M_COUNT = 4, parameter M_COUNT = 4,
// route via tid
parameter logic TID_ROUTE = 1'b0,
// route via tdest // route via tdest
parameter logic TDEST_ROUTE = 1'b0 parameter logic TDEST_ROUTE = 1'b0
) )
@@ -53,6 +55,8 @@ localparam logic LAST_EN = s_axis.LAST_EN && m_axis[0].LAST_EN;
localparam logic ID_EN = s_axis.ID_EN && m_axis[0].ID_EN; localparam logic ID_EN = s_axis.ID_EN && m_axis[0].ID_EN;
localparam ID_W = s_axis.ID_W; localparam ID_W = s_axis.ID_W;
localparam logic DEST_EN = s_axis.DEST_EN && m_axis[0].DEST_EN; localparam logic DEST_EN = s_axis.DEST_EN && m_axis[0].DEST_EN;
localparam S_ID_W = s_axis.ID_W;
localparam M_ID_W = m_axis[0].ID_W;
localparam S_DEST_W = s_axis.DEST_W; localparam S_DEST_W = s_axis.DEST_W;
localparam M_DEST_W = m_axis[0].DEST_W; localparam M_DEST_W = m_axis[0].DEST_W;
localparam logic USER_EN = s_axis.USER_EN && m_axis[0].USER_EN; localparam logic USER_EN = s_axis.USER_EN && m_axis[0].USER_EN;
@@ -61,6 +65,7 @@ localparam USER_W = s_axis.USER_W;
localparam CL_M_COUNT = $clog2(M_COUNT); localparam CL_M_COUNT = $clog2(M_COUNT);
localparam M_DEST_W_INT = M_DEST_W > 0 ? M_DEST_W : 1; localparam M_DEST_W_INT = M_DEST_W > 0 ? M_DEST_W : 1;
localparam M_ID_W_INT = M_ID_W > 0 ? M_ID_W : 1;
// check configuration // check configuration
if (m_axis[0].DATA_W != DATA_W) if (m_axis[0].DATA_W != DATA_W)
@@ -69,6 +74,17 @@ if (m_axis[0].DATA_W != DATA_W)
if (KEEP_EN && m_axis[0].KEEP_W != KEEP_W) if (KEEP_EN && m_axis[0].KEEP_W != KEEP_W)
$fatal(0, "Error: Interface KEEP_W parameter mismatch (instance %m)"); $fatal(0, "Error: Interface KEEP_W parameter mismatch (instance %m)");
if (TID_ROUTE) begin
if (!ID_EN)
$fatal(0, "Error: TID_ROUTE set requires ID_EN set (instance %m)");
if (S_ID_W < CL_M_COUNT)
$fatal(0, "Error: S_ID_W too small for port count (instance %m)");
if (TDEST_ROUTE)
$fatal(0, "Error: Cannot enable both TID_ROUTE and TDEST_ROUTE (instance %m)");
end
if (TDEST_ROUTE) begin if (TDEST_ROUTE) begin
if (!DEST_EN) if (!DEST_EN)
$fatal(0, "Error: TDEST_ROUTE set requires DEST_EN set (instance %m)"); $fatal(0, "Error: TDEST_ROUTE set requires DEST_EN set (instance %m)");
@@ -90,7 +106,7 @@ logic [KEEP_W-1:0] m_axis_tstrb_int;
logic [M_COUNT-1:0] m_axis_tvalid_int; logic [M_COUNT-1:0] m_axis_tvalid_int;
logic m_axis_tready_int_reg = 1'b0; logic m_axis_tready_int_reg = 1'b0;
logic m_axis_tlast_int; logic m_axis_tlast_int;
logic [ID_W-1:0] m_axis_tid_int; logic [M_ID_W-1:0] m_axis_tid_int;
logic [M_DEST_W-1:0] m_axis_tdest_int; logic [M_DEST_W-1:0] m_axis_tdest_int;
logic [USER_W-1:0] m_axis_tuser_int; logic [USER_W-1:0] m_axis_tuser_int;
wire m_axis_tready_int_early; wire m_axis_tready_int_early;
@@ -115,7 +131,15 @@ always_comb begin
if (!frame_reg && s_axis.tvalid && s_axis.tready) begin if (!frame_reg && s_axis.tvalid && s_axis.tready) begin
// start of frame, grab select value // start of frame, grab select value
if (TDEST_ROUTE) begin if (TID_ROUTE) begin
if (M_COUNT > 1) begin
select_ctl = s_axis.tid[S_ID_W-1:S_ID_W-CL_M_COUNT];
drop_ctl = (CL_M_COUNT+1)'(select_ctl) >= (CL_M_COUNT+1)'(M_COUNT);
end else begin
select_ctl = '0;
drop_ctl = 1'b0;
end
end else if (TDEST_ROUTE) begin
if (M_COUNT > 1) begin if (M_COUNT > 1) begin
select_ctl = s_axis.tdest[S_DEST_W-1:S_DEST_W-CL_M_COUNT]; select_ctl = s_axis.tdest[S_DEST_W-1:S_DEST_W-CL_M_COUNT];
drop_ctl = (CL_M_COUNT+1)'(select_ctl) >= (CL_M_COUNT+1)'(M_COUNT); drop_ctl = (CL_M_COUNT+1)'(select_ctl) >= (CL_M_COUNT+1)'(M_COUNT);
@@ -141,7 +165,7 @@ always_comb begin
m_axis_tvalid_int = '0; m_axis_tvalid_int = '0;
m_axis_tvalid_int[select_ctl] = s_axis.tvalid && s_axis.tready && !drop_ctl; m_axis_tvalid_int[select_ctl] = s_axis.tvalid && s_axis.tready && !drop_ctl;
m_axis_tlast_int = s_axis.tlast; m_axis_tlast_int = s_axis.tlast;
m_axis_tid_int = s_axis.tid; m_axis_tid_int = M_ID_W'(s_axis.tid);
m_axis_tdest_int = M_DEST_W'(s_axis.tdest); m_axis_tdest_int = M_DEST_W'(s_axis.tdest);
m_axis_tuser_int = s_axis.tuser; m_axis_tuser_int = s_axis.tuser;
end end
@@ -170,7 +194,7 @@ logic [KEEP_W-1:0] m_axis_tkeep_reg = '0;
logic [KEEP_W-1:0] m_axis_tstrb_reg = '0; logic [KEEP_W-1:0] m_axis_tstrb_reg = '0;
logic [M_COUNT-1:0] m_axis_tvalid_reg = '0, m_axis_tvalid_next; logic [M_COUNT-1:0] m_axis_tvalid_reg = '0, m_axis_tvalid_next;
logic m_axis_tlast_reg = 1'b0; logic m_axis_tlast_reg = 1'b0;
logic [ID_W-1:0] m_axis_tid_reg = '0; logic [M_ID_W-1:0] m_axis_tid_reg = '0;
logic [M_DEST_W-1:0] m_axis_tdest_reg = '0; logic [M_DEST_W-1:0] m_axis_tdest_reg = '0;
logic [USER_W-1:0] m_axis_tuser_reg = '0; logic [USER_W-1:0] m_axis_tuser_reg = '0;
@@ -179,7 +203,7 @@ logic [KEEP_W-1:0] temp_m_axis_tkeep_reg = '0;
logic [KEEP_W-1:0] temp_m_axis_tstrb_reg = '0; logic [KEEP_W-1:0] temp_m_axis_tstrb_reg = '0;
logic [M_COUNT-1:0] temp_m_axis_tvalid_reg = '0, temp_m_axis_tvalid_next; logic [M_COUNT-1:0] temp_m_axis_tvalid_reg = '0, temp_m_axis_tvalid_next;
logic temp_m_axis_tlast_reg = 1'b0; logic temp_m_axis_tlast_reg = 1'b0;
logic [ID_W-1:0] temp_m_axis_tid_reg = '0; logic [M_ID_W-1:0] temp_m_axis_tid_reg = '0;
logic [M_DEST_W-1:0] temp_m_axis_tdest_reg = '0; logic [M_DEST_W-1:0] temp_m_axis_tdest_reg = '0;
logic [USER_W-1:0] temp_m_axis_tuser_reg = '0; logic [USER_W-1:0] temp_m_axis_tuser_reg = '0;

View File

@@ -40,12 +40,14 @@ export PARAM_KEEP_W := $(shell expr \( $(PARAM_DATA_W) + 7 \) / 8 )
export PARAM_STRB_EN := 0 export PARAM_STRB_EN := 0
export PARAM_LAST_EN := 1 export PARAM_LAST_EN := 1
export PARAM_ID_EN := 1 export PARAM_ID_EN := 1
export PARAM_ID_W := 8 export PARAM_M_ID_W := 8
export PARAM_S_ID_W := $(shell python -c "print($(PARAM_M_ID_W) + ($(PARAM_M_COUNT)-1).bit_length())")
export PARAM_DEST_EN := 1 export PARAM_DEST_EN := 1
export PARAM_M_DEST_W := 8 export PARAM_M_DEST_W := 8
export PARAM_S_DEST_W := $(shell python -c "print($(PARAM_M_DEST_W) + ($(PARAM_M_COUNT)-1).bit_length())") export PARAM_S_DEST_W := $(shell python -c "print($(PARAM_M_DEST_W) + ($(PARAM_M_COUNT)-1).bit_length())")
export PARAM_USER_EN := 1 export PARAM_USER_EN := 1
export PARAM_USER_W := 1 export PARAM_USER_W := 1
export PARAM_TID_ROUTE := 0
export PARAM_TDEST_ROUTE := 1 export PARAM_TDEST_ROUTE := 1
ifeq ($(SIM), icarus) ifeq ($(SIM), icarus)

View File

@@ -65,11 +65,11 @@ async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=N
tb = TB(dut) tb = TB(dut)
id_width = len(tb.source.bus.tid) id_width = len(tb.sink[0].bus.tid)
id_count = 2**id_width id_count = 2**id_width
id_mask = id_count-1 id_mask = id_count-1
dest_width = len(tb.sink[0].bus.tid) dest_width = len(tb.sink[0].bus.tdest)
dest_count = 2**dest_width dest_count = 2**dest_width
dest_mask = dest_count-1 dest_mask = dest_count-1
@@ -183,12 +183,14 @@ def test_taxi_axis_demux(request, m_count, data_w, tdest_route):
parameters['STRB_EN'] = 0 parameters['STRB_EN'] = 0
parameters['LAST_EN'] = 1 parameters['LAST_EN'] = 1
parameters['ID_EN'] = 1 parameters['ID_EN'] = 1
parameters['ID_W'] = 8 parameters['M_ID_W'] = 8
parameters['S_ID_W'] = parameters['M_ID_W'] + (m_count-1).bit_length()
parameters['DEST_EN'] = 1 parameters['DEST_EN'] = 1
parameters['M_DEST_W'] = 8 parameters['M_DEST_W'] = 8
parameters['S_DEST_W'] = parameters['M_DEST_W'] + (m_count-1).bit_length() parameters['S_DEST_W'] = parameters['M_DEST_W'] + (m_count-1).bit_length()
parameters['USER_EN'] = 1 parameters['USER_EN'] = 1
parameters['USER_W'] = 1 parameters['USER_W'] = 1
parameters['TID_ROUTE'] = 0
parameters['TDEST_ROUTE'] = tdest_route parameters['TDEST_ROUTE'] = tdest_route
extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()} extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()}

View File

@@ -25,12 +25,14 @@ module test_taxi_axis_demux #
parameter logic STRB_EN = 1'b0, parameter logic STRB_EN = 1'b0,
parameter logic LAST_EN = 1'b1, parameter logic LAST_EN = 1'b1,
parameter logic ID_EN = 1'b0, parameter logic ID_EN = 1'b0,
parameter ID_W = 8, parameter M_ID_W = 8,
parameter S_ID_W = M_ID_W+$clog2(M_COUNT),
parameter logic DEST_EN = 1'b0, parameter logic DEST_EN = 1'b0,
parameter M_DEST_W = 8, parameter M_DEST_W = 8,
parameter S_DEST_W = M_DEST_W+$clog2(M_COUNT), parameter S_DEST_W = M_DEST_W+$clog2(M_COUNT),
parameter logic USER_EN = 1'b1, parameter logic USER_EN = 1'b1,
parameter USER_W = 1, parameter USER_W = 1,
parameter logic TID_ROUTE = 1'b0,
parameter logic TDEST_ROUTE = 1'b0 parameter logic TDEST_ROUTE = 1'b0
/* verilator lint_on WIDTHTRUNC */ /* verilator lint_on WIDTHTRUNC */
) )
@@ -46,7 +48,7 @@ taxi_axis_if #(
.STRB_EN(STRB_EN), .STRB_EN(STRB_EN),
.LAST_EN(LAST_EN), .LAST_EN(LAST_EN),
.ID_EN(ID_EN), .ID_EN(ID_EN),
.ID_W(ID_W), .ID_W(S_ID_W),
.DEST_EN(DEST_EN), .DEST_EN(DEST_EN),
.DEST_W(S_DEST_W), .DEST_W(S_DEST_W),
.USER_EN(USER_EN), .USER_EN(USER_EN),
@@ -60,7 +62,7 @@ taxi_axis_if #(
.STRB_EN(STRB_EN), .STRB_EN(STRB_EN),
.LAST_EN(LAST_EN), .LAST_EN(LAST_EN),
.ID_EN(ID_EN), .ID_EN(ID_EN),
.ID_W(ID_W), .ID_W(M_ID_W),
.DEST_EN(DEST_EN), .DEST_EN(DEST_EN),
.DEST_W(M_DEST_W), .DEST_W(M_DEST_W),
.USER_EN(USER_EN), .USER_EN(USER_EN),
@@ -73,6 +75,7 @@ logic [$clog2(M_COUNT)-1:0] select;
taxi_axis_demux #( taxi_axis_demux #(
.M_COUNT(M_COUNT), .M_COUNT(M_COUNT),
.TID_ROUTE(TID_ROUTE),
.TDEST_ROUTE(TDEST_ROUTE) .TDEST_ROUTE(TDEST_ROUTE)
) )
uut ( uut (

View File

@@ -0,0 +1,32 @@
# Corundum for ADM-PCIE-9V3
## Introduction
This design targets the Alpha Data ADM-PCIE-9V3 FPGA board.
* QSFP28
* 10GBASE-R or 25GBASE-R MACs via GTY transceivers
## Board details
* FPGA: xcvu3p-ffvc1517-2-i
* PCIe: gen 3 x16 (~128 Gbps)
* Reference oscillator: 161.1328125 MHz from Si5338
* 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.

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,490 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2014-2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
# XDC constraints for the ADM-PCIE-9V3
# part: xcvu3p-ffvc1517-2-i
# 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 {Pullnone} [current_design]
set_property BITSTREAM.CONFIG.OVERTEMPSHUTDOWN Enable [current_design]
# 300 MHz system clock
set_property -dict {LOC AP26 IOSTANDARD LVDS DIFF_TERM_ADV TERM_100} [get_ports clk_300mhz_p]
set_property -dict {LOC AP27 IOSTANDARD LVDS DIFF_TERM_ADV TERM_100} [get_ports clk_300mhz_n]
create_clock -period 3.333 -name clk_300mhz [get_ports clk_300mhz_p]
# LEDs
set_property -dict {LOC AT27 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports {user_led_g[0]}]
set_property -dict {LOC AU27 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports {user_led_g[1]}]
set_property -dict {LOC AU23 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports {user_led_r}]
set_property -dict {LOC AH24 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports {front_led[0]}]
set_property -dict {LOC AJ23 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports {front_led[1]}]
set_false_path -to [get_ports {user_led_g[*] user_led_r front_led[*]}]
set_output_delay 0 [get_ports {user_led_g[*] user_led_r front_led[*]}]
# Switches
set_property -dict {LOC AV27 IOSTANDARD LVCMOS18} [get_ports {user_sw[0]}]
set_property -dict {LOC AW27 IOSTANDARD LVCMOS18} [get_ports {user_sw[1]}]
set_false_path -from [get_ports {user_sw[*]}]
set_input_delay 0 [get_ports {user_sw[*]}]
# GPIO
#set_property -dict {LOC G30 IOSTANDARD LVCMOS18} [get_ports gpio_p[0]]
#set_property -dict {LOC F30 IOSTANDARD LVCMOS18} [get_ports gpio_n[0]]
#set_property -dict {LOC J31 IOSTANDARD LVCMOS18} [get_ports gpio_p[1]]
#set_property -dict {LOC H31 IOSTANDARD LVCMOS18} [get_ports gpio_n[1]]
# QSFP28 Interfaces
set_property -dict {LOC G38 } [get_ports {qsfp_0_rx_p[0]}] ;# MGTYRXP0_128 GTYE4_CHANNEL_X0Y16 / GTYE4_COMMON_X0Y4
set_property -dict {LOC G39 } [get_ports {qsfp_0_rx_n[0]}] ;# MGTYRXN0_128 GTYE4_CHANNEL_X0Y16 / GTYE4_COMMON_X0Y4
set_property -dict {LOC F35 } [get_ports {qsfp_0_tx_p[0]}] ;# MGTYTXP0_128 GTYE4_CHANNEL_X0Y16 / GTYE4_COMMON_X0Y4
set_property -dict {LOC F36 } [get_ports {qsfp_0_tx_n[0]}] ;# MGTYTXN0_128 GTYE4_CHANNEL_X0Y16 / GTYE4_COMMON_X0Y4
set_property -dict {LOC E38 } [get_ports {qsfp_0_rx_p[1]}] ;# MGTYRXP1_128 GTYE4_CHANNEL_X0Y17 / GTYE4_COMMON_X0Y4
set_property -dict {LOC E39 } [get_ports {qsfp_0_rx_n[1]}] ;# MGTYRXN1_128 GTYE4_CHANNEL_X0Y17 / GTYE4_COMMON_X0Y4
set_property -dict {LOC D35 } [get_ports {qsfp_0_tx_p[1]}] ;# MGTYTXP1_128 GTYE4_CHANNEL_X0Y17 / GTYE4_COMMON_X0Y4
set_property -dict {LOC D36 } [get_ports {qsfp_0_tx_n[1]}] ;# MGTYTXN1_128 GTYE4_CHANNEL_X0Y17 / GTYE4_COMMON_X0Y4
set_property -dict {LOC C38 } [get_ports {qsfp_0_rx_p[2]}] ;# MGTYRXP2_128 GTYE4_CHANNEL_X0Y18 / GTYE4_COMMON_X0Y4
set_property -dict {LOC C39 } [get_ports {qsfp_0_rx_n[2]}] ;# MGTYRXN2_128 GTYE4_CHANNEL_X0Y18 / GTYE4_COMMON_X0Y4
set_property -dict {LOC C33 } [get_ports {qsfp_0_tx_p[2]}] ;# MGTYTXP2_128 GTYE4_CHANNEL_X0Y18 / GTYE4_COMMON_X0Y4
set_property -dict {LOC C34 } [get_ports {qsfp_0_tx_n[2]}] ;# MGTYTXN2_128 GTYE4_CHANNEL_X0Y18 / GTYE4_COMMON_X0Y4
set_property -dict {LOC B36 } [get_ports {qsfp_0_rx_p[3]}] ;# MGTYRXP3_128 GTYE4_CHANNEL_X0Y19 / GTYE4_COMMON_X0Y4
set_property -dict {LOC B37 } [get_ports {qsfp_0_rx_n[3]}] ;# MGTYRXN3_128 GTYE4_CHANNEL_X0Y19 / GTYE4_COMMON_X0Y4
set_property -dict {LOC A33 } [get_ports {qsfp_0_tx_p[3]}] ;# MGTYTXP3_128 GTYE4_CHANNEL_X0Y19 / GTYE4_COMMON_X0Y4
set_property -dict {LOC A34 } [get_ports {qsfp_0_tx_n[3]}] ;# MGTYTXN3_128 GTYE4_CHANNEL_X0Y19 / GTYE4_COMMON_X0Y4
set_property -dict {LOC N33 } [get_ports qsfp_0_mgt_refclk_p] ;# MGTREFCLK0P_128 from ?
set_property -dict {LOC N34 } [get_ports qsfp_0_mgt_refclk_n] ;# MGTREFCLK0N_128 from ?
set_property -dict {LOC F29 IOSTANDARD LVCMOS18 PULLUP true} [get_ports qsfp_0_modprs_l]
set_property -dict {LOC D31 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports qsfp_0_sel_l]
# 161.1328125 MHz MGT reference clock
create_clock -period 6.206 -name qsfp_0_mgt_refclk [get_ports qsfp_0_mgt_refclk_p]
set_property -dict {LOC R38 } [get_ports {qsfp_1_rx_p[0]}] ;# MGTYRXP0_127 GTYE4_CHANNEL_X0Y12 / GTYE4_COMMON_X0Y3
set_property -dict {LOC R39 } [get_ports {qsfp_1_rx_n[0]}] ;# MGTYRXN0_127 GTYE4_CHANNEL_X0Y12 / GTYE4_COMMON_X0Y3
set_property -dict {LOC P35 } [get_ports {qsfp_1_tx_p[0]}] ;# MGTYTXP0_127 GTYE4_CHANNEL_X0Y12 / GTYE4_COMMON_X0Y3
set_property -dict {LOC P36 } [get_ports {qsfp_1_tx_n[0]}] ;# MGTYTXN0_127 GTYE4_CHANNEL_X0Y12 / GTYE4_COMMON_X0Y3
set_property -dict {LOC N38 } [get_ports {qsfp_1_rx_p[1]}] ;# MGTYRXP1_127 GTYE4_CHANNEL_X0Y13 / GTYE4_COMMON_X0Y3
set_property -dict {LOC N39 } [get_ports {qsfp_1_rx_n[1]}] ;# MGTYRXN1_127 GTYE4_CHANNEL_X0Y13 / GTYE4_COMMON_X0Y3
set_property -dict {LOC M35 } [get_ports {qsfp_1_tx_p[1]}] ;# MGTYTXP1_127 GTYE4_CHANNEL_X0Y13 / GTYE4_COMMON_X0Y3
set_property -dict {LOC M36 } [get_ports {qsfp_1_tx_n[1]}] ;# MGTYTXN1_127 GTYE4_CHANNEL_X0Y13 / GTYE4_COMMON_X0Y3
set_property -dict {LOC L38 } [get_ports {qsfp_1_rx_p[2]}] ;# MGTYRXP2_127 GTYE4_CHANNEL_X0Y14 / GTYE4_COMMON_X0Y3
set_property -dict {LOC L39 } [get_ports {qsfp_1_rx_n[2]}] ;# MGTYRXN2_127 GTYE4_CHANNEL_X0Y14 / GTYE4_COMMON_X0Y3
set_property -dict {LOC K35 } [get_ports {qsfp_1_tx_p[2]}] ;# MGTYTXP2_127 GTYE4_CHANNEL_X0Y14 / GTYE4_COMMON_X0Y3
set_property -dict {LOC K36 } [get_ports {qsfp_1_tx_n[2]}] ;# MGTYTXN2_127 GTYE4_CHANNEL_X0Y14 / GTYE4_COMMON_X0Y3
set_property -dict {LOC J38 } [get_ports {qsfp_1_rx_p[3]}] ;# MGTYRXP3_127 GTYE4_CHANNEL_X0Y15 / GTYE4_COMMON_X0Y3
set_property -dict {LOC J39 } [get_ports {qsfp_1_rx_n[3]}] ;# MGTYRXN3_127 GTYE4_CHANNEL_X0Y15 / GTYE4_COMMON_X0Y3
set_property -dict {LOC H35 } [get_ports {qsfp_1_tx_p[3]}] ;# MGTYTXP3_127 GTYE4_CHANNEL_X0Y15 / GTYE4_COMMON_X0Y3
set_property -dict {LOC H36 } [get_ports {qsfp_1_tx_n[3]}] ;# MGTYTXN3_127 GTYE4_CHANNEL_X0Y15 / GTYE4_COMMON_X0Y3
#set_property -dict {LOC U33 } [get_ports qsfp_1_mgt_refclk_p] ;# MGTREFCLK0P_127 from ?
#set_property -dict {LOC U34 } [get_ports qsfp_1_mgt_refclk_n] ;# MGTREFCLK0N_127 from ?
set_property -dict {LOC F33 IOSTANDARD LVCMOS18 PULLUP true} [get_ports qsfp_1_modprs_l]
set_property -dict {LOC D30 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports qsfp_1_sel_l]
# 161.1328125 MHz MGT reference clock
#create_clock -period 6.206 -name qsfp_1_mgt_refclk [get_ports qsfp_1_mgt_refclk_p]
set_property -dict {LOC B29 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12} [get_ports qsfp_reset_l]
set_property -dict {LOC C29 IOSTANDARD LVCMOS18 PULLUP true} [get_ports qsfp_int_l]
#set_property -dict {LOC A28 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12 PULLUP true} [get_ports qsfp_i2c_scl]
#set_property -dict {LOC A29 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12 PULLUP true} [get_ports qsfp_i2c_sda]
set_false_path -to [get_ports {qsfp_0_sel_l qsfp_1_sel_l qsfp_reset_l}]
set_output_delay 0 [get_ports {qsfp_0_sel_l qsfp_1_sel_l qsfp_reset_l}]
set_false_path -from [get_ports {qsfp_0_modprs_l qsfp_1_modprs_l qsfp_int_l}]
set_input_delay 0 [get_ports {qsfp_0_modprs_l qsfp_1_modprs_l qsfp_int_l}]
#set_false_path -to [get_ports {qsfp_i2c_sda qsfp_i2c_scl}]
#set_output_delay 0 [get_ports {qsfp_i2c_sda qsfp_i2c_scl}]
#set_false_path -from [get_ports {qsfp_i2c_sda qsfp_i2c_scl}]
#set_input_delay 0 [get_ports {qsfp_i2c_sda qsfp_i2c_scl}]
# I2C interface
#set_property -dict {LOC AT25 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12 PULLUP true} [get_ports eeprom_i2c_scl]
#set_property -dict {LOC AT26 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12 PULLUP true} [get_ports eeprom_i2c_sda]
#set_property -dict {LOC AP23 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12 PULLUP true} [get_ports eeprom_wp]
#set_false_path -to [get_ports {eeprom_i2c_sda eeprom_i2c_scl eeprom_wp}]
#set_output_delay 0 [get_ports {eeprom_i2c_sda eeprom_i2c_scl eeprom_wp}]
#set_false_path -from [get_ports {eeprom_i2c_sda eeprom_i2c_scl}]
#set_input_delay 0 [get_ports {eeprom_i2c_sda eeprom_i2c_scl}]
# PCIe Interface
set_property -dict {LOC J2 } [get_ports {pcie_rx_p[0]}] ;# MGTYRXP3_227 GTYE4_CHANNEL_X1Y15 / GTYE4_COMMON_X1Y3
set_property -dict {LOC J1 } [get_ports {pcie_rx_n[0]}] ;# MGTYRXN3_227 GTYE4_CHANNEL_X1Y15 / GTYE4_COMMON_X1Y3
set_property -dict {LOC H5 } [get_ports {pcie_tx_p[0]}] ;# MGTYTXP3_227 GTYE4_CHANNEL_X1Y15 / GTYE4_COMMON_X1Y3
set_property -dict {LOC H4 } [get_ports {pcie_tx_n[0]}] ;# MGTYTXN3_227 GTYE4_CHANNEL_X1Y15 / GTYE4_COMMON_X1Y3
set_property -dict {LOC L2 } [get_ports {pcie_rx_p[1]}] ;# MGTYRXP2_227 GTYE4_CHANNEL_X1Y14 / GTYE4_COMMON_X1Y3
set_property -dict {LOC L1 } [get_ports {pcie_rx_n[1]}] ;# MGTYRXN2_227 GTYE4_CHANNEL_X1Y14 / GTYE4_COMMON_X1Y3
set_property -dict {LOC K5 } [get_ports {pcie_tx_p[1]}] ;# MGTYTXP2_227 GTYE4_CHANNEL_X1Y14 / GTYE4_COMMON_X1Y3
set_property -dict {LOC K4 } [get_ports {pcie_tx_n[1]}] ;# MGTYTXN2_227 GTYE4_CHANNEL_X1Y14 / GTYE4_COMMON_X1Y3
set_property -dict {LOC N2 } [get_ports {pcie_rx_p[2]}] ;# MGTYRXP1_227 GTYE4_CHANNEL_X1Y13 / GTYE4_COMMON_X1Y3
set_property -dict {LOC N1 } [get_ports {pcie_rx_n[2]}] ;# MGTYRXN1_227 GTYE4_CHANNEL_X1Y13 / GTYE4_COMMON_X1Y3
set_property -dict {LOC M5 } [get_ports {pcie_tx_p[2]}] ;# MGTYTXP1_227 GTYE4_CHANNEL_X1Y13 / GTYE4_COMMON_X1Y3
set_property -dict {LOC M4 } [get_ports {pcie_tx_n[2]}] ;# MGTYTXN1_227 GTYE4_CHANNEL_X1Y13 / GTYE4_COMMON_X1Y3
set_property -dict {LOC R2 } [get_ports {pcie_rx_p[3]}] ;# MGTYRXP0_227 GTYE4_CHANNEL_X1Y12 / GTYE4_COMMON_X1Y3
set_property -dict {LOC R1 } [get_ports {pcie_rx_n[3]}] ;# MGTYRXN0_227 GTYE4_CHANNEL_X1Y12 / GTYE4_COMMON_X1Y3
set_property -dict {LOC P5 } [get_ports {pcie_tx_p[3]}] ;# MGTYTXP0_227 GTYE4_CHANNEL_X1Y12 / GTYE4_COMMON_X1Y3
set_property -dict {LOC P4 } [get_ports {pcie_tx_n[3]}] ;# MGTYTXN0_227 GTYE4_CHANNEL_X1Y12 / GTYE4_COMMON_X1Y3
set_property -dict {LOC U2 } [get_ports {pcie_rx_p[4]}] ;# MGTYRXP3_226 GTYE4_CHANNEL_X1Y11 / GTYE4_COMMON_X1Y2
set_property -dict {LOC U1 } [get_ports {pcie_rx_n[4]}] ;# MGTYRXN3_226 GTYE4_CHANNEL_X1Y11 / GTYE4_COMMON_X1Y2
set_property -dict {LOC T5 } [get_ports {pcie_tx_p[4]}] ;# MGTYTXP3_226 GTYE4_CHANNEL_X1Y11 / GTYE4_COMMON_X1Y2
set_property -dict {LOC T4 } [get_ports {pcie_tx_n[4]}] ;# MGTYTXN3_226 GTYE4_CHANNEL_X1Y11 / GTYE4_COMMON_X1Y2
set_property -dict {LOC W2 } [get_ports {pcie_rx_p[5]}] ;# MGTYRXP2_226 GTYE4_CHANNEL_X1Y10 / GTYE4_COMMON_X1Y2
set_property -dict {LOC W1 } [get_ports {pcie_rx_n[5]}] ;# MGTYRXN2_226 GTYE4_CHANNEL_X1Y10 / GTYE4_COMMON_X1Y2
set_property -dict {LOC V5 } [get_ports {pcie_tx_p[5]}] ;# MGTYTXP2_226 GTYE4_CHANNEL_X1Y10 / GTYE4_COMMON_X1Y2
set_property -dict {LOC V4 } [get_ports {pcie_tx_n[5]}] ;# MGTYTXN2_226 GTYE4_CHANNEL_X1Y10 / GTYE4_COMMON_X1Y2
set_property -dict {LOC AA2 } [get_ports {pcie_rx_p[6]}] ;# MGTYRXP1_226 GTYE4_CHANNEL_X1Y9 / GTYE4_COMMON_X1Y2
set_property -dict {LOC AA1 } [get_ports {pcie_rx_n[6]}] ;# MGTYRXN1_226 GTYE4_CHANNEL_X1Y9 / GTYE4_COMMON_X1Y2
set_property -dict {LOC AB5 } [get_ports {pcie_tx_p[6]}] ;# MGTYTXP1_226 GTYE4_CHANNEL_X1Y9 / GTYE4_COMMON_X1Y2
set_property -dict {LOC AB4 } [get_ports {pcie_tx_n[6]}] ;# MGTYTXN1_226 GTYE4_CHANNEL_X1Y9 / GTYE4_COMMON_X1Y2
set_property -dict {LOC AC2 } [get_ports {pcie_rx_p[7]}] ;# MGTYRXP0_226 GTYE4_CHANNEL_X1Y8 / GTYE4_COMMON_X1Y2
set_property -dict {LOC AC1 } [get_ports {pcie_rx_n[7]}] ;# MGTYRXN0_226 GTYE4_CHANNEL_X1Y8 / GTYE4_COMMON_X1Y2
set_property -dict {LOC AD5 } [get_ports {pcie_tx_p[7]}] ;# MGTYTXP0_226 GTYE4_CHANNEL_X1Y8 / GTYE4_COMMON_X1Y2
set_property -dict {LOC AD4 } [get_ports {pcie_tx_n[7]}] ;# MGTYTXN0_226 GTYE4_CHANNEL_X1Y8 / GTYE4_COMMON_X1Y2
set_property -dict {LOC AE2 } [get_ports {pcie_rx_p[8]}] ;# MGTYRXP3_225 GTYE4_CHANNEL_X1Y7 / GTYE4_COMMON_X1Y1
set_property -dict {LOC AE1 } [get_ports {pcie_rx_n[8]}] ;# MGTYRXN3_225 GTYE4_CHANNEL_X1Y7 / GTYE4_COMMON_X1Y1
set_property -dict {LOC AF5 } [get_ports {pcie_tx_p[8]}] ;# MGTYTXP3_225 GTYE4_CHANNEL_X1Y7 / GTYE4_COMMON_X1Y1
set_property -dict {LOC AF4 } [get_ports {pcie_tx_n[8]}] ;# MGTYTXN3_225 GTYE4_CHANNEL_X1Y7 / GTYE4_COMMON_X1Y1
set_property -dict {LOC AG2 } [get_ports {pcie_rx_p[9]}] ;# MGTYRXP2_225 GTYE4_CHANNEL_X1Y6 / GTYE4_COMMON_X1Y1
set_property -dict {LOC AG1 } [get_ports {pcie_rx_n[9]}] ;# MGTYRXN2_225 GTYE4_CHANNEL_X1Y6 / GTYE4_COMMON_X1Y1
set_property -dict {LOC AH5 } [get_ports {pcie_tx_p[9]}] ;# MGTYTXP2_225 GTYE4_CHANNEL_X1Y6 / GTYE4_COMMON_X1Y1
set_property -dict {LOC AH4 } [get_ports {pcie_tx_n[9]}] ;# MGTYTXN2_225 GTYE4_CHANNEL_X1Y6 / GTYE4_COMMON_X1Y1
set_property -dict {LOC AJ2 } [get_ports {pcie_rx_p[10]}] ;# MGTYRXP1_225 GTYE4_CHANNEL_X1Y5 / GTYE4_COMMON_X1Y1
set_property -dict {LOC AJ1 } [get_ports {pcie_rx_n[10]}] ;# MGTYRXN1_225 GTYE4_CHANNEL_X1Y5 / GTYE4_COMMON_X1Y1
set_property -dict {LOC AK5 } [get_ports {pcie_tx_p[10]}] ;# MGTYTXP1_225 GTYE4_CHANNEL_X1Y5 / GTYE4_COMMON_X1Y1
set_property -dict {LOC AK4 } [get_ports {pcie_tx_n[10]}] ;# MGTYTXN1_225 GTYE4_CHANNEL_X1Y5 / GTYE4_COMMON_X1Y1
set_property -dict {LOC AL2 } [get_ports {pcie_rx_p[11]}] ;# MGTYRXP0_225 GTYE4_CHANNEL_X1Y4 / GTYE4_COMMON_X1Y1
set_property -dict {LOC AL1 } [get_ports {pcie_rx_n[11]}] ;# MGTYRXN0_225 GTYE4_CHANNEL_X1Y4 / GTYE4_COMMON_X1Y1
set_property -dict {LOC AM5 } [get_ports {pcie_tx_p[11]}] ;# MGTYTXP0_225 GTYE4_CHANNEL_X1Y4 / GTYE4_COMMON_X1Y1
set_property -dict {LOC AM4 } [get_ports {pcie_tx_n[11]}] ;# MGTYTXN0_225 GTYE4_CHANNEL_X1Y4 / GTYE4_COMMON_X1Y1
set_property -dict {LOC AN2 } [get_ports {pcie_rx_p[12]}] ;# MGTYRXP3_224 GTYE4_CHANNEL_X1Y3 / GTYE4_COMMON_X1Y0
set_property -dict {LOC AN1 } [get_ports {pcie_rx_n[12]}] ;# MGTYRXN3_224 GTYE4_CHANNEL_X1Y3 / GTYE4_COMMON_X1Y0
set_property -dict {LOC AP5 } [get_ports {pcie_tx_p[12]}] ;# MGTYTXP3_224 GTYE4_CHANNEL_X1Y3 / GTYE4_COMMON_X1Y0
set_property -dict {LOC AP4 } [get_ports {pcie_tx_n[12]}] ;# MGTYTXN3_224 GTYE4_CHANNEL_X1Y3 / GTYE4_COMMON_X1Y0
set_property -dict {LOC AR2 } [get_ports {pcie_rx_p[13]}] ;# MGTYRXP2_224 GTYE4_CHANNEL_X1Y2 / GTYE4_COMMON_X1Y0
set_property -dict {LOC AR1 } [get_ports {pcie_rx_n[13]}] ;# MGTYRXN2_224 GTYE4_CHANNEL_X1Y2 / GTYE4_COMMON_X1Y0
set_property -dict {LOC AT5 } [get_ports {pcie_tx_p[13]}] ;# MGTYTXP2_224 GTYE4_CHANNEL_X1Y2 / GTYE4_COMMON_X1Y0
set_property -dict {LOC AT4 } [get_ports {pcie_tx_n[13]}] ;# MGTYTXN2_224 GTYE4_CHANNEL_X1Y2 / GTYE4_COMMON_X1Y0
set_property -dict {LOC AU2 } [get_ports {pcie_rx_p[14]}] ;# MGTYRXP1_224 GTYE4_CHANNEL_X1Y1 / GTYE4_COMMON_X1Y0
set_property -dict {LOC AU1 } [get_ports {pcie_rx_n[14]}] ;# MGTYRXN1_224 GTYE4_CHANNEL_X1Y1 / GTYE4_COMMON_X1Y0
set_property -dict {LOC AU7 } [get_ports {pcie_tx_p[14]}] ;# MGTYTXP1_224 GTYE4_CHANNEL_X1Y1 / GTYE4_COMMON_X1Y0
set_property -dict {LOC AU6 } [get_ports {pcie_tx_n[14]}] ;# MGTYTXN1_224 GTYE4_CHANNEL_X1Y1 / GTYE4_COMMON_X1Y0
set_property -dict {LOC AV4 } [get_ports {pcie_rx_p[15]}] ;# MGTYRXP0_224 GTYE4_CHANNEL_X1Y0 / GTYE4_COMMON_X1Y0
set_property -dict {LOC AV3 } [get_ports {pcie_rx_n[15]}] ;# MGTYRXN0_224 GTYE4_CHANNEL_X1Y0 / GTYE4_COMMON_X1Y0
set_property -dict {LOC AW7 } [get_ports {pcie_tx_p[15]}] ;# MGTYTXP0_224 GTYE4_CHANNEL_X1Y0 / GTYE4_COMMON_X1Y0
set_property -dict {LOC AW6 } [get_ports {pcie_tx_n[15]}] ;# MGTYTXN0_224 GTYE4_CHANNEL_X1Y0 / GTYE4_COMMON_X1Y0
set_property -dict {LOC AA7 } [get_ports pcie_refclk_1_p] ;# MGTREFCLK0P_226
set_property -dict {LOC AA6 } [get_ports pcie_refclk_1_n] ;# MGTREFCLK0N_226
#set_property -dict {LOC AJ7 } [get_ports pcie_refclk_2_p] ;# MGTREFCLK0P_224
#set_property -dict {LOC AJ6 } [get_ports pcie_refclk_2_n] ;# MGTREFCLK0N_224
set_property -dict {LOC AJ31 IOSTANDARD LVCMOS18 PULLUP true} [get_ports pcie_reset_n]
#set_property -dict {LOC AH29 IOSTANDARD LVCMOS18 PULLUP true} [get_ports pcie_reset_n]
# 100 MHz MGT reference clock
create_clock -period 10 -name pcie_mgt_refclk_1 [get_ports pcie_refclk_1_p]
#create_clock -period 10 -name pcie_mgt_refclk_2 [get_ports pcie_refclk_2_p]
set_false_path -from [get_ports {pcie_reset_n}]
set_input_delay 0 [get_ports {pcie_reset_n}]
# DDR4 C0
# 5x K4A8G085WB-RC
#set_property -dict {LOC F9 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_adr[0]}]
#set_property -dict {LOC G9 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_adr[1]}]
#set_property -dict {LOC G11 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_adr[2]}]
#set_property -dict {LOC D11 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_adr[3]}]
#set_property -dict {LOC E12 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_adr[4]}]
#set_property -dict {LOC G10 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_adr[5]}]
#set_property -dict {LOC F10 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_adr[6]}]
#set_property -dict {LOC J9 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_adr[7]}]
#set_property -dict {LOC J8 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_adr[8]}]
#set_property -dict {LOC F12 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_adr[9]}]
#set_property -dict {LOC D9 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_adr[10]}]
#set_property -dict {LOC H11 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_adr[11]}]
#set_property -dict {LOC E8 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_adr[12]}]
#set_property -dict {LOC J11 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_adr[13]}]
#set_property -dict {LOC C9 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_adr[14]}]
#set_property -dict {LOC B11 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_adr[15]}]
#set_property -dict {LOC K12 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_adr[16]}]
#set_property -dict {LOC H9 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_adr[17]}]
#set_property -dict {LOC F8 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_ba[0]}]
#set_property -dict {LOC H8 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_ba[1]}]
#set_property -dict {LOC D10 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_bg[0]}]
#set_property -dict {LOC E11 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_bg[1]}]
#set_property -dict {LOC B10 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_c[0]}]
#set_property -dict {LOC C11 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_c[1]}]
#set_property -dict {LOC A9 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_c[2]}]
#set_property -dict {LOC H12 IOSTANDARD DIFF_SSTL12_DCI} [get_ports {ddr4_c0_ck_t}]
#set_property -dict {LOC G12 IOSTANDARD DIFF_SSTL12_DCI} [get_ports {ddr4_c0_ck_c}]
#set_property -dict {LOC B9 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_cke}]
#set_property -dict {LOC E10 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_cs_n}]
#set_property -dict {LOC C12 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_act_n}]
#set_property -dict {LOC A10 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_odt}]
#set_property -dict {LOC G7 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c0_par}]
#set_property -dict {LOC F7 IOSTANDARD LVCMOS12 } [get_ports {ddr4_c0_reset_n}]
#set_property -dict {LOC H7 IOSTANDARD LVCMOS12 } [get_ports {ddr4_c0_alert_n}]
#set_property -dict {LOC J10 IOSTANDARD LVCMOS12 } [get_ports {ddr4_c0_ten}]
#set_property -dict {LOC L10 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[0]}]
#set_property -dict {LOC L9 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[1]}]
#set_property -dict {LOC N9 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[2]}]
#set_property -dict {LOC M9 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[3]}]
#set_property -dict {LOC M10 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[4]}]
#set_property -dict {LOC K11 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[5]}]
#set_property -dict {LOC M11 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[6]}]
#set_property -dict {LOC K10 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[7]}]
#set_property -dict {LOC L17 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[8]}]
#set_property -dict {LOC M16 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[9]}]
#set_property -dict {LOC M15 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[10]}]
#set_property -dict {LOC M17 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[11]}]
#set_property -dict {LOC M14 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[12]}]
#set_property -dict {LOC N18 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[13]}]
#set_property -dict {LOC N16 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[14]}]
#set_property -dict {LOC N17 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[15]}]
#set_property -dict {LOC F15 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[16]}]
#set_property -dict {LOC E16 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[17]}]
#set_property -dict {LOC F14 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[18]}]
#set_property -dict {LOC E17 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[19]}]
#set_property -dict {LOC G16 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[20]}]
#set_property -dict {LOC F17 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[21]}]
#set_property -dict {LOC E15 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[22]}]
#set_property -dict {LOC G17 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[23]}]
#set_property -dict {LOC A17 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[24]}]
#set_property -dict {LOC C16 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[25]}]
#set_property -dict {LOC B16 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[26]}]
#set_property -dict {LOC A14 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[27]}]
#set_property -dict {LOC B17 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[28]}]
#set_property -dict {LOC B14 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[29]}]
#set_property -dict {LOC D16 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[30]}]
#set_property -dict {LOC D15 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[31]}]
#set_property -dict {LOC F18 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[32]}]
#set_property -dict {LOC F20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[33]}]
#set_property -dict {LOC F19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[34]}]
#set_property -dict {LOC D21 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[35]}]
#set_property -dict {LOC E18 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[36]}]
#set_property -dict {LOC G19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[37]}]
#set_property -dict {LOC E21 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[38]}]
#set_property -dict {LOC G20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[39]}]
#set_property -dict {LOC D18 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[40]}]
#set_property -dict {LOC B22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[41]}]
#set_property -dict {LOC A19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[42]}]
#set_property -dict {LOC A18 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[43]}]
#set_property -dict {LOC C19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[44]}]
#set_property -dict {LOC B19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[45]}]
#set_property -dict {LOC A22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[46]}]
#set_property -dict {LOC C18 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[47]}]
#set_property -dict {LOC G22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[48]}]
#set_property -dict {LOC J20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[49]}]
#set_property -dict {LOC H19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[50]}]
#set_property -dict {LOC J19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[51]}]
#set_property -dict {LOC H18 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[52]}]
#set_property -dict {LOC J18 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[53]}]
#set_property -dict {LOC G21 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[54]}]
#set_property -dict {LOC K18 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[55]}]
#set_property -dict {LOC L20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[56]}]
#set_property -dict {LOC L18 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[57]}]
#set_property -dict {LOC N19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[58]}]
#set_property -dict {LOC M21 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[59]}]
#set_property -dict {LOC M19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[60]}]
#set_property -dict {LOC M22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[61]}]
#set_property -dict {LOC L19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[62]}]
#set_property -dict {LOC M20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[63]}]
#set_property -dict {LOC H16 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[64]}]
#set_property -dict {LOC K15 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[65]}]
#set_property -dict {LOC J16 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[66]}]
#set_property -dict {LOC J14 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[67]}]
#set_property -dict {LOC K13 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[68]}]
#set_property -dict {LOC L13 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[69]}]
#set_property -dict {LOC H14 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[70]}]
#set_property -dict {LOC J15 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dq[71]}]
#set_property -dict {LOC M12 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c0_dqs_t[0]}]
#set_property -dict {LOC L12 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c0_dqs_c[0]}]
#set_property -dict {LOC L15 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c0_dqs_t[1]}]
#set_property -dict {LOC L14 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c0_dqs_c[1]}]
#set_property -dict {LOC F13 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c0_dqs_t[2]}]
#set_property -dict {LOC E13 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c0_dqs_c[2]}]
#set_property -dict {LOC B15 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c0_dqs_t[3]}]
#set_property -dict {LOC A15 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c0_dqs_c[3]}]
#set_property -dict {LOC F22 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c0_dqs_t[4]}]
#set_property -dict {LOC E22 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c0_dqs_c[4]}]
#set_property -dict {LOC C21 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c0_dqs_t[5]}]
#set_property -dict {LOC B21 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c0_dqs_c[5]}]
#set_property -dict {LOC K21 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c0_dqs_t[6]}]
#set_property -dict {LOC K20 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c0_dqs_c[6]}]
#set_property -dict {LOC L22 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c0_dqs_t[7]}]
#set_property -dict {LOC K22 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c0_dqs_c[7]}]
#set_property -dict {LOC K17 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c0_dqs_t[8]}]
#set_property -dict {LOC K16 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c0_dqs_c[8]}]
#set_property -dict {LOC N12 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dm_dbi_n[0]}]
#set_property -dict {LOC P14 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dm_dbi_n[1]}]
#set_property -dict {LOC G15 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dm_dbi_n[2]}]
#set_property -dict {LOC D14 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dm_dbi_n[3]}]
#set_property -dict {LOC E20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dm_dbi_n[4]}]
#set_property -dict {LOC B20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dm_dbi_n[5]}]
#set_property -dict {LOC H22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dm_dbi_n[6]}]
#set_property -dict {LOC N22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dm_dbi_n[7]}]
#set_property -dict {LOC J13 IOSTANDARD POD12_DCI } [get_ports {ddr4_c0_dm_dbi_n[8]}]
# DDR4 C1
# 5x K4A8G085WB-RC
#set_property -dict {LOC AN9 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[0]}]
#set_property -dict {LOC AM9 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[1]}]
#set_property -dict {LOC AP11 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[2]}]
#set_property -dict {LOC AU9 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[3]}]
#set_property -dict {LOC AT10 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[4]}]
#set_property -dict {LOC AL12 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[5]}]
#set_property -dict {LOC AM12 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[6]}]
#set_property -dict {LOC AM10 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[7]}]
#set_property -dict {LOC AL11 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[8]}]
#set_property -dict {LOC AP7 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[9]}]
#set_property -dict {LOC AR8 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[10]}]
#set_property -dict {LOC AL10 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[11]}]
#set_property -dict {LOC AP8 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[12]}]
#set_property -dict {LOC AK11 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[13]}]
#set_property -dict {LOC AP9 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[14]}]
#set_property -dict {LOC AV10 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[15]}]
#set_property -dict {LOC AT11 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[16]}]
#set_property -dict {LOC AL8 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_adr[17]}]
#set_property -dict {LOC AN11 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_ba[0]}]
#set_property -dict {LOC AR9 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_ba[1]}]
#set_property -dict {LOC AP12 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_bg[0]}]
#set_property -dict {LOC AN10 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_bg[1]}]
#set_property -dict {LOC AW13 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_c[0]}]
#set_property -dict {LOC AU10 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_c[1]}]
#set_property -dict {LOC AW11 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_c[2]}]
#set_property -dict {LOC AM7 IOSTANDARD DIFF_SSTL12_DCI} [get_ports {ddr4_c1_ck_t}]
#set_property -dict {LOC AN7 IOSTANDARD DIFF_SSTL12_DCI} [get_ports {ddr4_c1_ck_c}]
#set_property -dict {LOC AU12 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_cke}]
#set_property -dict {LOC AT12 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_cs_n}]
#set_property -dict {LOC AV9 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_act_n}]
#set_property -dict {LOC AR11 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_odt}]
#set_property -dict {LOC AM8 IOSTANDARD SSTL12_DCI } [get_ports {ddr4_c1_par}]
#set_property -dict {LOC AN12 IOSTANDARD LVCMOS12 } [get_ports {ddr4_c1_reset_n}]
#set_property -dict {LOC AR10 IOSTANDARD LVCMOS12 } [get_ports {ddr4_c1_alert_n}]
#set_property -dict {LOC AV11 IOSTANDARD LVCMOS12 } [get_ports {ddr4_c1_ten}]
#set_property -dict {LOC AK9 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[0]}]
#set_property -dict {LOC AK10 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[1]}]
#set_property -dict {LOC AH10 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[2]}]
#set_property -dict {LOC AJ11 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[3]}]
#set_property -dict {LOC AJ9 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[4]}]
#set_property -dict {LOC AH12 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[5]}]
#set_property -dict {LOC AG10 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[6]}]
#set_property -dict {LOC AJ12 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[7]}]
#set_property -dict {LOC AM15 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[8]}]
#set_property -dict {LOC AN14 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[9]}]
#set_property -dict {LOC AL13 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[10]}]
#set_property -dict {LOC AM14 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[11]}]
#set_property -dict {LOC AL15 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[12]}]
#set_property -dict {LOC AM17 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[13]}]
#set_property -dict {LOC AL17 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[14]}]
#set_property -dict {LOC AM13 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[15]}]
#set_property -dict {LOC AR15 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[16]}]
#set_property -dict {LOC AP14 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[17]}]
#set_property -dict {LOC AT15 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[18]}]
#set_property -dict {LOC AR14 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[19]}]
#set_property -dict {LOC AP17 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[20]}]
#set_property -dict {LOC AN16 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[21]}]
#set_property -dict {LOC AN17 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[22]}]
#set_property -dict {LOC AN15 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[23]}]
#set_property -dict {LOC AU15 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[24]}]
#set_property -dict {LOC AT17 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[25]}]
#set_property -dict {LOC AV15 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[26]}]
#set_property -dict {LOC AT16 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[27]}]
#set_property -dict {LOC AV14 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[28]}]
#set_property -dict {LOC AW17 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[29]}]
#set_property -dict {LOC AW14 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[30]}]
#set_property -dict {LOC AW18 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[31]}]
#set_property -dict {LOC AP19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[32]}]
#set_property -dict {LOC AT20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[33]}]
#set_property -dict {LOC AN21 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[34]}]
#set_property -dict {LOC AR19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[35]}]
#set_property -dict {LOC AN20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[36]}]
#set_property -dict {LOC AR18 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[37]}]
#set_property -dict {LOC AR20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[38]}]
#set_property -dict {LOC AP18 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[39]}]
#set_property -dict {LOC AW19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[40]}]
#set_property -dict {LOC AU22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[41]}]
#set_property -dict {LOC AV19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[42]}]
#set_property -dict {LOC AW22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[43]}]
#set_property -dict {LOC AU18 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[44]}]
#set_property -dict {LOC AT22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[45]}]
#set_property -dict {LOC AW21 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[46]}]
#set_property -dict {LOC AU19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[47]}]
#set_property -dict {LOC AH19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[48]}]
#set_property -dict {LOC AJ22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[49]}]
#set_property -dict {LOC AF21 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[50]}]
#set_property -dict {LOC AH22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[51]}]
#set_property -dict {LOC AF20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[52]}]
#set_property -dict {LOC AJ19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[53]}]
#set_property -dict {LOC AH21 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[54]}]
#set_property -dict {LOC AJ21 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[55]}]
#set_property -dict {LOC AM19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[56]}]
#set_property -dict {LOC AK20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[57]}]
#set_property -dict {LOC AM22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[58]}]
#set_property -dict {LOC AL22 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[59]}]
#set_property -dict {LOC AM20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[60]}]
#set_property -dict {LOC AK19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[61]}]
#set_property -dict {LOC AN19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[62]}]
#set_property -dict {LOC AL20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[63]}]
#set_property -dict {LOC AF15 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[64]}]
#set_property -dict {LOC AJ17 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[65]}]
#set_property -dict {LOC AH17 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[66]}]
#set_property -dict {LOC AJ14 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[67]}]
#set_property -dict {LOC AG15 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[68]}]
#set_property -dict {LOC AJ13 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[69]}]
#set_property -dict {LOC AG17 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[70]}]
#set_property -dict {LOC AJ16 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dq[71]}]
#set_property -dict {LOC AG9 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_t[0]}]
#set_property -dict {LOC AH9 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_c[0]}]
#set_property -dict {LOC AK16 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_t[1]}]
#set_property -dict {LOC AL16 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_c[1]}]
#set_property -dict {LOC AR13 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_t[2]}]
#set_property -dict {LOC AT13 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_c[2]}]
#set_property -dict {LOC AU17 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_t[3]}]
#set_property -dict {LOC AV17 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_c[3]}]
#set_property -dict {LOC AN22 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_t[4]}]
#set_property -dict {LOC AP22 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_c[4]}]
#set_property -dict {LOC AV22 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_t[5]}]
#set_property -dict {LOC AV21 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_c[5]}]
#set_property -dict {LOC AG20 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_t[6]}]
#set_property -dict {LOC AH20 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_c[6]}]
#set_property -dict {LOC AK21 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_t[7]}]
#set_property -dict {LOC AL21 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_c[7]}]
#set_property -dict {LOC AH16 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_t[8]}]
#set_property -dict {LOC AH15 IOSTANDARD DIFF_POD12_DCI } [get_ports {ddr4_c1_dqs_c[8]}]
#set_property -dict {LOC AG12 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dm_dbi_n[0]}]
#set_property -dict {LOC AK15 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dm_dbi_n[1]}]
#set_property -dict {LOC AP16 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dm_dbi_n[2]}]
#set_property -dict {LOC AV16 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dm_dbi_n[3]}]
#set_property -dict {LOC AP21 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dm_dbi_n[4]}]
#set_property -dict {LOC AU20 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dm_dbi_n[5]}]
#set_property -dict {LOC AG19 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dm_dbi_n[6]}]
#set_property -dict {LOC AL18 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dm_dbi_n[7]}]
#set_property -dict {LOC AG14 IOSTANDARD POD12_DCI } [get_ports {ddr4_c1_dm_dbi_n[8]}]
# QSPI flash
set_property -dict {LOC AF30 IOSTANDARD LVCMOS18 DRIVE 12} [get_ports {qspi_1_dq[0]}]
set_property -dict {LOC AG30 IOSTANDARD LVCMOS18 DRIVE 12} [get_ports {qspi_1_dq[1]}]
set_property -dict {LOC AF28 IOSTANDARD LVCMOS18 DRIVE 12} [get_ports {qspi_1_dq[2]}]
set_property -dict {LOC AG28 IOSTANDARD LVCMOS18 DRIVE 12} [get_ports {qspi_1_dq[3]}]
set_property -dict {LOC AV30 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,94 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025-2026 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
# FPGA settings
FPGA_PART = xcvu3p-ffvc1517-2-i
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.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)/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)/io/rtl/taxi_debounce_switch.sv
SYN_FILES += $(TAXI_SRC_DIR)/pyrite/rtl/pyrite_pcie_us_vpd_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/pcie4_uscale_plus_0.tcl
IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_161.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)_primary.mcs $(PROJECT)_secondary.mcs $(PROJECT)_primary.prm $(PROJECT)_secondary.prm: $(PROJECT).bit
echo "write_cfgmem -force -format mcs -size 64 -interface SPIx8 -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 _primary.mcs _secondary.mcs _primary.prm _secondary.prm; \
do cp $*$$x rev/$*_rev$$COUNT$$x; \
echo "Output: rev/$*_rev$$COUNT$$x"; done;
flash: $(PROJECT)_primary.mcs $(PROJECT)_secondary.mcs $(PROJECT)_primary.prm $(PROJECT)_secondary.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 {mt25qu256-spi-x1_x2_x4_x8}] 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)_primary.mcs\" \"$(PROJECT)_secondary.mcs\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(PROJECT)_primary.prm\" \"$(PROJECT)_secondary.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 0x4B39093]
set fw_id [expr 0x0000C001]
set fw_ver $tag_ver
set board_vendor_id [expr 0x4144]
set board_device_id [expr 0x9003]
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,94 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025-2026 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
# FPGA settings
FPGA_PART = xcvu3p-ffvc1517-2-i
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.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)/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)/io/rtl/taxi_debounce_switch.sv
SYN_FILES += $(TAXI_SRC_DIR)/pyrite/rtl/pyrite_pcie_us_vpd_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/pcie4_uscale_plus_0.tcl
IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_phy_10g_us_gty_161.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)_primary.mcs $(PROJECT)_secondary.mcs $(PROJECT)_primary.prm $(PROJECT)_secondary.prm: $(PROJECT).bit
echo "write_cfgmem -force -format mcs -size 64 -interface SPIx8 -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 _primary.mcs _secondary.mcs _primary.prm _secondary.prm; \
do cp $*$$x rev/$*_rev$$COUNT$$x; \
echo "Output: rev/$*_rev$$COUNT$$x"; done;
flash: $(PROJECT)_primary.mcs $(PROJECT)_secondary.mcs $(PROJECT)_primary.prm $(PROJECT)_secondary.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 {mt25qu256-spi-x1_x2_x4_x8}] 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)_primary.mcs\" \"$(PROJECT)_secondary.mcs\"] [current_hw_cfgmem]" >> flash.tcl
echo "set_property PROGRAM.PRM_FILES [list \"$(PROJECT)_primary.prm\" \"$(PROJECT)_secondary.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 0x4B39093]
set fw_id [expr 0x0000C001]
set fw_ver $tag_ver
set board_vendor_id [expr 0x4144]
set board_device_id [expr 0x9003]
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]

View File

@@ -0,0 +1,30 @@
create_ip -name pcie4_uscale_plus -vendor xilinx.com -library ip -module_name pcie4_uscale_plus_0
set_property -dict [list \
CONFIG.PL_LINK_CAP_MAX_LINK_SPEED {8.0_GT/s} \
CONFIG.PL_LINK_CAP_MAX_LINK_WIDTH {X16} \
CONFIG.AXISTEN_IF_EXT_512_CQ_STRADDLE {false} \
CONFIG.AXISTEN_IF_EXT_512_RQ_STRADDLE {false} \
CONFIG.AXISTEN_IF_EXT_512_RC_4TLP_STRADDLE {false} \
CONFIG.axisten_if_enable_client_tag {true} \
CONFIG.axisten_if_width {512_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 {020000} \
CONFIG.PF0_DEVICE_ID {C001} \
CONFIG.PF0_SUBSYSTEM_ID {9003} \
CONFIG.PF0_SUBSYSTEM_VENDOR_ID {4144} \
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.legacy_ext_pcie_cfg_space_enabled {true} \
CONFIG.vendor_id {1234} \
CONFIG.mode_selection {Advanced} \
] [get_ips pcie4_uscale_plus_0]

View File

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

View File

@@ -0,0 +1,904 @@
// 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 = "virtexuplus",
// FW ID
parameter FPGA_ID = 32'h4B39093,
parameter FW_ID = 32'h0000C001,
parameter FW_VER = 32'h000_01_000,
parameter BOARD_ID = 32'h4144_9003,
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: 300MHz LVDS
*/
input wire logic clk_300mhz_p,
input wire logic clk_300mhz_n,
/*
* GPIO
*/
output wire logic [1:0] user_led_g,
output wire logic user_led_r,
output wire logic [1:0] front_led,
input wire logic [1:0] user_sw,
/*
* Ethernet: QSFP28
*/
output wire logic qsfp_0_tx_p[4],
output wire logic qsfp_0_tx_n[4],
input wire logic qsfp_0_rx_p[4],
input wire logic qsfp_0_rx_n[4],
input wire logic qsfp_0_mgt_refclk_p,
input wire logic qsfp_0_mgt_refclk_n,
input wire logic qsfp_0_modprs_l,
output wire logic qsfp_0_sel_l,
output wire logic qsfp_1_tx_p[4],
output wire logic qsfp_1_tx_n[4],
input wire logic qsfp_1_rx_p[4],
input wire logic qsfp_1_rx_n[4],
// input wire logic qsfp_1_mgt_refclk_p,
// input wire logic qsfp_1_mgt_refclk_n,
input wire logic qsfp_1_modprs_l,
output wire logic qsfp_1_sel_l,
output wire logic qsfp_reset_l,
input wire logic qsfp_int_l,
/*
* PCIe
*/
input wire logic [15:0] pcie_rx_p,
input wire logic [15:0] pcie_rx_n,
output wire logic [15:0] pcie_tx_p,
output wire logic [15:0] pcie_tx_n,
input wire logic pcie_refclk_1_p,
input wire logic pcie_refclk_1_n,
input wire logic pcie_reset_n,
/*
* QSPI
*/
inout wire logic [3:0] qspi_1_dq,
output wire logic qspi_1_cs
);
// Clock and reset
wire pcie_user_clk;
wire pcie_user_rst;
wire clk_300mhz_ibufg;
// Internal 125 MHz clock
wire clk_125mhz_mmcm_out;
wire clk_125mhz_int;
wire rst_125mhz_int;
wire mmcm_rst = 1'b0;
wire mmcm_locked;
wire mmcm_clkfb;
IBUFGDS #(
.DIFF_TERM("FALSE"),
.IBUF_LOW_PWR("FALSE")
)
clk_300mhz_ibufg_inst (
.O (clk_300mhz_ibufg),
.I (clk_300mhz_p),
.IB (clk_300mhz_n)
);
// MMCM instance
MMCME4_BASE #(
// 300 MHz input
.CLKIN1_PERIOD(3.333),
.REF_JITTER1(0.010),
// 300 MHz input / 3 = 100 MHz PFD (range 10 MHz to 500 MHz)
.DIVCLK_DIVIDE(3),
// 100 MHz PFD * 12.5 = 1250 MHz VCO (range 800 MHz to 1600 MHz)
.CLKFBOUT_MULT_F(12.5),
.CLKFBOUT_PHASE(0),
// 1250 MHz / 10 = 125 MHz, 0 degrees
.CLKOUT0_DIVIDE_F(10),
.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 (
// 300 MHz input
.CLKIN1(clk_300mhz_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)
);
// GPIO
wire [1:0] user_sw_int;
taxi_debounce_switch #(
.WIDTH(2),
.N(4),
.RATE(125000)
)
debounce_switch_inst (
.clk(clk_125mhz_int),
.rst(rst_125mhz_int),
.in({user_sw}),
.out({user_sw_int})
);
// Flash
wire qspi_clk_int;
wire [3:0] qspi_0_dq_int;
wire [3:0] qspi_0_dq_i_int;
wire [3:0] qspi_0_dq_o_int;
wire [3:0] qspi_0_dq_oe_int;
wire qspi_0_cs_int;
wire [3:0] qspi_1_dq_i_int;
wire [3:0] qspi_1_dq_o_int;
wire [3:0] qspi_1_dq_oe_int;
wire qspi_1_cs_int;
logic qspi_clk_reg;
logic [3:0] qspi_0_dq_o_reg;
logic [3:0] qspi_0_dq_oe_reg;
logic qspi_0_cs_reg;
logic [3:0] qspi_1_dq_o_reg;
logic [3:0] qspi_1_dq_oe_reg;
logic qspi_1_cs_reg;
always_ff @(posedge pcie_user_clk) begin
qspi_clk_reg <= qspi_clk_int;
qspi_0_dq_o_reg <= qspi_0_dq_o_int;
qspi_0_dq_oe_reg <= qspi_0_dq_oe_int;
qspi_0_cs_reg <= qspi_0_cs_int;
qspi_1_dq_o_reg <= qspi_1_dq_o_int;
qspi_1_dq_oe_reg <= qspi_1_dq_oe_int;
qspi_1_cs_reg <= qspi_1_cs_int;
end
assign qspi_1_dq[0] = qspi_1_dq_oe_reg[0] ? qspi_1_dq_o_reg[0] : 1'bz;
assign qspi_1_dq[1] = qspi_1_dq_oe_reg[1] ? qspi_1_dq_o_reg[1] : 1'bz;
assign qspi_1_dq[2] = qspi_1_dq_oe_reg[2] ? qspi_1_dq_o_reg[2] : 1'bz;
assign qspi_1_dq[3] = qspi_1_dq_oe_reg[3] ? qspi_1_dq_o_reg[3] : 1'bz;
assign qspi_1_cs = qspi_1_cs_reg;
taxi_sync_signal #(
.WIDTH(8),
.N(2)
)
flash_sync_signal_inst (
.clk(pcie_user_clk),
.in({qspi_1_dq, qspi_0_dq_int}),
.out({qspi_1_dq_i_int, qspi_0_dq_i_int})
);
STARTUPE3
startupe3_inst (
.CFGCLK(),
.CFGMCLK(),
.DI(qspi_0_dq_int),
.DO(qspi_0_dq_o_reg),
.DTS(~qspi_0_dq_oe_reg),
.EOS(),
.FCSBO(qspi_0_cs_reg),
.FCSBTS(1'b0),
.GSR(1'b0),
.GTS(1'b0),
.KEYCLEARB(1'b1),
.PACK(1'b0),
.PREQ(),
.USRCCLKO(qspi_clk_reg),
.USRCCLKTS(1'b0),
.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 = 512;
localparam AXIS_PCIE_KEEP_W = (AXIS_PCIE_DATA_W/32);
localparam AXIS_PCIE_RC_USER_W = AXIS_PCIE_DATA_W < 512 ? 75 : 161;
localparam AXIS_PCIE_RQ_USER_W = AXIS_PCIE_DATA_W < 512 ? 62 : 137;
localparam AXIS_PCIE_CQ_USER_W = AXIS_PCIE_DATA_W < 512 ? 85 : 183;
localparam AXIS_PCIE_CC_USER_W = AXIS_PCIE_DATA_W < 512 ? 33 : 81;
localparam RC_STRADDLE = 0; // AXIS_PCIE_DATA_W >= 256;
localparam RQ_STRADDLE = 0; // AXIS_PCIE_DATA_W >= 512;
localparam CQ_STRADDLE = 0; // AXIS_PCIE_DATA_W >= 512;
localparam CC_STRADDLE = 0; // AXIS_PCIE_DATA_W >= 512;
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_num0;
wire pcie_rq_seq_num_vld0;
wire [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num1;
wire pcie_rq_seq_num_vld1;
wire [2:0] cfg_max_payload;
wire [2:0] cfg_max_read_req;
wire [3:0] cfg_rcb_status;
wire [9:0] cfg_mgmt_addr;
wire [7:0] cfg_mgmt_function_number;
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 [1: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 [1: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 [7:0] cfg_interrupt_msi_tph_st_tag;
wire [7:0] cfg_interrupt_msi_function_number;
wire stat_err_cor;
wire stat_err_uncor;
wire pcie_sys_clk;
wire pcie_sys_clk_gt;
IBUFDS_GTE4 #(
.REFCLK_HROW_CK_SEL(2'b00)
)
ibufds_gte4_pcie_refclk_inst (
.I (pcie_refclk_1_p),
.IB (pcie_refclk_1_n),
.CEB (1'b0),
.O (pcie_sys_clk_gt),
.ODIV2 (pcie_sys_clk)
);
pcie4_uscale_plus_0
pcie4_uscale_plus_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_num0(pcie_rq_seq_num0),
.pcie_rq_seq_num_vld0(pcie_rq_seq_num_vld0),
.pcie_rq_seq_num1(pcie_rq_seq_num1),
.pcie_rq_seq_num_vld1(pcie_rq_seq_num_vld1),
.pcie_rq_tag0(),
.pcie_rq_tag1(),
.pcie_rq_tag_av(),
.pcie_rq_tag_vld0(),
.pcie_rq_tag_vld1(),
.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_function_number(cfg_mgmt_function_number),
.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_debug_access(1'b0),
.cfg_err_cor_out(),
.cfg_err_nonfatal_out(),
.cfg_err_fatal_out(),
.cfg_local_error_valid(),
.cfg_local_error_out(),
.cfg_ltssm_state(),
.cfg_rx_pm_state(),
.cfg_tx_pm_state(),
.cfg_rcb_status(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(),
.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_dsn(64'd0),
.cfg_bus_number(),
.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_func_num(8'd0),
.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_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_pm_aspm_l1_entry_reject(1'b0),
.cfg_pm_aspm_tx_l0s_entry_disable(1'b0),
.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),
.sys_clk(pcie_sys_clk),
.sys_clk_gt(pcie_sys_clk_gt),
.sys_reset(pcie_reset_n),
.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: 125 MHz
* Synchronous reset
*/
.clk_125mhz(clk_125mhz_int),
.rst_125mhz(rst_125mhz_int),
/*
* GPIO
*/
.user_led_g(user_led_g),
.user_led_r(user_led_r),
.front_led(front_led),
.user_sw(user_sw_int),
/*
* Ethernet: QSFP28
*/
.qsfp_0_tx_p(qsfp_0_tx_p),
.qsfp_0_tx_n(qsfp_0_tx_n),
.qsfp_0_rx_p(qsfp_0_rx_p),
.qsfp_0_rx_n(qsfp_0_rx_n),
.qsfp_0_mgt_refclk_p(qsfp_0_mgt_refclk_p),
.qsfp_0_mgt_refclk_n(qsfp_0_mgt_refclk_n),
.qsfp_0_modprs_l(qsfp_0_modprs_l),
.qsfp_0_sel_l(qsfp_0_sel_l),
.qsfp_1_tx_p(qsfp_1_tx_p),
.qsfp_1_tx_n(qsfp_1_tx_n),
.qsfp_1_rx_p(qsfp_1_rx_p),
.qsfp_1_rx_n(qsfp_1_rx_n),
// .qsfp_1_mgt_refclk_p(qsfp_1_mgt_refclk_p),
// .qsfp_1_mgt_refclk_n(qsfp_1_mgt_refclk_n),
.qsfp_1_modprs_l(qsfp_1_modprs_l),
.qsfp_1_sel_l(qsfp_1_sel_l),
.qsfp_reset_l(qsfp_reset_l),
.qsfp_int_l(qsfp_int_l),
/*
* 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_num0(pcie_rq_seq_num0),
.pcie_rq_seq_num_vld0(pcie_rq_seq_num_vld0),
.pcie_rq_seq_num1(pcie_rq_seq_num1),
.pcie_rq_seq_num_vld1(pcie_rq_seq_num_vld1),
.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_function_number(cfg_mgmt_function_number),
.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),
/*
* QSPI flash
*/
.fpga_boot(fpga_boot),
.qspi_clk(qspi_clk_int),
.qspi_0_dq_i(qspi_0_dq_i_int),
.qspi_0_dq_o(qspi_0_dq_o_int),
.qspi_0_dq_oe(qspi_0_dq_oe_int),
.qspi_0_cs(qspi_0_cs_int),
.qspi_1_dq_i(qspi_1_dq_i_int),
.qspi_1_dq_o(qspi_1_dq_o_int),
.qspi_1_dq_oe(qspi_1_dq_oe_int),
.qspi_1_cs(qspi_1_cs_int)
);
endmodule
`resetall

View File

@@ -0,0 +1,695 @@
// 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 = "virtexuplus",
// FW ID
parameter FPGA_ID = 32'h4B39093,
parameter FW_ID = 32'h0000C001,
parameter FW_VER = 32'h000_01_000,
parameter BOARD_ID = 32'h4144_9003,
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: 125 MHz
* Synchronous reset
*/
input wire logic clk_125mhz,
input wire logic rst_125mhz,
/*
* GPIO
*/
output wire logic [1:0] user_led_g,
output wire logic user_led_r,
output wire logic [1:0] front_led,
input wire logic [1:0] user_sw,
/*
* Ethernet: QSFP28
*/
output wire logic qsfp_0_tx_p[4],
output wire logic qsfp_0_tx_n[4],
input wire logic qsfp_0_rx_p[4],
input wire logic qsfp_0_rx_n[4],
input wire logic qsfp_0_mgt_refclk_p,
input wire logic qsfp_0_mgt_refclk_n,
input wire logic qsfp_0_modprs_l,
output wire logic qsfp_0_sel_l,
output wire logic qsfp_1_tx_p[4],
output wire logic qsfp_1_tx_n[4],
input wire logic qsfp_1_rx_p[4],
input wire logic qsfp_1_rx_n[4],
// input wire logic qsfp_1_mgt_refclk_p,
// input wire logic qsfp_1_mgt_refclk_n,
input wire logic qsfp_1_modprs_l,
output wire logic qsfp_1_sel_l,
output wire logic qsfp_reset_l,
input wire logic qsfp_int_l,
/*
* 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_num0,
input wire logic pcie_rq_seq_num_vld0,
input wire logic [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num1,
input wire logic pcie_rq_seq_num_vld1,
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 [9:0] cfg_mgmt_addr,
output wire logic [7:0] cfg_mgmt_function_number,
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 [1: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 [1: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 [7:0] cfg_interrupt_msi_tph_st_tag,
output wire logic [7:0] cfg_interrupt_msi_function_number,
/*
* QSPI flash
*/
output wire logic fpga_boot,
output wire logic qspi_clk,
input wire logic [3:0] qspi_0_dq_i,
output wire logic [3:0] qspi_0_dq_o,
output wire logic [3:0] qspi_0_dq_oe,
output wire logic qspi_0_cs,
input wire logic [3:0] qspi_1_dq_i,
output wire logic [3:0] qspi_1_dq_o,
output wire logic [3:0] qspi_1_dq_oe,
output wire logic qspi_1_cs
);
localparam logic PTP_TS_FMT_TOD = 1'b0;
localparam PTP_TS_W = PTP_TS_FMT_TOD ? 96 : 48;
// flashing via PCIe VPD
pyrite_pcie_us_vpd_qspi #(
.VPD_CAP_ID(8'h03),
.VPD_CAP_OFFSET(8'hB0),
.VPD_CAP_NEXT(8'h00),
// 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(2),
.FLASH_SEG_DEFAULT(1),
.FLASH_SEG_FALLBACK(0),
.FLASH_SEG0_SIZE(32'h00000000),
.FLASH_DATA_W(4),
.FLASH_DUAL_QSPI(1'b1)
)
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),
/*
* 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)
);
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
assign qsfp_0_sel_l = 1'b1;
assign qsfp_1_sel_l = 1'b1;
assign qsfp_reset_l = 1'b1;
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];
wire [1:0] qsfp_gtpowergood;
wire qsfp_0_mgt_refclk;
wire qsfp_0_mgt_refclk_int;
wire qsfp_0_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]();
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(8)) axis_qsfp_stat[2]();
if (SIM) begin
assign qsfp_0_mgt_refclk = qsfp_0_mgt_refclk_p;
assign qsfp_0_mgt_refclk_int = qsfp_0_mgt_refclk_p;
assign qsfp_0_mgt_refclk_bufg = qsfp_0_mgt_refclk_int;
end else begin
IBUFDS_GTE4 ibufds_gte4_qsfp_0_mgt_refclk_inst (
.I (qsfp_0_mgt_refclk_p),
.IB (qsfp_0_mgt_refclk_n),
.CEB (1'b0),
.O (qsfp_0_mgt_refclk),
.ODIV2 (qsfp_0_mgt_refclk_int)
);
BUFG_GT bufg_gt_qsfp_0_mgt_refclk_inst (
.CE (&qsfp_gtpowergood),
.CEMASK (1'b1),
.CLR (1'b0),
.CLRMASK (1'b1),
.DIV (3'd0),
.I (qsfp_0_mgt_refclk_int),
.O (qsfp_0_mgt_refclk_bufg)
);
end
taxi_sync_reset #(
.N(4)
)
qsfp_sync_reset_inst (
.clk(qsfp_0_mgt_refclk_bufg),
.rst(rst_125mhz),
.out(qsfp_rst)
);
wire ptp_clk = qsfp_0_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_g[0] = ptp_pps_str;
assign user_led_g[1] = 1'b0;
assign user_led_r = 1'b0;
wire qsfp_tx_p[8];
wire qsfp_tx_n[8];
wire qsfp_rx_p[8];
wire qsfp_rx_n[8];
assign qsfp_0_tx_p = qsfp_tx_p[4*0 +: 4];
assign qsfp_0_tx_n = qsfp_tx_n[4*0 +: 4];
assign qsfp_1_tx_p = qsfp_tx_p[4*1 +: 4];
assign qsfp_1_tx_n = qsfp_tx_n[4*1 +: 4];
assign qsfp_rx_p[4*0 +: 4] = qsfp_0_rx_p;
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_n[4*1 +: 4] = qsfp_1_rx_n;
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_eth_mac_25g_us #(
.SIM(SIM),
.VENDOR(VENDOR),
.FAMILY(FAMILY),
.CNT(CNT),
// GT config
.CFG_LOW_LATENCY(CFG_LOW_LATENCY),
// GT type
.GT_TYPE("GTY"),
// PHY parameters
.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'b0)
)
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(qsfp_0_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(qsfp_0_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_qsfp_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
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(1024),
.PTP_CLK_PER_NS_DEN(165),
// 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_num0),
.pcie_rq_seq_num_vld0(pcie_rq_seq_num_vld0),
.pcie_rq_seq_num1(pcie_rq_seq_num1),
.pcie_rq_seq_num_vld1(pcie_rq_seq_num_vld1),
.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_function_number(cfg_mgmt_function_number),
.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(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),
/*
* 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,71 @@
# 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)/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_signal.sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/io/rtl/taxi_debounce_switch.sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/pyrite/rtl/pyrite_pcie_us_vpd_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 := "\"virtexuplus\""
# 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 := "64"
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,522 @@
#!/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 pytest
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.pcie.core import RootComplex
from cocotbext.pcie.xilinx.us import UltraScalePlusPcieDevice
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 = UltraScalePlusPcieDevice(
# configuration options
pcie_generation=3,
pcie_link_width=16,
user_clk_frequency=250e6,
alignment="dword",
cq_straddle=False,
cc_straddle=False,
rq_straddle=False,
rc_straddle=False,
rc_4tlp_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,
pf2_msi_enable=False,
pf2_msi_count=1,
pf3_msi_enable=False,
pf3_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,
pf2_msix_enable=False,
pf2_msix_table_size=0,
pf2_msix_table_bir=0,
pf2_msix_table_offset=0x00000000,
pf2_msix_pba_bir=0,
pf2_msix_pba_offset=0x00000000,
pf3_msix_enable=False,
pf3_msix_table_size=0,
pf3_msix_table_bir=0,
pf3_msix_table_offset=0x00000000,
pf3_msix_pba_bir=0,
pf3_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_num0=dut.pcie_rq_seq_num0,
pcie_rq_seq_num_vld0=dut.pcie_rq_seq_num_vld0,
pcie_rq_seq_num1=dut.pcie_rq_seq_num1,
pcie_rq_seq_num_vld1=dut.pcie_rq_seq_num_vld1,
# pcie_rq_tag0
# pcie_rq_tag1
# pcie_rq_tag_av
# pcie_rq_tag_vld0
# pcie_rq_tag_vld1
# 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_function_number=dut.cfg_mgmt_function_number,
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_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_vec_pending=dut.cfg_interrupt_msix_vec_pending,
# cfg_interrupt_msix_vec_pending_status=dut.cfg_interrupt_msix_vec_pending_status,
# 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.qsfp_0_mgt_refclk_p, 6.206, 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 = 2.482
gbx_cfg = (66, [64, 65])
else:
clk = 2.56
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
))
dut.user_sw.setimmediatevalue(0)
dut.qsfp_0_modprs_l.setimmediatevalue(0)
dut.qsfp_1_modprs_l.setimmediatevalue(0)
dut.qsfp_int_l.setimmediatevalue(0)
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())
@pytest.mark.parametrize("mac_data_w", [32, 64])
def test_fpga_core(request, mac_data_w):
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, "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_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_vpd_qspi.f"),
]
verilog_sources = process_f_files(verilog_sources)
parameters = {}
parameters['SIM'] = "1'b1"
parameters['VENDOR'] = "\"XILINX\""
parameters['FAMILY'] = "\"virtexuplus\""
# 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'] = mac_data_w
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,328 @@
// 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 = "virtexuplus",
// FW ID
parameter FPGA_ID = 32'h4B39093,
parameter FW_ID = 32'h0000C001,
parameter FW_VER = 32'h000_01_000,
parameter BOARD_ID = 32'h4144_9003,
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 = 512,
parameter AXIS_PCIE_RC_USER_W = AXIS_PCIE_DATA_W < 512 ? 75 : 161,
parameter AXIS_PCIE_RQ_USER_W = AXIS_PCIE_DATA_W < 512 ? 62 : 137,
parameter AXIS_PCIE_CQ_USER_W = AXIS_PCIE_DATA_W < 512 ? 85 : 183,
parameter AXIS_PCIE_CC_USER_W = AXIS_PCIE_DATA_W < 512 ? 33 : 81,
// 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
/* 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 [1:0] user_led_g;
logic user_led_r;
logic [1:0] front_led;
logic [1:0] user_sw;
logic qsfp_0_mgt_refclk_p;
logic qsfp_0_mgt_refclk_n;
logic qsfp_0_modprs_l;
logic qsfp_0_sel_l;
// logic qsfp_1_mgt_refclk_p;
// logic qsfp_1_mgt_refclk_n;
logic qsfp_1_modprs_l;
logic qsfp_1_sel_l;
logic qsfp_reset_l;
logic qsfp_int_l;
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_num0;
logic pcie_rq_seq_num_vld0;
logic [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num1;
logic pcie_rq_seq_num_vld1;
logic [2:0] cfg_max_payload;
logic [2:0] cfg_max_read_req;
logic [3:0] cfg_rcb_status;
logic [9:0] cfg_mgmt_addr;
logic [7:0] cfg_mgmt_function_number;
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 [1: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 [1: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 [7:0] cfg_interrupt_msi_tph_st_tag;
logic [7: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
*/
.user_led_g(user_led_g),
.user_led_r(user_led_r),
.front_led(front_led),
.user_sw(user_sw),
/*
* Ethernet: QSFP28
*/
.qsfp_0_tx_p(),
.qsfp_0_tx_n(),
.qsfp_0_rx_p('{4{1'b0}}),
.qsfp_0_rx_n('{4{1'b0}}),
.qsfp_0_mgt_refclk_p(qsfp_0_mgt_refclk_p),
.qsfp_0_mgt_refclk_n(qsfp_0_mgt_refclk_n),
.qsfp_0_modprs_l(qsfp_0_modprs_l),
.qsfp_0_sel_l(qsfp_0_sel_l),
.qsfp_1_tx_p(),
.qsfp_1_tx_n(),
.qsfp_1_rx_p('{4{1'b0}}),
.qsfp_1_rx_n('{4{1'b0}}),
// .qsfp_1_mgt_refclk_p(qsfp_1_mgt_refclk_p),
// .qsfp_1_mgt_refclk_n(qsfp_1_mgt_refclk_n),
.qsfp_1_modprs_l(qsfp_1_modprs_l),
.qsfp_1_sel_l(qsfp_1_sel_l),
.qsfp_reset_l(qsfp_reset_l),
.qsfp_int_l(qsfp_int_l),
/*
* 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_num0),
.pcie_rq_seq_num_vld0(pcie_rq_seq_num_vld0),
.pcie_rq_seq_num1(pcie_rq_seq_num1),
.pcie_rq_seq_num_vld1(pcie_rq_seq_num_vld1),
.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_function_number(cfg_mgmt_function_number),
.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

@@ -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
@@ -25,8 +25,8 @@ This design targets the Alibaba AS02MC04 FPGA board.
Run `make` in the appropriate `fpga*` subdirectory to build the bitstream. Ensure that the Xilinx Vivado toolchain components are in PATH. 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_proto` to build the driver. Ensure that the headers for the running kernel are installed, otherwise the driver cannot be compiled. 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 ## 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_proto.ko`. Check `dmesg` for output from driver initialization. Run `cndm_proto_ddcmd.sh =p` to enable all debug messages. 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

@@ -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

@@ -18,11 +18,13 @@ TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
# Files for synthesis # Files for synthesis
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)/corundum/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
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv
SYN_FILES += $(TAXI_SRC_DIR)/pyrite/rtl/pyrite_pcie_us_vpd_qspi.f
# XDC files # XDC files
XDC_FILES = ../fpga.xdc XDC_FILES = ../fpga.xdc

View File

@@ -1,6 +1,6 @@
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
# #
# Copyright (c) 2025 FPGA Ninja, LLC # Copyright (c) 2025-2026 FPGA Ninja, LLC
# #
# Authors: # Authors:
# - Alex Forencich # - Alex Forencich
@@ -8,11 +8,120 @@
set params [dict create] set params [dict create]
# 10G MAC configuration # 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 0x4A63093]
set fw_id [expr 0x0000C001]
set fw_ver $tag_ver
set board_vendor_id [expr 0x1ded]
set board_device_id [expr 0x0009]
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 CFG_LOW_LATENCY "1"
dict set params COMBINED_MAC_PCS "1" dict set params COMBINED_MAC_PCS "1"
dict set params MAC_DATA_W "64" 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 # apply parameters to top-level
set param_list {} set param_list {}
dict for {name value} $params { dict for {name value} $params {

View File

@@ -19,10 +19,12 @@ 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
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv
SYN_FILES += $(TAXI_SRC_DIR)/pyrite/rtl/pyrite_pcie_us_vpd_qspi.f
# XDC files # XDC files
XDC_FILES = ../fpga.xdc XDC_FILES = ../fpga.xdc

View File

@@ -1,6 +1,6 @@
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
# #
# Copyright (c) 2025 FPGA Ninja, LLC # Copyright (c) 2025-2026 FPGA Ninja, LLC
# #
# Authors: # Authors:
# - Alex Forencich # - Alex Forencich
@@ -8,11 +8,120 @@
set params [dict create] set params [dict create]
# 10G MAC configuration # 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 0x4A63093]
set fw_id [expr 0x0000C001]
set fw_ver $tag_ver
set board_vendor_id [expr 0x1ded]
set board_device_id [expr 0x0009]
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 CFG_LOW_LATENCY "1"
dict set params COMBINED_MAC_PCS "1" dict set params COMBINED_MAC_PCS "1"
dict set params MAC_DATA_W "32" 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 # apply parameters to top-level
set param_list {} set param_list {}
dict for {name value} $params { dict for {name value} $params {

View File

@@ -10,7 +10,8 @@ set_property -dict [list \
CONFIG.extended_tag_field {true} \ CONFIG.extended_tag_field {true} \
CONFIG.pf0_dev_cap_max_payload {1024_bytes} \ CONFIG.pf0_dev_cap_max_payload {1024_bytes} \
CONFIG.axisten_freq {250} \ CONFIG.axisten_freq {250} \
CONFIG.PF0_CLASS_CODE {058000} \ CONFIG.PF0_Use_Class_Code_Lookup_Assistant {false} \
CONFIG.PF0_CLASS_CODE {020000} \
CONFIG.PF0_DEVICE_ID {C001} \ CONFIG.PF0_DEVICE_ID {C001} \
CONFIG.PF0_SUBSYSTEM_ID {0009} \ CONFIG.PF0_SUBSYSTEM_ID {0009} \
CONFIG.PF0_SUBSYSTEM_VENDOR_ID {1ded} \ CONFIG.PF0_SUBSYSTEM_VENDOR_ID {1ded} \
@@ -21,6 +22,7 @@ set_property -dict [list \
CONFIG.pf0_msi_enabled {true} \ CONFIG.pf0_msi_enabled {true} \
CONFIG.PF0_MSI_CAP_MULTIMSGCAP {32_vectors} \ CONFIG.PF0_MSI_CAP_MULTIMSGCAP {32_vectors} \
CONFIG.en_msi_per_vec_masking {true} \ CONFIG.en_msi_per_vec_masking {true} \
CONFIG.legacy_ext_pcie_cfg_space_enabled {true} \
CONFIG.vendor_id {1234} \ CONFIG.vendor_id {1234} \
CONFIG.mode_selection {Advanced} \ CONFIG.mode_selection {Advanced} \
CONFIG.en_gt_selection {true} \ CONFIG.en_gt_selection {true} \

View File

@@ -23,9 +23,25 @@ module fpga #
parameter string VENDOR = "XILINX", parameter string VENDOR = "XILINX",
// device family // device family
parameter string FAMILY = "kintexuplus", parameter string FAMILY = "kintexuplus",
// FW ID
parameter FPGA_ID = 32'h4A63093,
parameter FW_ID = 32'h0000C001,
parameter FW_VER = 32'h000_01_000,
parameter BOARD_ID = 32'h1ded_0009,
parameter BOARD_VER = 32'h001_00_000,
parameter BUILD_DATE = 32'd602976000,
parameter GIT_HASH = 32'h5f87c2e8,
parameter RELEASE_INFO = 32'h00000000,
// PTP configuration // PTP configuration
parameter logic PTP_TS_EN = 1'b1, parameter logic PTP_TS_EN = 1'b1,
// 10G/25G MAC configuration
// 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 CFG_LOW_LATENCY = 1'b1,
parameter logic COMBINED_MAC_PCS = 1'b1, parameter logic COMBINED_MAC_PCS = 1'b1,
parameter MAC_DATA_W = 64 parameter MAC_DATA_W = 64
@@ -48,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+
*/ */
@@ -60,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
@@ -74,6 +104,8 @@ module fpga #
); );
// Clock and reset // Clock and reset
wire pcie_user_clk;
wire pcie_user_rst;
wire clk_100mhz_ibufg; wire clk_100mhz_ibufg;
@@ -189,6 +221,261 @@ 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
wire qspi_clk_int;
wire [3:0] qspi_dq_int;
wire [3:0] qspi_dq_i_int;
wire [3:0] qspi_dq_o_int;
wire [3:0] qspi_dq_oe_int;
wire qspi_cs_int;
reg qspi_clk_reg;
reg [3:0] qspi_dq_o_reg;
reg [3:0] qspi_dq_oe_reg;
reg qspi_cs_reg;
always_ff @(posedge pcie_user_clk) begin
qspi_clk_reg <= qspi_clk_int;
qspi_dq_o_reg <= qspi_dq_o_int;
qspi_dq_oe_reg <= qspi_dq_oe_int;
qspi_cs_reg <= qspi_cs_int;
end
taxi_sync_signal #(
.WIDTH(8),
.N(2)
)
flash_sync_inst (
.clk(pcie_user_clk),
.in({qspi_dq_int}),
.out({qspi_dq_i_int})
);
STARTUPE3
startupe3_inst (
.CFGCLK(),
.CFGMCLK(),
.DI(qspi_dq_int),
.DO(qspi_dq_o_reg),
.DTS(~qspi_dq_oe_reg),
.EOS(),
.FCSBO(qspi_cs_reg),
.FCSBTS(1'b0),
.GSR(1'b0),
.GTS(1'b0),
.KEYCLEARB(1'b1),
.PACK(1'b0),
.PREQ(),
.USRCCLKO(qspi_clk_reg),
.USRCCLKTS(1'b0),
.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 // PCIe
localparam AXIS_PCIE_DATA_W = 256; localparam AXIS_PCIE_DATA_W = 256;
localparam AXIS_PCIE_KEEP_W = (AXIS_PCIE_DATA_W/32); localparam AXIS_PCIE_KEEP_W = (AXIS_PCIE_DATA_W/32);
@@ -201,12 +488,9 @@ 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_W = AXIS_PCIE_RQ_USER_W == 60 ? 4 : 6;
localparam RQ_SEQ_NUM_EN = 1; localparam RQ_SEQ_NUM_EN = 1;
localparam PCIE_TAG_CNT = 64; localparam PCIE_TAG_CNT = AXIS_PCIE_RQ_USER_W == 60 ? 64 : 256;
localparam BAR0_APERTURE = 24; localparam BAR0_APERTURE = 24;
logic pcie_user_clk;
logic pcie_user_rst;
taxi_axis_if #( taxi_axis_if #(
.DATA_W(AXIS_PCIE_DATA_W), .DATA_W(AXIS_PCIE_DATA_W),
.KEEP_EN(1), .KEEP_EN(1),
@@ -265,6 +549,15 @@ wire [7:0] cfg_fc_cplh;
wire [11:0] cfg_fc_cpld; wire [11:0] cfg_fc_cpld;
wire [2:0] cfg_fc_sel; 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_enable;
// wire [3:0] cfg_interrupt_msix_mask; // wire [3:0] cfg_interrupt_msix_mask;
// wire [251:0] cfg_interrupt_msix_vf_enable; // wire [251:0] cfg_interrupt_msix_vf_enable;
@@ -437,6 +730,15 @@ pcie4_uscale_plus_inst (
.cfg_link_training_enable(1'b1), .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_int(4'd0),
.cfg_interrupt_pending(4'd0), .cfg_interrupt_pending(4'd0),
.cfg_interrupt_sent(), .cfg_interrupt_sent(),
@@ -493,7 +795,28 @@ fpga_core #(
.SIM(SIM), .SIM(SIM),
.VENDOR(VENDOR), .VENDOR(VENDOR),
.FAMILY(FAMILY), .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), .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), .CFG_LOW_LATENCY(CFG_LOW_LATENCY),
.COMBINED_MAC_PCS(COMBINED_MAC_PCS), .COMBINED_MAC_PCS(COMBINED_MAC_PCS),
.MAC_DATA_W(MAC_DATA_W) .MAC_DATA_W(MAC_DATA_W)
@@ -515,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+
*/ */
@@ -525,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
@@ -565,6 +909,15 @@ core_inst (
.cfg_fc_cpld(cfg_fc_cpld), .cfg_fc_cpld(cfg_fc_cpld),
.cfg_fc_sel(cfg_fc_sel), .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_enable(cfg_interrupt_msix_enable),
// .cfg_interrupt_msix_mask(cfg_interrupt_msix_mask), // .cfg_interrupt_msix_mask(cfg_interrupt_msix_mask),
// .cfg_interrupt_msix_vf_enable(cfg_interrupt_msix_vf_enable), // .cfg_interrupt_msix_vf_enable(cfg_interrupt_msix_vf_enable),
@@ -593,7 +946,17 @@ core_inst (
.cfg_interrupt_msi_tph_present(cfg_interrupt_msi_tph_present), .cfg_interrupt_msi_tph_present(cfg_interrupt_msi_tph_present),
.cfg_interrupt_msi_tph_type(cfg_interrupt_msi_tph_type), .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_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),
/*
* QSPI flash
*/
.fpga_boot(fpga_boot),
.qspi_clk(qspi_clk_int),
.qspi_dq_i(qspi_dq_i_int),
.qspi_dq_o(qspi_dq_o_int),
.qspi_dq_oe(qspi_dq_oe_int),
.qspi_cs(qspi_cs_int)
); );
endmodule endmodule

View File

@@ -23,10 +23,28 @@ module fpga_core #
parameter string VENDOR = "XILINX", parameter string VENDOR = "XILINX",
// device family // device family
parameter string FAMILY = "kintexuplus", parameter string FAMILY = "kintexuplus",
parameter RQ_SEQ_NUM_W = 6,
// FW ID
parameter FPGA_ID = 32'h4A63093,
parameter FW_ID = 32'h0000C001,
parameter FW_VER = 32'h000_01_000,
parameter BOARD_ID = 32'h1ded_0009,
parameter BOARD_VER = 32'h001_00_000,
parameter BUILD_DATE = 32'd602976000,
parameter GIT_HASH = 32'h5f87c2e8,
parameter RELEASE_INFO = 32'h00000000,
// PTP configuration // PTP configuration
parameter logic PTP_TS_EN = 1'b1, parameter logic PTP_TS_EN = 1'b1,
// 10G/25G MAC configuration
// 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 CFG_LOW_LATENCY = 1'b1,
parameter logic COMBINED_MAC_PCS = 1'b1, parameter logic COMBINED_MAC_PCS = 1'b1,
parameter MAC_DATA_W = 64 parameter MAC_DATA_W = 64
@@ -36,89 +54,299 @@ module fpga_core #
* Clock: 125MHz * Clock: 125MHz
* Synchronous reset * Synchronous reset
*/ */
input wire logic clk_125mhz, input wire logic clk_125mhz,
input wire logic rst_125mhz, input wire logic rst_125mhz,
/* /*
* GPIO * GPIO
*/ */
output wire logic sfp_led[2], output wire logic sfp_led[2],
output wire logic [3:0] led, output wire logic [3:0] led,
output wire logic led_r, output wire logic led_r,
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+
*/ */
input wire logic sfp_rx_p[2], input wire logic sfp_rx_p[2],
input wire logic sfp_rx_n[2], input wire logic sfp_rx_n[2],
output wire logic sfp_tx_p[2], output wire logic sfp_tx_p[2],
output wire logic sfp_tx_n[2], output wire logic sfp_tx_n[2],
input wire logic sfp_mgt_refclk_p, input wire logic sfp_mgt_refclk_p,
input wire logic sfp_mgt_refclk_n, input wire logic sfp_mgt_refclk_n,
output wire logic sfp_mgt_refclk_out, output wire logic sfp_mgt_refclk_out,
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,
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
*/ */
input wire logic pcie_clk, input wire logic pcie_clk,
input wire logic pcie_rst, input wire logic pcie_rst,
taxi_axis_if.snk s_axis_pcie_cq, taxi_axis_if.snk s_axis_pcie_cq,
taxi_axis_if.src m_axis_pcie_cc, taxi_axis_if.src m_axis_pcie_cc,
taxi_axis_if.src m_axis_pcie_rq, taxi_axis_if.src m_axis_pcie_rq,
taxi_axis_if.snk s_axis_pcie_rc, taxi_axis_if.snk s_axis_pcie_rc,
input wire [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num0, input wire logic [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num0,
input wire pcie_rq_seq_num_vld0, input wire logic pcie_rq_seq_num_vld0,
input wire [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num1, input wire logic [RQ_SEQ_NUM_W-1:0] pcie_rq_seq_num1,
input wire pcie_rq_seq_num_vld1, input wire logic pcie_rq_seq_num_vld1,
input wire [2:0] cfg_max_payload, input wire logic [2:0] cfg_max_payload,
input wire [2:0] cfg_max_read_req, input wire logic [2:0] cfg_max_read_req,
input wire [3:0] cfg_rcb_status, input wire logic [3:0] cfg_rcb_status,
output wire [9:0] cfg_mgmt_addr, output wire logic [9:0] cfg_mgmt_addr,
output wire [7:0] cfg_mgmt_function_number, output wire logic [7:0] cfg_mgmt_function_number,
output wire cfg_mgmt_write, output wire logic cfg_mgmt_write,
output wire [31:0] cfg_mgmt_write_data, output wire logic [31:0] cfg_mgmt_write_data,
output wire [3:0] cfg_mgmt_byte_enable, output wire logic [3:0] cfg_mgmt_byte_enable,
output wire cfg_mgmt_read, output wire logic cfg_mgmt_read,
output wire [31:0] cfg_mgmt_read_data, output wire logic [31:0] cfg_mgmt_read_data,
input wire cfg_mgmt_read_write_done, input wire logic cfg_mgmt_read_write_done,
input wire [7:0] cfg_fc_ph, input wire logic [7:0] cfg_fc_ph,
input wire [11:0] cfg_fc_pd, input wire logic [11:0] cfg_fc_pd,
input wire [7:0] cfg_fc_nph, input wire logic [7:0] cfg_fc_nph,
input wire [11:0] cfg_fc_npd, input wire logic [11:0] cfg_fc_npd,
input wire [7:0] cfg_fc_cplh, input wire logic [7:0] cfg_fc_cplh,
input wire [11:0] cfg_fc_cpld, input wire logic [11:0] cfg_fc_cpld,
output wire [2:0] cfg_fc_sel, output wire logic [2:0] cfg_fc_sel,
input wire [3:0] cfg_interrupt_msi_enable, input wire logic cfg_ext_read_received,
input wire [11:0] cfg_interrupt_msi_mmenable, input wire logic cfg_ext_write_received,
input wire cfg_interrupt_msi_mask_update, input wire logic [9:0] cfg_ext_register_number,
input wire [31:0] cfg_interrupt_msi_data, input wire logic [7:0] cfg_ext_function_number,
output wire [1:0] cfg_interrupt_msi_select, input wire logic [31:0] cfg_ext_write_data,
output wire [31:0] cfg_interrupt_msi_int, input wire logic [3:0] cfg_ext_write_byte_enable,
output wire [31:0] cfg_interrupt_msi_pending_status, output wire logic [31:0] cfg_ext_read_data,
output wire cfg_interrupt_msi_pending_status_data_enable, output wire logic cfg_ext_read_data_valid,
output wire [1:0] cfg_interrupt_msi_pending_status_function_num,
input wire cfg_interrupt_msi_sent, input wire logic [3:0] cfg_interrupt_msi_enable,
input wire cfg_interrupt_msi_fail, input wire logic [11:0] cfg_interrupt_msi_mmenable,
output wire [2:0] cfg_interrupt_msi_attr, input wire logic cfg_interrupt_msi_mask_update,
output wire cfg_interrupt_msi_tph_present, input wire logic [31:0] cfg_interrupt_msi_data,
output wire [1:0] cfg_interrupt_msi_tph_type, output wire logic [1:0] cfg_interrupt_msi_select,
output wire [7:0] cfg_interrupt_msi_tph_st_tag, output wire logic [31:0] cfg_interrupt_msi_int,
output wire [7:0] cfg_interrupt_msi_function_number output wire logic [31:0] cfg_interrupt_msi_pending_status,
output wire logic cfg_interrupt_msi_pending_status_data_enable,
output wire logic [1: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 [7:0] cfg_interrupt_msi_tph_st_tag,
output wire logic [7:0] cfg_interrupt_msi_function_number,
/*
* QSPI flash
*/
output wire logic fpga_boot,
output wire logic qspi_clk,
input wire logic [3:0] qspi_dq_i,
output wire logic [3:0] qspi_dq_o,
output wire logic [3:0] qspi_dq_oe,
output wire logic qspi_cs
); );
localparam logic PTP_TS_FMT_TOD = 1'b0; localparam logic PTP_TS_FMT_TOD = 1'b0;
localparam PTP_TS_W = PTP_TS_FMT_TOD ? 96 : 48; localparam PTP_TS_W = PTP_TS_FMT_TOD ? 96 : 48;
// flashing via PCIe VPD
pyrite_pcie_us_vpd_qspi #(
.VPD_CAP_ID(8'h03),
.VPD_CAP_OFFSET(8'hB0),
.VPD_CAP_NEXT(8'h00),
// 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(2),
.FLASH_SEG_DEFAULT(1),
.FLASH_SEG_FALLBACK(0),
.FLASH_SEG0_SIZE(32'h00000000),
.FLASH_DATA_W(4),
.FLASH_DUAL_QSPI(1'b0)
)
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),
/*
* QSPI flash
*/
.fpga_boot(fpga_boot),
.qspi_clk(qspi_clk),
.qspi_0_dq_i(qspi_dq_i),
.qspi_0_dq_o(qspi_dq_o),
.qspi_0_dq_oe(qspi_dq_oe),
.qspi_0_cs(qspi_cs),
.qspi_1_dq_i('0),
.qspi_1_dq_o(),
.qspi_1_dq_oe(),
.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];
@@ -462,12 +690,35 @@ cndm_micro_pcie_us #(
.SIM(SIM), .SIM(SIM),
.VENDOR(VENDOR), .VENDOR(VENDOR),
.FAMILY(FAMILY), .FAMILY(FAMILY),
.PORTS(2),
// 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_sfp_tx)),
.BRD_CTRL_EN(1'b1),
.SYS_CLK_PER_NS_NUM(4),
.SYS_CLK_PER_NS_DEN(1),
// PTP configuration
.PTP_TS_EN(PTP_TS_EN), .PTP_TS_EN(PTP_TS_EN),
.PTP_TS_FMT_TOD(1'b0),
.PTP_CLK_PER_NS_NUM(32), .PTP_CLK_PER_NS_NUM(32),
.PTP_CLK_PER_NS_DENOM(5), .PTP_CLK_PER_NS_DEN(5),
// PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W), .RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),
.BAR0_APERTURE(24)
// AXI lite interface configuration (control)
.AXIL_CTRL_DATA_W(AXIL_CTRL_DATA_W),
.AXIL_CTRL_ADDR_W(AXIL_CTRL_ADDR_W)
) )
cndm_inst ( cndm_inst (
/* /*
@@ -523,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
*/ */

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