Compare commits

...

152 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
371 changed files with 45125 additions and 3310 deletions

View File

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

View File

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

View File

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

@@ -91,11 +91,12 @@ if (m_axil_wr.DATA_W != m_axil_rd.DATA_W)
if (AXIL_BYTE_LANES == APB_BYTE_LANES) begin : bypass if (AXIL_BYTE_LANES == APB_BYTE_LANES) begin : bypass
// 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 s_apb_pready_reg = 1'b0, s_apb_pready_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 [APB_DATA_W-1:0] s_apb_prdata_reg = '0, s_apb_prdata_next;
@@ -167,7 +168,7 @@ if (AXIL_BYTE_LANES == APB_BYTE_LANES) begin : bypass
m_axil_auser_next = s_apb.pauser; m_axil_auser_next = s_apb.pauser;
m_axil_wuser_next = s_apb.pwuser; m_axil_wuser_next = s_apb.pwuser;
if (s_apb.psel && s_apb.penable && !s_apb.pready) begin if (s_apb.psel && !s_apb.pready) begin
if (s_apb.pwrite) begin if (s_apb.pwrite) begin
m_axil_awvalid_next = 1'b1; m_axil_awvalid_next = 1'b1;
m_axil_wvalid_next = 1'b1; m_axil_wvalid_next = 1'b1;
@@ -243,11 +244,12 @@ if (AXIL_BYTE_LANES == APB_BYTE_LANES) begin : bypass
end else if (AXIL_BYTE_LANES > APB_BYTE_LANES) begin : upsize end else if (AXIL_BYTE_LANES > APB_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 [APB_DATA_W-1:0] s_apb_prdata_reg = '0, s_apb_prdata_next; logic [APB_DATA_W-1:0] s_apb_prdata_reg = '0, s_apb_prdata_next;
@@ -320,7 +322,7 @@ end else if (AXIL_BYTE_LANES > APB_BYTE_LANES) begin : upsize
m_axil_auser_next = s_apb.pauser; m_axil_auser_next = s_apb.pauser;
m_axil_wuser_next = s_apb.pwuser; m_axil_wuser_next = s_apb.pwuser;
if (s_apb.psel && s_apb.penable && !s_apb.pready) begin if (s_apb.psel && !s_apb.pready) begin
if (s_apb.pwrite) begin if (s_apb.pwrite) begin
m_axil_awvalid_next = 1'b1; m_axil_awvalid_next = 1'b1;
m_axil_wvalid_next = 1'b1; m_axil_wvalid_next = 1'b1;
@@ -406,11 +408,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;
@@ -498,7 +501,7 @@ end else begin : downsize
s_apb_pslverr_next = 1'b0; s_apb_pslverr_next = 1'b0;
if (s_apb.psel && s_apb.penable && !s_apb.pready) begin if (s_apb.psel && !s_apb.pready) begin
if (s_apb.pwrite) begin if (s_apb.pwrite) begin
m_axil_awvalid_next = 1'b1; m_axil_awvalid_next = 1'b1;
m_axil_wvalid_next = 1'b1; m_axil_wvalid_next = 1'b1;

View File

@@ -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];
wire [PBUSER_W-1:0] cur_m_apb_pbuser = m_apb_pbuser[m_sel_reg];
// arbiter instance
wire [S_CNT-1:0] req;
wire [S_CNT-1:0] ack;
wire [S_CNT-1:0] grant;
wire grant_valid;
wire [CL_S_CNT_INT-1:0] grant_index;
assign s_sel = grant_index;
if (S_CNT > 1) begin : arb
taxi_arbiter #(
.PORTS(S_CNT),
.ARB_ROUND_ROBIN(1),
.ARB_BLOCK(1),
.ARB_BLOCK_ACK(1),
.LSB_HIGH_PRIO(1)
)
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 end
if (!act_reg) begin if (ack || rst) begin
m_apb_paddr_reg <= s_apb.paddr; grant_valid_reg <= 1'b0;
m_apb_pprot_reg <= s_apb.pprot; end
m_apb_pwrite_reg <= s_apb.pwrite; end
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; assign grant_valid = grant_valid_reg;
m_apb_penable_reg <= 1'b0; assign grant = grant_valid_reg;
assign grant_index = '0;
if (s_apb.psel && s_apb.penable && !s_apb_pready_reg) begin end
act_reg <= 1'b1;
// 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 i = 0; i < M_CNT; i = i + 1) begin
for (integer j = 0; j < M_REGIONS; j = j + 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 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
sel_reg <= CL_M_CNT_INT'(i); m_sel_next = CL_M_CNT_INT'(i);
m_apb_psel_reg[i] <= 1'b1; match = 1'b1;
end
end
end end
end 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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
if (m_apb_pwrite_reg) begin
s_axil_buser_next = m_apb.pbuser; s_axil_buser_next = m_apb.pbuser;
end else 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_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_ruser_next = m_apb.pruser;
s_axil_resp_next = m_apb.pslverr ? AXI_RESP_SLVERR : AXI_RESP_OKAY; 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

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

View File

@@ -9,6 +9,7 @@ Authors:
""" """
import itertools
import logging import logging
import os import os
import sys import sys
@@ -282,8 +283,7 @@ class TB:
self.qsfp_sources = [] self.qsfp_sources = []
self.qsfp_sinks = [] self.qsfp_sinks = []
for inst in dut.uut.gty_quad: for ch in itertools.chain.from_iterable([inst.mac_inst.ch for inst in dut.uut.gt_quad]):
for ch in inst.mac_inst.ch:
gt_inst = ch.ch_inst.gt.gt_inst gt_inst = ch.ch_inst.gt.gt_inst
if ch.ch_inst.DATA_W.value == 64: if ch.ch_inst.DATA_W.value == 64:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -803,7 +803,7 @@ fpga_core #(
// PTP configuration // PTP configuration
.PTP_TS_EN(PTP_TS_EN), .PTP_TS_EN(PTP_TS_EN),
.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 // PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W), .RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -766,7 +766,7 @@ fpga_core #(
// PTP configuration // PTP configuration
.PTP_TS_EN(PTP_TS_EN), .PTP_TS_EN(PTP_TS_EN),
.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 // PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W), .RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -748,7 +748,7 @@ fpga_core #(
// PTP configuration // PTP configuration
.PTP_TS_EN(PTP_TS_EN), .PTP_TS_EN(PTP_TS_EN),
.PTP_CLK_PER_NS_NUM(1024), .PTP_CLK_PER_NS_NUM(1024),
.PTP_CLK_PER_NS_DENOM(165), .PTP_CLK_PER_NS_DEN(165),
// PCIe interface configuration // PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W), .RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -737,7 +737,7 @@ fpga_core #(
// PTP configuration // PTP configuration
.PTP_TS_EN(PTP_TS_EN), .PTP_TS_EN(PTP_TS_EN),
.PTP_CLK_PER_NS_NUM(1024), .PTP_CLK_PER_NS_NUM(1024),
.PTP_CLK_PER_NS_DENOM(165), .PTP_CLK_PER_NS_DEN(165),
// PCIe interface configuration // PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W), .RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -754,7 +754,7 @@ fpga_core #(
// PTP configuration // PTP configuration
.PTP_TS_EN(PTP_TS_EN), .PTP_TS_EN(PTP_TS_EN),
.PTP_CLK_PER_NS_NUM(1024), .PTP_CLK_PER_NS_NUM(1024),
.PTP_CLK_PER_NS_DENOM(165), .PTP_CLK_PER_NS_DEN(165),
// PCIe interface configuration // PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W), .RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

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

View File

@@ -745,7 +745,7 @@ fpga_core #(
// PTP configuration // PTP configuration
.PTP_TS_EN(PTP_TS_EN), .PTP_TS_EN(PTP_TS_EN),
.PTP_CLK_PER_NS_NUM(1024), .PTP_CLK_PER_NS_NUM(1024),
.PTP_CLK_PER_NS_DENOM(165), .PTP_CLK_PER_NS_DEN(165),
// PCIe interface configuration // PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W), .RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

@@ -59,7 +59,7 @@ export PARAM_GTY_CLK_CNT := $(PARAM_GTY_QUAD_CNT)
# PTP configuration # PTP configuration
export PARAM_PTP_TS_EN := 1 export PARAM_PTP_TS_EN := 1
export PARAM_PTP_CLK_PER_NS_NUM := 32 export PARAM_PTP_CLK_PER_NS_NUM := 32
export PARAM_PTP_CLK_PER_NS_DENOM := 5 export PARAM_PTP_CLK_PER_NS_DEN := 5
# AXI lite interface configuration (control) # AXI lite interface configuration (control)
export PARAM_AXIL_CTRL_DATA_W := 32 export PARAM_AXIL_CTRL_DATA_W := 32

View File

@@ -9,6 +9,7 @@ Authors:
""" """
import itertools
import logging import logging
import os import os
import sys import sys
@@ -293,8 +294,7 @@ class TB:
self.qsfp_sources = [] self.qsfp_sources = []
self.qsfp_sinks = [] self.qsfp_sinks = []
for inst in dut.uut.gty_quad: for ch in itertools.chain.from_iterable([inst.mac_inst.ch for inst in dut.uut.gt_quad]):
for ch in inst.mac_inst.ch:
gt_inst = ch.ch_inst.gt.gt_inst gt_inst = ch.ch_inst.gt.gt_inst
if ch.ch_inst.DATA_W.value == 64: if ch.ch_inst.DATA_W.value == 64:
@@ -519,7 +519,7 @@ def test_fpga_core(request, mac_data_w):
# PTP configuration # PTP configuration
parameters['PTP_TS_EN'] = 1 parameters['PTP_TS_EN'] = 1
parameters['PTP_CLK_PER_NS_NUM'] = 32 parameters['PTP_CLK_PER_NS_NUM'] = 32
parameters['PTP_CLK_PER_NS_DENOM'] = 5 parameters['PTP_CLK_PER_NS_DEN'] = 5
# AXI lite interface configuration (control) # AXI lite interface configuration (control)
parameters['AXIL_CTRL_DATA_W'] = 32 parameters['AXIL_CTRL_DATA_W'] = 32

View File

@@ -45,7 +45,7 @@ module test_fpga_core #
// PTP configuration // PTP configuration
parameter logic PTP_TS_EN = 1'b1, parameter logic PTP_TS_EN = 1'b1,
parameter PTP_CLK_PER_NS_NUM = 32, parameter PTP_CLK_PER_NS_NUM = 32,
parameter PTP_CLK_PER_NS_DENOM = 5, parameter PTP_CLK_PER_NS_DEN = 5,
// PCIe interface configuration // PCIe interface configuration
parameter AXIS_PCIE_DATA_W = 512, parameter AXIS_PCIE_DATA_W = 512,
@@ -215,7 +215,7 @@ fpga_core #(
// PTP configuration // PTP configuration
.PTP_TS_EN(PTP_TS_EN), .PTP_TS_EN(PTP_TS_EN),
.PTP_CLK_PER_NS_NUM(PTP_CLK_PER_NS_NUM), .PTP_CLK_PER_NS_NUM(PTP_CLK_PER_NS_NUM),
.PTP_CLK_PER_NS_DENOM(PTP_CLK_PER_NS_DENOM), .PTP_CLK_PER_NS_DEN(PTP_CLK_PER_NS_DEN),
// PCIe interface configuration // PCIe interface configuration
.RQ_SEQ_NUM_W(RQ_SEQ_NUM_W), .RQ_SEQ_NUM_W(RQ_SEQ_NUM_W),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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