1
0
mirror of https://github.com/corundum/corundum.git synced 2025-01-16 08:12:53 +08:00

merged changes in axi

This commit is contained in:
Alex Forencich 2021-08-11 01:28:07 -07:00
commit 07292b7dda
21 changed files with 2895 additions and 637 deletions

View File

@ -30,4 +30,4 @@ jobs:
pip install tox tox-gh-actions
- name: Test with tox
run: tox -- --splits 10 --group ${{ matrix.group }}
run: tox -- --splits 10 --group ${{ matrix.group }} --splitting-algorithm least_duration

View File

@ -1,518 +1,518 @@
[
[
"tb/axi_axil_adapter/test_axi_axil_adapter.py::test_axi_axil_adapter[8-32]",
92.34029131208081
],
[
"tb/axi_axil_adapter/test_axi_axil_adapter.py::test_axi_axil_adapter[8-16]",
116.95964422891848
],
[
"tb/axi_axil_adapter/test_axi_axil_adapter.py::test_axi_axil_adapter[8-8]",
160.44773711299058
],
[
"tb/axi_axil_adapter/test_axi_axil_adapter.py::test_axi_axil_adapter[16-32]",
137.5760340038687
],
[
"tb/axi_adapter/test_axi_adapter.py::test_axi_adapter[8-16]",
74.270280775032
],
[
"tb/axi_axil_adapter/test_axi_axil_adapter.py::test_axi_axil_adapter[32-16]",
400.71982841100544
],
[
"tb/axi_cdma/test_axi_cdma.py::test_axi_dma[8-0]",
15.593242217088118
],
[
"tb/axi_adapter/test_axi_adapter.py::test_axi_adapter[8-32]",
72.42707156692632
],
[
"tb/axi_adapter/test_axi_adapter.py::test_axi_adapter[8-8]",
81.75273804098833
],
[
"tb/axi_cdma/test_axi_cdma.py::test_axi_dma[8-1]",
15.523522189934738
],
[
"tb/axi_axil_adapter/test_axi_axil_adapter.py::test_axi_axil_adapter[16-8]",
275.6350795699982
],
[
"tb/axi_axil_adapter/test_axi_axil_adapter.py::test_axi_axil_adapter[16-16]",
187.96441543195397
],
[
"tb/axi_axil_adapter/test_axi_axil_adapter.py::test_axi_axil_adapter[32-32]",
332.42191640788224
],
[
"tb/axi_adapter/test_axi_adapter.py::test_axi_adapter[32-8]",
299.3205338130938
],
[
"tb/axi_adapter/test_axi_adapter.py::test_axi_adapter[32-16]",
225.4822902668966
],
[
"tb/axi_adapter/test_axi_adapter.py::test_axi_adapter[16-8]",
153.9310424028663
],
[
"tb/axi_cdma/test_axi_cdma.py::test_axi_dma[16-0]",
11.925561288022436
],
[
"tb/axi_adapter/test_axi_adapter.py::test_axi_adapter[16-16]",
105.30798149493057
154.80171429924667
],
[
"tb/axi_adapter/test_axi_adapter.py::test_axi_adapter[16-32]",
90.9395789729897
129.46799642406404
],
[
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[1-1-16]",
62.324559034081176
"tb/axi_adapter/test_axi_adapter.py::test_axi_adapter[16-8]",
231.553730818443
],
[
"tb/axi_axil_adapter/test_axi_axil_adapter.py::test_axi_axil_adapter[32-8]",
593.6646482730284
],
[
"tb/axi_cdma/test_axi_cdma.py::test_axi_dma[16-1]",
49.035118295112625
],
[
"tb/axi_cdma/test_axi_cdma.py::test_axi_dma[32-0]",
13.027022278984077
],
[
"tb/axi_cdma/test_axi_cdma.py::test_axi_dma[32-1]",
206.7382632988738
],
[
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[4-1-8]",
203.24327663891017
],
[
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[1-4-8]",
212.6529240750242
],
[
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[4-1-16]",
173.30611170106567
],
[
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[4-1-32]",
165.20796160399914
],
[
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[1-1-8]",
82.1008072240511
"tb/axi_adapter/test_axi_adapter.py::test_axi_adapter[32-16]",
330.9125733766705
],
[
"tb/axi_adapter/test_axi_adapter.py::test_axi_adapter[32-32]",
186.82002451398876
248.16152153350413
],
[
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[1-4-16]",
168.1181099790847
"tb/axi_adapter/test_axi_adapter.py::test_axi_adapter[32-8]",
460.55696750525385
],
[
"tb/axi_adapter/test_axi_adapter.py::test_axi_adapter[8-16]",
61.18986997473985
],
[
"tb/axi_adapter/test_axi_adapter.py::test_axi_adapter[8-32]",
105.168587657623
],
[
"tb/axi_adapter/test_axi_adapter.py::test_axi_adapter[8-8]",
103.56085381656885
],
[
"tb/axi_axil_adapter/test_axi_axil_adapter.py::test_axi_axil_adapter[16-16]",
276.60084352083504
],
[
"tb/axi_axil_adapter/test_axi_axil_adapter.py::test_axi_axil_adapter[16-32]",
207.58588458877057
],
[
"tb/axi_axil_adapter/test_axi_axil_adapter.py::test_axi_axil_adapter[16-8]",
455.6177165629342
],
[
"tb/axi_axil_adapter/test_axi_axil_adapter.py::test_axi_axil_adapter[32-16]",
647.3827625270933
],
[
"tb/axi_axil_adapter/test_axi_axil_adapter.py::test_axi_axil_adapter[32-32]",
518.5061077158898
],
[
"tb/axi_axil_adapter/test_axi_axil_adapter.py::test_axi_axil_adapter[32-8]",
944.8823729595169
],
[
"tb/axi_axil_adapter/test_axi_axil_adapter.py::test_axi_axil_adapter[8-16]",
197.43744012899697
],
[
"tb/axi_axil_adapter/test_axi_axil_adapter.py::test_axi_axil_adapter[8-32]",
145.78048656322062
],
[
"tb/axi_axil_adapter/test_axi_axil_adapter.py::test_axi_axil_adapter[8-8]",
280.12128001917154
],
[
"tb/axi_cdma/test_axi_cdma.py::test_axi_dma[16-0]",
17.06440698262304
],
[
"tb/axi_cdma/test_axi_cdma.py::test_axi_dma[16-1]",
71.17776732705534
],
[
"tb/axi_cdma/test_axi_cdma.py::test_axi_dma[32-0]",
19.746693274006248
],
[
"tb/axi_cdma/test_axi_cdma.py::test_axi_dma[32-1]",
333.3781503010541
],
[
"tb/axi_cdma/test_axi_cdma.py::test_axi_dma[8-0]",
22.358843713067472
],
[
"tb/axi_cdma/test_axi_cdma.py::test_axi_dma[8-1]",
23.01292904186994
],
[
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[1-1-16]",
82.07929699122906
],
[
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[1-1-32]",
51.11953857005574
66.04357133992016
],
[
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[1-1-8]",
116.83163902442902
],
[
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[1-4-16]",
226.835347446613
],
[
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[1-4-32]",
167.10660719079897
221.82670008204877
],
[
"tb/axi_dma/test_axi_dma.py::test_axi_dma[0-8]",
38.593522747047246
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[1-4-8]",
278.4844740750268
],
[
"tb/axi_dma/test_axi_dma.py::test_axi_dma[0-16]",
26.12306741985958
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[4-1-16]",
147.22683315817267
],
[
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[4-1-32]",
166.78969807736576
],
[
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[4-1-8]",
278.06333569251
],
[
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[4-4-16]",
385.9775214729598
],
[
"tb/axi_dma_rd/test_axi_dma_rd.py::test_axi_dma_rd[16-0]",
2.330480069038458
],
[
"tb/axi_dma_wr/test_axi_dma_wr.py::test_axi_dma_wr[8-0]",
18.85620612394996
],
[
"tb/axi_dma/test_axi_dma.py::test_axi_dma[1-16]",
54.40660252713133
549.59216252435
],
[
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[4-4-32]",
421.9630580791272
455.38514183368534
],
[
"tb/axi_crossbar/test_axi_crossbar.py::test_axi_crossbar[4-4-8]",
404.845993772964
588.921606304124
],
[
"tb/axi_dma_wr/test_axi_dma_wr.py::test_axi_dma_wr[8-1]",
19.358775094966404
],
[
"tb/axi_dma_rd/test_axi_dma_rd.py::test_axi_dma_rd[8-1]",
3.2852856101235375
"tb/axi_dma/test_axi_dma.py::test_axi_dma[0-16]",
36.3299577338621
],
[
"tb/axi_dma/test_axi_dma.py::test_axi_dma[0-32]",
27.126582405064255
39.596242003142834
],
[
"tb/axi_dma_rd/test_axi_dma_rd.py::test_axi_dma_rd[8-0]",
3.397583018988371
"tb/axi_dma/test_axi_dma.py::test_axi_dma[0-8]",
54.620901849120855
],
[
"tb/axi_dma/test_axi_dma.py::test_axi_dma[1-8]",
39.06702446111012
"tb/axi_dma/test_axi_dma.py::test_axi_dma[1-16]",
70.15106952376664
],
[
"tb/axi_dma/test_axi_dma.py::test_axi_dma[1-32]",
109.1842717891559
157.4396074814722
],
[
"tb/axi_dma_rd/test_axi_dma_rd.py::test_axi_dma_rd[32-1]",
10.748354449984618
"tb/axi_dma/test_axi_dma.py::test_axi_dma[1-8]",
56.511911587789655
],
[
"tb/axi_dma_wr/test_axi_dma_wr.py::test_axi_dma_wr[16-0]",
14.207220426993445
],
[
"tb/axi_dma_rd/test_axi_dma_rd.py::test_axi_dma_rd[32-0]",
4.082128511974588
"tb/axi_dma_rd/test_axi_dma_rd.py::test_axi_dma_rd[16-0]",
3.7544524213299155
],
[
"tb/axi_dma_rd/test_axi_dma_rd.py::test_axi_dma_rd[16-1]",
4.67441277008038
7.172512795776129
],
[
"tb/axi_dma_rd/test_axi_dma_rd.py::test_axi_dma_rd[32-0]",
4.666332081891596
],
[
"tb/axi_dma_rd/test_axi_dma_rd.py::test_axi_dma_rd[32-1]",
23.44465008098632
],
[
"tb/axi_dma_rd/test_axi_dma_rd.py::test_axi_dma_rd[8-0]",
5.142332099378109
],
[
"tb/axi_dma_rd/test_axi_dma_rd.py::test_axi_dma_rd[8-1]",
6.475921370089054
],
[
"tb/axi_dma_wr/test_axi_dma_wr.py::test_axi_dma_wr[16-0]",
20.40422752313316
],
[
"tb/axi_dma_wr/test_axi_dma_wr.py::test_axi_dma_wr[16-1]",
26.38754628202878
],
[
"tb/axi_dp_ram/test_axi_dp_ram.py::test_axi_dp_ram[8]",
190.6977087969426
],
[
"tb/axi_dma_wr/test_axi_dma_wr.py::test_axi_dma_wr[32-1]",
61.13482341193594
],
[
"tb/axi_dp_ram/test_axi_dp_ram.py::test_axi_dp_ram[32]",
631.3725310519803
],
[
"tb/axi_fifo/test_axi_fifo.py::test_axi_fifo[16-1]",
116.16801285289694
46.69374061562121
],
[
"tb/axi_dma_wr/test_axi_dma_wr.py::test_axi_dma_wr[32-0]",
14.180392780923285
22.988098615780473
],
[
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[1-1-8]",
110.69283434608951
"tb/axi_dma_wr/test_axi_dma_wr.py::test_axi_dma_wr[32-1]",
89.21624889411032
],
[
"tb/axi_fifo/test_axi_fifo.py::test_axi_fifo[32-1]",
235.51755335007329
"tb/axi_dma_wr/test_axi_dma_wr.py::test_axi_dma_wr[8-0]",
29.688831198960543
],
[
"tb/axi_fifo/test_axi_fifo.py::test_axi_fifo[16-0]",
114.71273985889275
"tb/axi_dma_wr/test_axi_dma_wr.py::test_axi_dma_wr[8-1]",
27.773485894314945
],
[
"tb/axi_dp_ram/test_axi_dp_ram.py::test_axi_dp_ram[16]",
339.84432155790273
557.706888041459
],
[
"tb/axi_fifo/test_axi_fifo.py::test_axi_fifo[8-1]",
81.9772285890067
"tb/axi_dp_ram/test_axi_dp_ram.py::test_axi_dp_ram[32]",
875.9048622418195
],
[
"tb/axi_fifo/test_axi_fifo.py::test_axi_fifo[8-0]",
80.0548778581433
"tb/axi_dp_ram/test_axi_dp_ram.py::test_axi_dp_ram[8]",
293.5553059997037
],
[
"tb/axi_fifo/test_axi_fifo.py::test_axi_fifo[16-0]",
128.83496031537652
],
[
"tb/axi_fifo/test_axi_fifo.py::test_axi_fifo[16-1]",
173.11390095669776
],
[
"tb/axi_fifo/test_axi_fifo.py::test_axi_fifo[32-0]",
217.3123359469464
343.3222937248647
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[1-4-8]",
59.05071274796501
"tb/axi_fifo/test_axi_fifo.py::test_axi_fifo[32-1]",
350.7498745601624
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[1-1-32]",
10.958538840059191
"tb/axi_fifo/test_axi_fifo.py::test_axi_fifo[8-0]",
105.13950155116618
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[1-1-16]",
16.18374707410112
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[1-4-32]",
30.99582407809794
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[1-4-16]",
32.26239267003257
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[4-1-8]",
55.87296755902935
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[16-1]",
134.0978170959279
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[32-None]",
233.25326886295807
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[4-4-32]",
53.02282854996156
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[4-4-8]",
82.27994647994637
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[16-0]",
111.6125350688817
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[16-None]",
114.57908571104053
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[4-1-16]",
31.820328426081687
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[4-1-32]",
27.239373297896236
],
[
"tb/axil_cdc/test_axil_cdc.py::test_axil_cdc[32]",
18.885881599970162
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[4-4-16]",
47.431341870105825
],
[
"tb/axil_dp_ram/test_axil_dp_ram.py::test_axil_dp_ram[8]",
6.083705611992627
],
[
"tb/axil_cdc/test_axil_cdc.py::test_axil_cdc[16]",
23.918021908029914
],
[
"tb/axil_dp_ram/test_axil_dp_ram.py::test_axil_dp_ram[16]",
5.008629633928649
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[16-2]",
109.07862244499847
],
[
"tb/axil_adapter/test_axil_adapter.py::test_axil_adapter[8-8]",
11.255430878023617
],
[
"tb/axil_dp_ram/test_axil_dp_ram.py::test_axil_dp_ram[32]",
9.214697457035072
],
[
"tb/axil_ram/test_axil_ram.py::test_axil_ram[8]",
3.814734523068182
],
[
"tb/axil_register/test_axil_register.py::test_axil_register[32-2]",
3.088388371048495
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[32-2]",
210.00476461392827
],
[
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[1-4-8]",
232.57985687395558
],
[
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[1-1-32]",
54.11528235801961
],
[
"tb/axil_register/test_axil_register.py::test_axil_register[8-1]",
6.881038482999429
"tb/axi_fifo/test_axi_fifo.py::test_axi_fifo[8-1]",
121.01873329374939
],
[
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[1-1-16]",
67.14825033093803
102.19653648044914
],
[
"tb/axil_register/test_axil_register.py::test_axil_register[8-2]",
4.017322617932223
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[1-1-32]",
82.02585211675614
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[32-1]",
226.09505098406225
],
[
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[4-1-8]",
228.00826906599104
],
[
"tb/axi_ram/test_axi_ram.py::test_axi_ram[8]",
59.478687431896105
],
[
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[1-4-32]",
158.42456139600836
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[1-1-8]",
24.357805628911592
],
[
"tb/axil_register/test_axil_register.py::test_axil_register[32-1]",
3.4112419869052246
],
[
"tb/axil_register/test_axil_register.py::test_axil_register[16-0]",
2.5862843709765
],
[
"tb/axil_register/test_axil_register.py::test_axil_register[16-1]",
3.946968311909586
],
[
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[4-4-32]",
400.17059198615607
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[8-None]",
67.14530843799002
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[1-1-8]",
161.5555182993412
],
[
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[1-4-16]",
177.14258515485562
257.6017242670059
],
[
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[4-4-16]",
400.5200162229594
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[1-4-32]",
234.7367910388857
],
[
"tb/axil_adapter/test_axil_adapter.py::test_axil_adapter[32-8]",
11.39128352503758
],
[
"tb/axil_adapter/test_axil_adapter.py::test_axil_adapter[16-8]",
8.046741236932576
],
[
"tb/axil_adapter/test_axil_adapter.py::test_axil_adapter[8-32]",
9.869203691952862
],
[
"tb/axil_adapter/test_axil_adapter.py::test_axil_adapter[16-32]",
5.44320015097037
],
[
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[4-4-8]",
463.621744088945
],
[
"tb/axi_ram/test_axi_ram.py::test_axi_ram[32]",
169.53810201212764
],
[
"tb/axil_ram/test_axil_ram.py::test_axil_ram[16]",
2.378014532965608
],
[
"tb/axil_adapter/test_axil_adapter.py::test_axil_adapter[16-16]",
5.53720978286583
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[32-0]",
190.57033147790935
],
[
"tb/axil_adapter/test_axil_adapter.py::test_axil_adapter[8-16]",
9.342879572999664
],
[
"tb/axil_register/test_axil_register.py::test_axil_register[16-2]",
2.4198110720608383
],
[
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[4-1-32]",
152.4494464310119
],
[
"tb/axil_register/test_axil_register.py::test_axil_register[32-0]",
2.364597169100307
],
[
"tb/axi_ram/test_axi_ram.py::test_axi_ram[16]",
90.49995070195291
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[1-4-8]",
347.6929644905031
],
[
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[4-1-16]",
166.57522002898622
246.63431577198207
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[8-2]",
64.4880481789587
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[4-1-32]",
172.08718999754637
],
[
"tb/axil_ram/test_axil_ram.py::test_axil_ram[32]",
2.7770232169423252
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[4-1-8]",
321.3593363221735
],
[
"tb/axil_adapter/test_axil_adapter.py::test_axil_adapter[32-32]",
4.392885608016513
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[4-4-16]",
574.1888536829501
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[8-1]",
95.14355011994485
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[4-4-32]",
410.4118745010346
],
[
"tb/axil_adapter/test_axil_adapter.py::test_axil_adapter[32-16]",
6.293487015995197
"tb/axi_interconnect/test_axi_interconnect.py::test_axi_interconnect[4-4-8]",
735.5517066828907
],
[
"tb/axil_cdc/test_axil_cdc.py::test_axil_cdc[8]",
31.775441756122746
"tb/axi_ram/test_axi_ram.py::test_axi_ram[16]",
157.18584052287042
],
[
"tb/axi_ram/test_axi_ram.py::test_axi_ram[32]",
284.1904304390773
],
[
"tb/axi_ram/test_axi_ram.py::test_axi_ram[8]",
71.96863563451916
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[16-0]",
137.7420165129006
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[16-1]",
195.76706382073462
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[16-2]",
165.80640455987304
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[16-None]",
161.71680294163525
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[32-0]",
312.6301383897662
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[32-1]",
363.7704292088747
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[32-2]",
327.6335842087865
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[32-None]",
342.006927145645
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[8-0]",
63.281225918093696
102.75957749877125
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[8-1]",
150.65885178279132
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[8-2]",
116.52124607004225
],
[
"tb/axi_register/test_axi_register.py::test_axi_register[8-None]",
112.02143712155521
],
[
"tb/axil_adapter/test_axil_adapter.py::test_axil_adapter[16-16]",
9.414873909205198
],
[
"tb/axil_adapter/test_axil_adapter.py::test_axil_adapter[16-32]",
10.720249651931226
],
[
"tb/axil_adapter/test_axil_adapter.py::test_axil_adapter[16-8]",
15.94476203713566
],
[
"tb/axil_adapter/test_axil_adapter.py::test_axil_adapter[32-16]",
10.456397350877523
],
[
"tb/axil_adapter/test_axil_adapter.py::test_axil_adapter[32-32]",
9.175778770819306
],
[
"tb/axil_adapter/test_axil_adapter.py::test_axil_adapter[32-8]",
20.37657857965678
],
[
"tb/axil_adapter/test_axil_adapter.py::test_axil_adapter[8-16]",
18.28249195497483
],
[
"tb/axil_adapter/test_axil_adapter.py::test_axil_adapter[8-32]",
18.1448409659788
],
[
"tb/axil_adapter/test_axil_adapter.py::test_axil_adapter[8-8]",
18.509287000633776
],
[
"tb/axil_cdc/test_axil_cdc.py::test_axil_cdc[16]",
32.789682413451374
],
[
"tb/axil_cdc/test_axil_cdc.py::test_axil_cdc[32]",
27.674326405860484
],
[
"tb/axil_cdc/test_axil_cdc.py::test_axil_cdc[8]",
58.896160850301385
],
[
"tb/axil_dp_ram/test_axil_dp_ram.py::test_axil_dp_ram[16]",
8.325086586177349
],
[
"tb/axil_dp_ram/test_axil_dp_ram.py::test_axil_dp_ram[32]",
14.020466917194426
],
[
"tb/axil_dp_ram/test_axil_dp_ram.py::test_axil_dp_ram[8]",
9.97084455192089
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[1-1-16]",
23.2663188977167
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[1-1-32]",
23.612671780399978
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[1-1-8]",
42.97799370903522
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[1-4-16]",
44.34295728802681
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[1-4-32]",
35.623706634156406
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[1-4-8]",
81.04713163338602
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[4-1-16]",
43.093923680484295
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[4-1-32]",
34.437351221218705
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[4-1-8]",
73.75804248824716
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[4-4-16]",
64.2899643778801
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[4-4-32]",
67.7834402685985
],
[
"tb/axil_interconnect/test_axil_interconnect.py::test_axil_interconnect[4-4-8]",
87.84026487357914
],
[
"tb/axil_ram/test_axil_ram.py::test_axil_ram[16]",
4.694024303928018
],
[
"tb/axil_ram/test_axil_ram.py::test_axil_ram[32]",
5.4611031180247664
],
[
"tb/axil_ram/test_axil_ram.py::test_axil_ram[8]",
7.07833203766495
],
[
"tb/axil_register/test_axil_register.py::test_axil_register[16-0]",
4.518617523834109
],
[
"tb/axil_register/test_axil_register.py::test_axil_register[16-1]",
6.114853054285049
],
[
"tb/axil_register/test_axil_register.py::test_axil_register[16-2]",
4.118833149783313
],
[
"tb/axil_register/test_axil_register.py::test_axil_register[32-0]",
4.708139616064727
],
[
"tb/axil_register/test_axil_register.py::test_axil_register[32-1]",
5.979810021817684
],
[
"tb/axil_register/test_axil_register.py::test_axil_register[32-2]",
5.279176370240748
],
[
"tb/axil_register/test_axil_register.py::test_axil_register[8-0]",
3.50379631400574
6.333443800918758
],
[
"tb/axil_register/test_axil_register.py::test_axil_register[8-1]",
10.641177451238036
],
[
"tb/axil_register/test_axil_register.py::test_axil_register[8-2]",
7.088530145585537
]
]

View File

@ -62,8 +62,8 @@ distributing responses.
AXI nonblocking crossbar interconnect with parametrizable data and address
interface widths and master and slave interface counts. Supports all burst
types. Fully nonblocking with completely separate read and write paths; ID
based transaction ordering protection logic; and per-port address decode,
types. Fully nonblocking with completely separate read and write paths;
ID-based transaction ordering protection logic; and per-port address decode,
admission control, and decode error handling. Wrapper for `axi_crossbar_rd`
and `axi_crossbar_wr`.
@ -78,7 +78,7 @@ Address decode and admission control module for AXI nonblocking crossbar interco
AXI nonblocking crossbar interconnect with parametrizable data and address
interface widths and master and slave interface counts. Read interface only.
Supports all burst types. Fully nonblocking with completely separate read and
write paths; ID based transaction ordering protection logic; and per-port
write paths; ID-based transaction ordering protection logic; and per-port
address decode, admission control, and decode error handling.
### `axi_crossbar_wr` module
@ -86,7 +86,7 @@ address decode, admission control, and decode error handling.
AXI nonblocking crossbar interconnect with parametrizable data and address
interface widths and master and slave interface counts. Write interface only.
Supports all burst types. Fully nonblocking with completely separate read and
write paths; ID based transaction ordering protection logic; and per-port
write paths; ID-based transaction ordering protection logic; and per-port
address decode, admission control, and decode error handling.
### `axi_dma` module
@ -226,6 +226,36 @@ interface widths.
AXI lite clock domain crossing module with parametrizable data and address
interface widths.
### `axil_crossbar` module
AXI lite nonblocking crossbar interconnect with parametrizable data and address
interface widths and master and slave interface counts. Fully nonblocking
with completely separate read and write paths; FIFO-based transaction ordering
protection logic; and per-port address decode, admission control, and decode
error handling. Wrapper for `axil_crossbar_rd` and `axil_crossbar_wr`.
Wrappers can generated with `axil_crossbar_wrap.py`.
### `axil_crossbar_addr` module
Address decode and admission control module for AXI lite nonblocking crossbar interconnect.
### `axil_crossbar_rd` module
AXI lite nonblocking crossbar interconnect with parametrizable data and address
interface widths and master and slave interface counts. Read interface only.
Fully nonblocking with completely separate read and write paths; FIFO-based
transaction ordering protection logic; and per-port address decode, admission
control, and decode error handling.
### `axil_crossbar_wr` module
AXI lite nonblocking crossbar interconnect with parametrizable data and address
interface widths and master and slave interface counts. Write interface only.
Fully nonblocking with completely separate read and write paths; FIFO-based
transaction ordering protection logic; and per-port address decode, admission
control, and decode error handling.
### `axil_interconnect` module
AXI lite shared interconnect with parametrizable data and address interface
@ -333,8 +363,8 @@ registers can be individually bypassed.
rtl/axi_cdma_desc_mux.v : AXI CDMA descriptor mux
rtl/axi_crossbar.v : AXI nonblocking crossbar interconnect
rtl/axi_crossbar_addr.v : AXI crossbar address module
rtl/axi_crossbar_rd.v : AXI crossbar read module
rtl/axi_crossbar_wr.v : AXI crossbar write module
rtl/axi_crossbar_rd.v : AXI crossbar interconnect (read)
rtl/axi_crossbar_wr.v : AXI crossbar interconnect (write)
rtl/axi_dma.v : AXI DMA engine
rtl/axi_dma_desc_mux.v : AXI DMA descriptor mux
rtl/axi_dma_rd.v : AXI DMA engine (read)
@ -357,6 +387,10 @@ registers can be individually bypassed.
rtl/axil_cdc.v : AXI lite CDC
rtl/axil_cdc_rd.v : AXI lite CDC (read)
rtl/axil_cdc_wr.v : AXI lite CDC (write)
rtl/axil_crossbar.v : AXI lite nonblocking crossbar interconnect
rtl/axil_crossbar_addr.v : AXI lite crossbar address module
rtl/axil_crossbar_rd.v : AXI lite crossbar interconnect (read)
rtl/axil_crossbar_wr.v : AXI lite crossbar interconnect (write)
rtl/axil_interconnect.v : AXI lite shared interconnect
rtl/axil_ram.v : AXI lite RAM
rtl/axil_register.v : AXI lite register

View File

@ -66,6 +66,7 @@ module axi_cdma #
* AXI descriptor status output
*/
output wire [TAG_WIDTH-1:0] m_axis_desc_status_tag,
output wire [3:0] m_axis_desc_status_error,
output wire m_axis_desc_status_valid,
/*
@ -128,6 +129,7 @@ parameter ADDR_MASK = {AXI_ADDR_WIDTH{1'b1}} << $clog2(AXI_STRB_WIDTH);
parameter CYCLE_COUNT_WIDTH = LEN_WIDTH - AXI_BURST_SIZE + 1;
parameter STATUS_FIFO_ADDR_WIDTH = 5;
parameter OUTPUT_FIFO_ADDR_WIDTH = 5;
// bus width assertions
initial begin
@ -147,6 +149,25 @@ initial begin
end
end
localparam [1:0]
AXI_RESP_OKAY = 2'b00,
AXI_RESP_EXOKAY = 2'b01,
AXI_RESP_SLVERR = 2'b10,
AXI_RESP_DECERR = 2'b11;
localparam [3:0]
DMA_ERROR_NONE = 4'd0,
DMA_ERROR_TIMEOUT = 4'd1,
DMA_ERROR_PARITY = 4'd2,
DMA_ERROR_AXI_RD_SLVERR = 4'd4,
DMA_ERROR_AXI_RD_DECERR = 4'd5,
DMA_ERROR_AXI_WR_SLVERR = 4'd6,
DMA_ERROR_AXI_WR_DECERR = 4'd7,
DMA_ERROR_PCIE_FLR = 4'd8,
DMA_ERROR_PCIE_CPL_POISONED = 4'd9,
DMA_ERROR_PCIE_CPL_STATUS_UR = 4'd10,
DMA_ERROR_PCIE_CPL_STATUS_CA = 4'd11;
localparam [1:0]
READ_STATE_IDLE = 2'd0,
READ_STATE_START = 2'd1,
@ -194,14 +215,18 @@ reg first_input_cycle_reg = 1'b0, first_input_cycle_next;
reg first_output_cycle_reg = 1'b0, first_output_cycle_next;
reg output_last_cycle_reg = 1'b0, output_last_cycle_next;
reg last_transfer_reg = 1'b0, last_transfer_next;
reg [1:0] rresp_reg = AXI_RESP_OKAY, rresp_next;
reg [1:0] bresp_reg = AXI_RESP_OKAY, bresp_next;
reg [TAG_WIDTH-1:0] tag_reg = {TAG_WIDTH{1'b0}}, tag_next;
reg [STATUS_FIFO_ADDR_WIDTH+1-1:0] status_fifo_wr_ptr_reg = 0;
reg [STATUS_FIFO_ADDR_WIDTH+1-1:0] status_fifo_rd_ptr_reg = 0, status_fifo_rd_ptr_next;
reg [TAG_WIDTH-1:0] status_fifo_tag[(2**STATUS_FIFO_ADDR_WIDTH)-1:0];
reg [1:0] status_fifo_resp[(2**STATUS_FIFO_ADDR_WIDTH)-1:0];
reg status_fifo_last[(2**STATUS_FIFO_ADDR_WIDTH)-1:0];
reg [TAG_WIDTH-1:0] status_fifo_wr_tag;
reg [1:0] status_fifo_wr_resp;
reg status_fifo_wr_last;
reg [STATUS_FIFO_ADDR_WIDTH+1-1:0] active_count_reg = 0;
@ -212,6 +237,7 @@ reg dec_active;
reg s_axis_desc_ready_reg = 1'b0, s_axis_desc_ready_next;
reg [TAG_WIDTH-1:0] m_axis_desc_status_tag_reg = {TAG_WIDTH{1'b0}}, m_axis_desc_status_tag_next;
reg [3:0] m_axis_desc_status_error_reg = 4'd0, m_axis_desc_status_error_next;
reg m_axis_desc_status_valid_reg = 1'b0, m_axis_desc_status_valid_next;
reg [AXI_ADDR_WIDTH-1:0] m_axi_araddr_reg = {AXI_ADDR_WIDTH{1'b0}}, m_axi_araddr_next;
@ -233,12 +259,12 @@ reg [AXI_DATA_WIDTH-1:0] m_axi_wdata_int;
reg [AXI_STRB_WIDTH-1:0] m_axi_wstrb_int;
reg m_axi_wlast_int;
reg m_axi_wvalid_int;
reg m_axi_wready_int_reg = 1'b0;
wire m_axi_wready_int_early;
wire m_axi_wready_int;
assign s_axis_desc_ready = s_axis_desc_ready_reg;
assign m_axis_desc_status_tag = m_axis_desc_status_tag_reg;
assign m_axis_desc_status_error = m_axis_desc_status_error_reg;
assign m_axis_desc_status_valid = m_axis_desc_status_valid_reg;
assign m_axi_arid = {AXI_ID_WIDTH{1'b0}};
@ -418,6 +444,7 @@ always @* begin
axi_state_next = AXI_STATE_IDLE;
m_axis_desc_status_tag_next = m_axis_desc_status_tag_reg;
m_axis_desc_status_error_next = m_axis_desc_status_error_reg;
m_axis_desc_status_valid_next = 1'b0;
m_axi_awaddr_next = m_axi_awaddr_reg;
@ -454,7 +481,20 @@ always @* begin
dec_active = 1'b0;
if (m_axi_rready && m_axi_rvalid && (m_axi_rresp == AXI_RESP_SLVERR || m_axi_rresp == AXI_RESP_DECERR)) begin
rresp_next = m_axi_rresp;
end else begin
rresp_next = rresp_reg;
end
if (m_axi_bready && m_axi_bvalid && (m_axi_bresp == AXI_RESP_SLVERR || m_axi_bresp == AXI_RESP_DECERR)) begin
bresp_next = m_axi_bresp;
end else begin
bresp_next = bresp_reg;
end
status_fifo_wr_tag = tag_reg;
status_fifo_wr_resp = rresp_next;
status_fifo_wr_last = 1'b0;
case (axi_state_reg)
@ -490,15 +530,15 @@ always @* begin
m_axi_awlen_next = axi_cmd_output_cycle_count_reg;
m_axi_awvalid_next = 1'b1;
m_axi_rready_next = m_axi_wready_int_early;
m_axi_rready_next = m_axi_wready_int;
axi_state_next = AXI_STATE_WRITE;
end
end
AXI_STATE_WRITE: begin
// handle AXI read data
m_axi_rready_next = m_axi_wready_int_early && input_active_reg;
m_axi_rready_next = m_axi_wready_int && input_active_reg;
if (m_axi_wready_int_reg && ((m_axi_rready && m_axi_rvalid) || !input_active_reg)) begin
if ((m_axi_rready && m_axi_rvalid) || !input_active_reg) begin
// transfer in AXI read data
transfer_in_save = m_axi_rready && m_axi_rvalid;
@ -510,7 +550,7 @@ always @* begin
bubble_cycle_next = 1'b0;
first_input_cycle_next = 1'b0;
m_axi_rready_next = m_axi_wready_int_early && input_active_next;
m_axi_rready_next = m_axi_wready_int && input_active_next;
axi_state_next = AXI_STATE_WRITE;
end else begin
// update counters
@ -545,8 +585,13 @@ always @* begin
status_fifo_we = 1'b1;
status_fifo_wr_tag = tag_reg;
status_fifo_wr_resp = rresp_next;
status_fifo_wr_last = last_transfer_reg;
if (last_transfer_reg) begin
rresp_next = AXI_RESP_OKAY;
end
m_axi_rready_next = 1'b0;
axi_state_next = AXI_STATE_IDLE;
end else begin
@ -565,10 +610,25 @@ always @* begin
if (m_axi_bready && m_axi_bvalid) begin
// got write completion, pop and return status
m_axis_desc_status_tag_next = status_fifo_tag[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]];
if (status_fifo_resp[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]] == AXI_RESP_SLVERR) begin
m_axis_desc_status_error_next = DMA_ERROR_AXI_RD_SLVERR;
end else if (status_fifo_resp[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]] == AXI_RESP_DECERR) begin
m_axis_desc_status_error_next = DMA_ERROR_AXI_RD_DECERR;
end else if (bresp_next == AXI_RESP_SLVERR) begin
m_axis_desc_status_error_next = DMA_ERROR_AXI_WR_SLVERR;
end else if (bresp_next == AXI_RESP_DECERR) begin
m_axis_desc_status_error_next = DMA_ERROR_AXI_WR_DECERR;
end else begin
m_axis_desc_status_error_next = DMA_ERROR_NONE;
end
m_axis_desc_status_valid_next = status_fifo_last[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]];
status_fifo_rd_ptr_next = status_fifo_rd_ptr_reg + 1;
m_axi_bready_next = 1'b0;
if (status_fifo_last[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]]) begin
bresp_next = AXI_RESP_OKAY;
end
dec_active = 1'b1;
end else begin
// wait for write completion
@ -584,6 +644,7 @@ always @(posedge clk) begin
s_axis_desc_ready_reg <= s_axis_desc_ready_next;
m_axis_desc_status_tag_reg <= m_axis_desc_status_tag_next;
m_axis_desc_status_error_reg <= m_axis_desc_status_error_next;
m_axis_desc_status_valid_reg <= m_axis_desc_status_valid_next;
m_axi_awaddr_reg <= m_axi_awaddr_next;
@ -624,6 +685,8 @@ always @(posedge clk) begin
first_output_cycle_reg <= first_output_cycle_next;
output_last_cycle_reg <= output_last_cycle_next;
last_transfer_reg <= last_transfer_next;
rresp_reg <= rresp_next;
bresp_reg <= bresp_next;
tag_reg <= tag_next;
@ -633,6 +696,7 @@ always @(posedge clk) begin
if (status_fifo_we) begin
status_fifo_tag[status_fifo_wr_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]] <= status_fifo_wr_tag;
status_fifo_resp[status_fifo_wr_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]] <= status_fifo_wr_resp;
status_fifo_last[status_fifo_wr_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]] <= status_fifo_wr_last;
status_fifo_wr_ptr_reg <= status_fifo_wr_ptr_reg + 1;
end
@ -652,8 +716,6 @@ always @(posedge clk) begin
read_state_reg <= READ_STATE_IDLE;
axi_state_reg <= AXI_STATE_IDLE;
axi_cmd_valid_reg <= 1'b0;
s_axis_desc_ready_reg <= 1'b0;
m_axis_desc_status_valid_reg <= 1'b0;
@ -662,6 +724,11 @@ always @(posedge clk) begin
m_axi_arvalid_reg <= 1'b0;
m_axi_rready_reg <= 1'b0;
axi_cmd_valid_reg <= 1'b0;
rresp_reg <= AXI_RESP_OKAY;
bresp_reg <= AXI_RESP_OKAY;
status_fifo_wr_ptr_reg <= 0;
status_fifo_rd_ptr_reg <= 0;
@ -674,80 +741,53 @@ end
reg [AXI_DATA_WIDTH-1:0] m_axi_wdata_reg = {AXI_DATA_WIDTH{1'b0}};
reg [AXI_STRB_WIDTH-1:0] m_axi_wstrb_reg = {AXI_STRB_WIDTH{1'b0}};
reg m_axi_wlast_reg = 1'b0;
reg m_axi_wvalid_reg = 1'b0, m_axi_wvalid_next;
reg m_axi_wvalid_reg = 1'b0;
reg [AXI_DATA_WIDTH-1:0] temp_m_axi_wdata_reg = {AXI_DATA_WIDTH{1'b0}};
reg [AXI_STRB_WIDTH-1:0] temp_m_axi_wstrb_reg = {AXI_STRB_WIDTH{1'b0}};
reg temp_m_axi_wlast_reg = 1'b0;
reg temp_m_axi_wvalid_reg = 1'b0, temp_m_axi_wvalid_next;
reg [OUTPUT_FIFO_ADDR_WIDTH+1-1:0] out_fifo_wr_ptr_reg = 0;
reg [OUTPUT_FIFO_ADDR_WIDTH+1-1:0] out_fifo_rd_ptr_reg = 0;
reg out_fifo_half_full_reg = 1'b0;
// datapath control
reg store_axi_w_int_to_output;
reg store_axi_w_int_to_temp;
reg store_axi_w_temp_to_output;
wire out_fifo_full = out_fifo_wr_ptr_reg == (out_fifo_rd_ptr_reg ^ {1'b1, {OUTPUT_FIFO_ADDR_WIDTH{1'b0}}});
wire out_fifo_empty = out_fifo_wr_ptr_reg == out_fifo_rd_ptr_reg;
(* ram_style = "distributed" *)
reg [AXI_DATA_WIDTH-1:0] out_fifo_wdata[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
(* ram_style = "distributed" *)
reg [AXI_STRB_WIDTH-1:0] out_fifo_wstrb[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
(* ram_style = "distributed" *)
reg out_fifo_wlast[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
assign m_axi_wready_int = !out_fifo_half_full_reg;
assign m_axi_wdata = m_axi_wdata_reg;
assign m_axi_wstrb = m_axi_wstrb_reg;
assign m_axi_wvalid = m_axi_wvalid_reg;
assign m_axi_wlast = m_axi_wlast_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_axi_wready_int_early = m_axi_wready || (!temp_m_axi_wvalid_reg && (!m_axi_wvalid_reg || !m_axi_wvalid_int));
always @* begin
// transfer sink ready state to source
m_axi_wvalid_next = m_axi_wvalid_reg;
temp_m_axi_wvalid_next = temp_m_axi_wvalid_reg;
store_axi_w_int_to_output = 1'b0;
store_axi_w_int_to_temp = 1'b0;
store_axi_w_temp_to_output = 1'b0;
if (m_axi_wready_int_reg) begin
// input is ready
if (m_axi_wready || !m_axi_wvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_axi_wvalid_next = m_axi_wvalid_int;
store_axi_w_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axi_wvalid_next = m_axi_wvalid_int;
store_axi_w_int_to_temp = 1'b1;
end
end else if (m_axi_wready) begin
// input is not ready, but output is ready
m_axi_wvalid_next = temp_m_axi_wvalid_reg;
temp_m_axi_wvalid_next = 1'b0;
store_axi_w_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
m_axi_wvalid_reg <= m_axi_wvalid_reg && !m_axi_wready;
out_fifo_half_full_reg <= $unsigned(out_fifo_wr_ptr_reg - out_fifo_rd_ptr_reg) >= 2**(OUTPUT_FIFO_ADDR_WIDTH-1);
if (!out_fifo_full && m_axi_wvalid_int) begin
out_fifo_wdata[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axi_wdata_int;
out_fifo_wstrb[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axi_wstrb_int;
out_fifo_wlast[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axi_wlast_int;
out_fifo_wr_ptr_reg <= out_fifo_wr_ptr_reg + 1;
end
if (!out_fifo_empty && (!m_axi_wvalid_reg || m_axi_wready)) begin
m_axi_wdata_reg <= out_fifo_wdata[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
m_axi_wstrb_reg <= out_fifo_wstrb[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
m_axi_wlast_reg <= out_fifo_wlast[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
m_axi_wvalid_reg <= 1'b1;
out_fifo_rd_ptr_reg <= out_fifo_rd_ptr_reg + 1;
end
if (rst) begin
out_fifo_wr_ptr_reg <= 0;
out_fifo_rd_ptr_reg <= 0;
m_axi_wvalid_reg <= 1'b0;
m_axi_wready_int_reg <= 1'b0;
temp_m_axi_wvalid_reg <= 1'b0;
end else begin
m_axi_wvalid_reg <= m_axi_wvalid_next;
m_axi_wready_int_reg <= m_axi_wready_int_early;
temp_m_axi_wvalid_reg <= temp_m_axi_wvalid_next;
end
// datapath
if (store_axi_w_int_to_output) begin
m_axi_wdata_reg <= m_axi_wdata_int;
m_axi_wstrb_reg <= m_axi_wstrb_int;
m_axi_wlast_reg <= m_axi_wlast_int;
end else if (store_axi_w_temp_to_output) begin
m_axi_wdata_reg <= temp_m_axi_wdata_reg;
m_axi_wstrb_reg <= temp_m_axi_wstrb_reg;
m_axi_wlast_reg <= temp_m_axi_wlast_reg;
end
if (store_axi_w_int_to_temp) begin
temp_m_axi_wdata_reg <= m_axi_wdata_int;
temp_m_axi_wstrb_reg <= m_axi_wstrb_int;
temp_m_axi_wlast_reg <= m_axi_wlast_int;
end
end

View File

@ -65,6 +65,7 @@ module axi_cdma_desc_mux #
* Descriptor status input (from AXI CDMA core)
*/
input wire [M_TAG_WIDTH-1:0] s_axis_desc_status_tag,
input wire [3:0] s_axis_desc_status_error,
input wire s_axis_desc_status_valid,
/*
@ -81,6 +82,7 @@ module axi_cdma_desc_mux #
* Descriptor status output
*/
output wire [PORTS*S_TAG_WIDTH-1:0] m_axis_desc_status_tag,
output wire [PORTS*4-1:0] m_axis_desc_status_error,
output wire [PORTS-1:0] m_axis_desc_status_valid
);
@ -238,9 +240,11 @@ end
// descriptor status demux
reg [S_TAG_WIDTH-1:0] m_axis_desc_status_tag_reg = {S_TAG_WIDTH{1'b0}};
reg [3:0] m_axis_desc_status_error_reg = 4'd0;
reg [PORTS-1:0] m_axis_desc_status_valid_reg = {PORTS{1'b0}};
assign m_axis_desc_status_tag = {PORTS{m_axis_desc_status_tag_reg}};
assign m_axis_desc_status_error = {PORTS{m_axis_desc_status_error_reg}};
assign m_axis_desc_status_valid = m_axis_desc_status_valid_reg;
always @(posedge clk) begin
@ -251,6 +255,7 @@ always @(posedge clk) begin
end
m_axis_desc_status_tag_reg <= s_axis_desc_status_tag;
m_axis_desc_status_error_reg <= s_axis_desc_status_error;
end
endmodule

View File

@ -279,7 +279,6 @@ always @* begin
m_axi_aregion_next = m_axi_aregion_reg;
m_select_next = m_select_reg;
m_select_next = m_select_reg;
m_axi_avalid_next = m_axi_avalid_reg && !m_axi_aready;
m_decerr_next = m_decerr_reg;
m_wc_valid_next = m_wc_valid_reg && !m_wc_ready;

View File

@ -91,6 +91,7 @@ module axi_dma #
* AXI read descriptor status output
*/
output wire [TAG_WIDTH-1:0] m_axis_read_desc_status_tag,
output wire [3:0] m_axis_read_desc_status_error,
output wire m_axis_read_desc_status_valid,
/*
@ -122,6 +123,7 @@ module axi_dma #
output wire [AXIS_ID_WIDTH-1:0] m_axis_write_desc_status_id,
output wire [AXIS_DEST_WIDTH-1:0] m_axis_write_desc_status_dest,
output wire [AXIS_USER_WIDTH-1:0] m_axis_write_desc_status_user,
output wire [3:0] m_axis_write_desc_status_error,
output wire m_axis_write_desc_status_valid,
/*
@ -224,6 +226,7 @@ axi_dma_rd_inst (
* AXI read descriptor status output
*/
.m_axis_read_desc_status_tag(m_axis_read_desc_status_tag),
.m_axis_read_desc_status_error(m_axis_read_desc_status_error),
.m_axis_read_desc_status_valid(m_axis_read_desc_status_valid),
/*
@ -306,6 +309,7 @@ axi_dma_wr_inst (
.m_axis_write_desc_status_id(m_axis_write_desc_status_id),
.m_axis_write_desc_status_dest(m_axis_write_desc_status_dest),
.m_axis_write_desc_status_user(m_axis_write_desc_status_user),
.m_axis_write_desc_status_error(m_axis_write_desc_status_error),
.m_axis_write_desc_status_valid(m_axis_write_desc_status_valid),
/*

View File

@ -83,6 +83,7 @@ module axi_dma_desc_mux #
input wire [AXIS_ID_WIDTH-1:0] s_axis_desc_status_id,
input wire [AXIS_DEST_WIDTH-1:0] s_axis_desc_status_dest,
input wire [AXIS_USER_WIDTH-1:0] s_axis_desc_status_user,
input wire [3:0] s_axis_desc_status_error,
input wire s_axis_desc_status_valid,
/*
@ -105,6 +106,7 @@ module axi_dma_desc_mux #
output wire [PORTS*AXIS_ID_WIDTH-1:0] m_axis_desc_status_id,
output wire [PORTS*AXIS_DEST_WIDTH-1:0] m_axis_desc_status_dest,
output wire [PORTS*AXIS_USER_WIDTH-1:0] m_axis_desc_status_user,
output wire [PORTS*4-1:0] m_axis_desc_status_error,
output wire [PORTS-1:0] m_axis_desc_status_valid
);
@ -284,6 +286,7 @@ reg [S_TAG_WIDTH-1:0] m_axis_desc_status_tag_reg = {S_TAG_WIDTH{1'b0}};
reg [AXIS_ID_WIDTH-1:0] m_axis_desc_status_id_reg = {AXIS_ID_WIDTH{1'b0}};
reg [AXIS_DEST_WIDTH-1:0] m_axis_desc_status_dest_reg = {AXIS_DEST_WIDTH{1'b0}};
reg [AXIS_USER_WIDTH-1:0] m_axis_desc_status_user_reg = {AXIS_USER_WIDTH{1'b0}};
reg [3:0] m_axis_desc_status_error_reg = 4'd0;
reg [PORTS-1:0] m_axis_desc_status_valid_reg = {PORTS{1'b0}};
assign m_axis_desc_status_len = {PORTS{m_axis_desc_status_len_reg}};
@ -291,6 +294,7 @@ assign m_axis_desc_status_tag = {PORTS{m_axis_desc_status_tag_reg}};
assign m_axis_desc_status_id = AXIS_ID_ENABLE ? {PORTS{m_axis_desc_status_id_reg}} : {AXIS_ID_WIDTH*PORTS{1'b0}};
assign m_axis_desc_status_dest = AXIS_DEST_ENABLE ? {PORTS{m_axis_desc_status_dest_reg}} : {AXIS_DEST_WIDTH*PORTS{1'b0}};
assign m_axis_desc_status_user = AXIS_USER_ENABLE ? {PORTS{m_axis_desc_status_user_reg}} : {AXIS_USER_WIDTH*PORTS{1'b0}};
assign m_axis_desc_status_error = {PORTS{m_axis_desc_status_error_reg}};
assign m_axis_desc_status_valid = m_axis_desc_status_valid_reg;
always @(posedge clk) begin
@ -305,6 +309,7 @@ always @(posedge clk) begin
m_axis_desc_status_id_reg <= s_axis_desc_status_id;
m_axis_desc_status_dest_reg <= s_axis_desc_status_dest;
m_axis_desc_status_user_reg <= s_axis_desc_status_user;
m_axis_desc_status_error_reg <= s_axis_desc_status_error;
end
endmodule

View File

@ -91,6 +91,7 @@ module axi_dma_rd #
* AXI read descriptor status output
*/
output wire [TAG_WIDTH-1:0] m_axis_read_desc_status_tag,
output wire [3:0] m_axis_read_desc_status_error,
output wire m_axis_read_desc_status_valid,
/*
@ -145,6 +146,8 @@ parameter OFFSET_MASK = AXI_STRB_WIDTH > 1 ? {OFFSET_WIDTH{1'b1}} : 0;
parameter ADDR_MASK = {AXI_ADDR_WIDTH{1'b1}} << $clog2(AXI_STRB_WIDTH);
parameter CYCLE_COUNT_WIDTH = LEN_WIDTH - AXI_BURST_SIZE + 1;
parameter OUTPUT_FIFO_ADDR_WIDTH = 5;
// bus width assertions
initial begin
if (AXI_WORD_SIZE * AXI_STRB_WIDTH != AXI_DATA_WIDTH) begin
@ -183,6 +186,25 @@ initial begin
end
end
localparam [1:0]
AXI_RESP_OKAY = 2'b00,
AXI_RESP_EXOKAY = 2'b01,
AXI_RESP_SLVERR = 2'b10,
AXI_RESP_DECERR = 2'b11;
localparam [3:0]
DMA_ERROR_NONE = 4'd0,
DMA_ERROR_TIMEOUT = 4'd1,
DMA_ERROR_PARITY = 4'd2,
DMA_ERROR_AXI_RD_SLVERR = 4'd4,
DMA_ERROR_AXI_RD_DECERR = 4'd5,
DMA_ERROR_AXI_WR_SLVERR = 4'd6,
DMA_ERROR_AXI_WR_DECERR = 4'd7,
DMA_ERROR_PCIE_FLR = 4'd8,
DMA_ERROR_PCIE_CPL_POISONED = 4'd9,
DMA_ERROR_PCIE_CPL_STATUS_UR = 4'd10,
DMA_ERROR_PCIE_CPL_STATUS_CA = 4'd11;
localparam [0:0]
AXI_STATE_IDLE = 1'd0,
AXI_STATE_START = 1'd1;
@ -223,6 +245,7 @@ reg output_active_reg = 1'b0, output_active_next;
reg bubble_cycle_reg = 1'b0, bubble_cycle_next;
reg first_cycle_reg = 1'b0, first_cycle_next;
reg output_last_cycle_reg = 1'b0, output_last_cycle_next;
reg [1:0] rresp_reg = AXI_RESP_OKAY, rresp_next;
reg [TAG_WIDTH-1:0] tag_reg = {TAG_WIDTH{1'b0}}, tag_next;
reg [AXIS_ID_WIDTH-1:0] axis_id_reg = {AXIS_ID_WIDTH{1'b0}}, axis_id_next;
@ -232,6 +255,7 @@ reg [AXIS_USER_WIDTH-1:0] axis_user_reg = {AXIS_USER_WIDTH{1'b0}}, axis_user_nex
reg s_axis_read_desc_ready_reg = 1'b0, s_axis_read_desc_ready_next;
reg [TAG_WIDTH-1:0] m_axis_read_desc_status_tag_reg = {TAG_WIDTH{1'b0}}, m_axis_read_desc_status_tag_next;
reg [3:0] m_axis_read_desc_status_error_reg = 4'd0, m_axis_read_desc_status_error_next;
reg m_axis_read_desc_status_valid_reg = 1'b0, m_axis_read_desc_status_valid_next;
reg [AXI_ADDR_WIDTH-1:0] m_axi_araddr_reg = {AXI_ADDR_WIDTH{1'b0}}, m_axi_araddr_next;
@ -247,16 +271,16 @@ wire [AXI_DATA_WIDTH-1:0] shift_axi_rdata = {m_axi_rdata, save_axi_rdata_reg} >>
reg [AXIS_DATA_WIDTH-1:0] m_axis_read_data_tdata_int;
reg [AXIS_KEEP_WIDTH-1:0] m_axis_read_data_tkeep_int;
reg m_axis_read_data_tvalid_int;
reg m_axis_read_data_tready_int_reg = 1'b0;
wire m_axis_read_data_tready_int;
reg m_axis_read_data_tlast_int;
reg [AXIS_ID_WIDTH-1:0] m_axis_read_data_tid_int;
reg [AXIS_DEST_WIDTH-1:0] m_axis_read_data_tdest_int;
reg [AXIS_USER_WIDTH-1:0] m_axis_read_data_tuser_int;
wire m_axis_read_data_tready_int_early;
assign s_axis_read_desc_ready = s_axis_read_desc_ready_reg;
assign m_axis_read_desc_status_tag = m_axis_read_desc_status_tag_reg;
assign m_axis_read_desc_status_error = m_axis_read_desc_status_error_reg;
assign m_axis_read_desc_status_valid = m_axis_read_desc_status_valid_reg;
assign m_axi_arid = {AXI_ID_WIDTH{1'b0}};
@ -384,6 +408,7 @@ always @* begin
axis_state_next = AXIS_STATE_IDLE;
m_axis_read_desc_status_tag_next = m_axis_read_desc_status_tag_reg;
m_axis_read_desc_status_error_next = m_axis_read_desc_status_error_reg;
m_axis_read_desc_status_valid_next = 1'b0;
m_axis_read_data_tdata_int = shift_axi_rdata;
@ -414,6 +439,12 @@ always @* begin
axis_dest_next = axis_dest_reg;
axis_user_next = axis_user_reg;
if (m_axi_rready && m_axi_rvalid && (m_axi_rresp == AXI_RESP_SLVERR || m_axi_rresp == AXI_RESP_DECERR)) begin
rresp_next = m_axi_rresp;
end else begin
rresp_next = rresp_reg;
end
case (axis_state_reg)
AXIS_STATE_IDLE: begin
// idle state - load new descriptor to start operation
@ -441,15 +472,15 @@ always @* begin
if (axis_cmd_valid_reg) begin
axis_cmd_ready = 1'b1;
m_axi_rready_next = m_axis_read_data_tready_int_early;
m_axi_rready_next = m_axis_read_data_tready_int;
axis_state_next = AXIS_STATE_READ;
end
end
AXIS_STATE_READ: begin
// handle AXI read data
m_axi_rready_next = m_axis_read_data_tready_int_early && input_active_reg;
m_axi_rready_next = m_axis_read_data_tready_int && input_active_reg;
if (m_axis_read_data_tready_int_reg && ((m_axi_rready && m_axi_rvalid) || !input_active_reg)) begin
if ((m_axi_rready && m_axi_rvalid) || !input_active_reg) begin
// transfer in AXI read data
transfer_in_save = m_axi_rready && m_axi_rvalid;
@ -461,7 +492,7 @@ always @* begin
bubble_cycle_next = 1'b0;
first_cycle_next = 1'b0;
m_axi_rready_next = m_axis_read_data_tready_int_early && input_active_next;
m_axi_rready_next = m_axis_read_data_tready_int && input_active_next;
axis_state_next = AXIS_STATE_READ;
end else begin
// update counters
@ -490,13 +521,22 @@ always @* begin
m_axis_read_data_tlast_int = 1'b1;
m_axis_read_desc_status_tag_next = tag_reg;
if (rresp_next == AXI_RESP_SLVERR) begin
m_axis_read_desc_status_error_next = DMA_ERROR_AXI_RD_SLVERR;
end else if (rresp_next == AXI_RESP_DECERR) begin
m_axis_read_desc_status_error_next = DMA_ERROR_AXI_RD_DECERR;
end else begin
m_axis_read_desc_status_error_next = DMA_ERROR_NONE;
end
m_axis_read_desc_status_valid_next = 1'b1;
rresp_next = AXI_RESP_OKAY;
m_axi_rready_next = 1'b0;
axis_state_next = AXIS_STATE_IDLE;
end else begin
// more cycles in AXI transfer
m_axi_rready_next = m_axis_read_data_tready_int_early && input_active_next;
m_axi_rready_next = m_axis_read_data_tready_int && input_active_next;
axis_state_next = AXIS_STATE_READ;
end
end
@ -513,8 +553,9 @@ always @(posedge clk) begin
s_axis_read_desc_ready_reg <= s_axis_read_desc_ready_next;
m_axis_read_desc_status_valid_reg <= m_axis_read_desc_status_valid_next;
m_axis_read_desc_status_tag_reg <= m_axis_read_desc_status_tag_next;
m_axis_read_desc_status_error_reg <= m_axis_read_desc_status_error_next;
m_axis_read_desc_status_valid_reg <= m_axis_read_desc_status_valid_next;
m_axi_araddr_reg <= m_axi_araddr_next;
m_axi_arlen_reg <= m_axi_arlen_next;
@ -545,6 +586,7 @@ always @(posedge clk) begin
bubble_cycle_reg <= bubble_cycle_next;
first_cycle_reg <= first_cycle_next;
output_last_cycle_reg <= output_last_cycle_next;
rresp_reg <= rresp_next;
tag_reg <= tag_next;
axis_id_reg <= axis_id_next;
@ -566,30 +608,41 @@ always @(posedge clk) begin
m_axis_read_desc_status_valid_reg <= 1'b0;
m_axi_arvalid_reg <= 1'b0;
m_axi_rready_reg <= 1'b0;
rresp_reg <= AXI_RESP_OKAY;
end
end
// output datapath logic
reg [AXIS_DATA_WIDTH-1:0] m_axis_read_data_tdata_reg = {AXIS_DATA_WIDTH{1'b0}};
reg [AXIS_KEEP_WIDTH-1:0] m_axis_read_data_tkeep_reg = {AXIS_KEEP_WIDTH{1'b0}};
reg m_axis_read_data_tvalid_reg = 1'b0, m_axis_read_data_tvalid_next;
reg m_axis_read_data_tvalid_reg = 1'b0;
reg m_axis_read_data_tlast_reg = 1'b0;
reg [AXIS_ID_WIDTH-1:0] m_axis_read_data_tid_reg = {AXIS_ID_WIDTH{1'b0}};
reg [AXIS_DEST_WIDTH-1:0] m_axis_read_data_tdest_reg = {AXIS_DEST_WIDTH{1'b0}};
reg [AXIS_USER_WIDTH-1:0] m_axis_read_data_tuser_reg = {AXIS_USER_WIDTH{1'b0}};
reg [AXIS_DATA_WIDTH-1:0] temp_m_axis_read_data_tdata_reg = {AXIS_DATA_WIDTH{1'b0}};
reg [AXIS_KEEP_WIDTH-1:0] temp_m_axis_read_data_tkeep_reg = {AXIS_KEEP_WIDTH{1'b0}};
reg temp_m_axis_read_data_tvalid_reg = 1'b0, temp_m_axis_read_data_tvalid_next;
reg temp_m_axis_read_data_tlast_reg = 1'b0;
reg [AXIS_ID_WIDTH-1:0] temp_m_axis_read_data_tid_reg = {AXIS_ID_WIDTH{1'b0}};
reg [AXIS_DEST_WIDTH-1:0] temp_m_axis_read_data_tdest_reg = {AXIS_DEST_WIDTH{1'b0}};
reg [AXIS_USER_WIDTH-1:0] temp_m_axis_read_data_tuser_reg = {AXIS_USER_WIDTH{1'b0}};
reg [OUTPUT_FIFO_ADDR_WIDTH+1-1:0] out_fifo_wr_ptr_reg = 0;
reg [OUTPUT_FIFO_ADDR_WIDTH+1-1:0] out_fifo_rd_ptr_reg = 0;
reg out_fifo_half_full_reg = 1'b0;
// datapath control
reg store_axis_int_to_output;
reg store_axis_int_to_temp;
reg store_axis_temp_to_output;
wire out_fifo_full = out_fifo_wr_ptr_reg == (out_fifo_rd_ptr_reg ^ {1'b1, {OUTPUT_FIFO_ADDR_WIDTH{1'b0}}});
wire out_fifo_empty = out_fifo_wr_ptr_reg == out_fifo_rd_ptr_reg;
(* ram_style = "distributed" *)
reg [AXIS_DATA_WIDTH-1:0] out_fifo_tdata[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
(* ram_style = "distributed" *)
reg [AXIS_KEEP_WIDTH-1:0] out_fifo_tkeep[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
(* ram_style = "distributed" *)
reg out_fifo_tlast[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
(* ram_style = "distributed" *)
reg [AXIS_ID_WIDTH-1:0] out_fifo_tid[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
(* ram_style = "distributed" *)
reg [AXIS_DEST_WIDTH-1:0] out_fifo_tdest[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
(* ram_style = "distributed" *)
reg [AXIS_USER_WIDTH-1:0] out_fifo_tuser[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
assign m_axis_read_data_tready_int = !out_fifo_half_full_reg;
assign m_axis_read_data_tdata = m_axis_read_data_tdata_reg;
assign m_axis_read_data_tkeep = AXIS_KEEP_ENABLE ? m_axis_read_data_tkeep_reg : {AXIS_KEEP_WIDTH{1'b1}};
@ -599,72 +652,36 @@ assign m_axis_read_data_tid = AXIS_ID_ENABLE ? m_axis_read_data_tid_reg :
assign m_axis_read_data_tdest = AXIS_DEST_ENABLE ? m_axis_read_data_tdest_reg : {AXIS_DEST_WIDTH{1'b0}};
assign m_axis_read_data_tuser = AXIS_USER_ENABLE ? m_axis_read_data_tuser_reg : {AXIS_USER_WIDTH{1'b0}};
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_axis_read_data_tready_int_early = m_axis_read_data_tready || (!temp_m_axis_read_data_tvalid_reg && (!m_axis_read_data_tvalid_reg || !m_axis_read_data_tvalid_int));
always @* begin
// transfer sink ready state to source
m_axis_read_data_tvalid_next = m_axis_read_data_tvalid_reg;
temp_m_axis_read_data_tvalid_next = temp_m_axis_read_data_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (m_axis_read_data_tready_int_reg) begin
// input is ready
if (m_axis_read_data_tready || !m_axis_read_data_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_axis_read_data_tvalid_next = m_axis_read_data_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axis_read_data_tvalid_next = m_axis_read_data_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (m_axis_read_data_tready) begin
// input is not ready, but output is ready
m_axis_read_data_tvalid_next = temp_m_axis_read_data_tvalid_reg;
temp_m_axis_read_data_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
m_axis_read_data_tvalid_reg <= m_axis_read_data_tvalid_reg && !m_axis_read_data_tready;
out_fifo_half_full_reg <= $unsigned(out_fifo_wr_ptr_reg - out_fifo_rd_ptr_reg) >= 2**(OUTPUT_FIFO_ADDR_WIDTH-1);
if (!out_fifo_full && m_axis_read_data_tvalid_int) begin
out_fifo_tdata[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axis_read_data_tdata_int;
out_fifo_tkeep[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axis_read_data_tkeep_int;
out_fifo_tlast[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axis_read_data_tlast_int;
out_fifo_tid[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axis_read_data_tid_int;
out_fifo_tdest[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axis_read_data_tdest_int;
out_fifo_tuser[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axis_read_data_tuser_int;
out_fifo_wr_ptr_reg <= out_fifo_wr_ptr_reg + 1;
end
if (!out_fifo_empty && (!m_axis_read_data_tvalid_reg || m_axis_read_data_tready)) begin
m_axis_read_data_tdata_reg <= out_fifo_tdata[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
m_axis_read_data_tkeep_reg <= out_fifo_tkeep[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
m_axis_read_data_tvalid_reg <= 1'b1;
m_axis_read_data_tlast_reg <= out_fifo_tlast[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
m_axis_read_data_tid_reg <= out_fifo_tid[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
m_axis_read_data_tdest_reg <= out_fifo_tdest[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
m_axis_read_data_tuser_reg <= out_fifo_tuser[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
out_fifo_rd_ptr_reg <= out_fifo_rd_ptr_reg + 1;
end
if (rst) begin
out_fifo_wr_ptr_reg <= 0;
out_fifo_rd_ptr_reg <= 0;
m_axis_read_data_tvalid_reg <= 1'b0;
m_axis_read_data_tready_int_reg <= 1'b0;
temp_m_axis_read_data_tvalid_reg <= 1'b0;
end else begin
m_axis_read_data_tvalid_reg <= m_axis_read_data_tvalid_next;
m_axis_read_data_tready_int_reg <= m_axis_read_data_tready_int_early;
temp_m_axis_read_data_tvalid_reg <= temp_m_axis_read_data_tvalid_next;
end
// datapath
if (store_axis_int_to_output) begin
m_axis_read_data_tdata_reg <= m_axis_read_data_tdata_int;
m_axis_read_data_tkeep_reg <= m_axis_read_data_tkeep_int;
m_axis_read_data_tlast_reg <= m_axis_read_data_tlast_int;
m_axis_read_data_tid_reg <= m_axis_read_data_tid_int;
m_axis_read_data_tdest_reg <= m_axis_read_data_tdest_int;
m_axis_read_data_tuser_reg <= m_axis_read_data_tuser_int;
end else if (store_axis_temp_to_output) begin
m_axis_read_data_tdata_reg <= temp_m_axis_read_data_tdata_reg;
m_axis_read_data_tkeep_reg <= temp_m_axis_read_data_tkeep_reg;
m_axis_read_data_tlast_reg <= temp_m_axis_read_data_tlast_reg;
m_axis_read_data_tid_reg <= temp_m_axis_read_data_tid_reg;
m_axis_read_data_tdest_reg <= temp_m_axis_read_data_tdest_reg;
m_axis_read_data_tuser_reg <= temp_m_axis_read_data_tuser_reg;
end
if (store_axis_int_to_temp) begin
temp_m_axis_read_data_tdata_reg <= m_axis_read_data_tdata_int;
temp_m_axis_read_data_tkeep_reg <= m_axis_read_data_tkeep_int;
temp_m_axis_read_data_tlast_reg <= m_axis_read_data_tlast_int;
temp_m_axis_read_data_tid_reg <= m_axis_read_data_tid_int;
temp_m_axis_read_data_tdest_reg <= m_axis_read_data_tdest_int;
temp_m_axis_read_data_tuser_reg <= m_axis_read_data_tuser_int;
end
end

View File

@ -92,6 +92,7 @@ module axi_dma_wr #
output wire [AXIS_ID_WIDTH-1:0] m_axis_write_desc_status_id,
output wire [AXIS_DEST_WIDTH-1:0] m_axis_write_desc_status_dest,
output wire [AXIS_USER_WIDTH-1:0] m_axis_write_desc_status_user,
output wire [3:0] m_axis_write_desc_status_error,
output wire m_axis_write_desc_status_valid,
/*
@ -151,6 +152,7 @@ parameter ADDR_MASK = {AXI_ADDR_WIDTH{1'b1}} << $clog2(AXI_STRB_WIDTH);
parameter CYCLE_COUNT_WIDTH = LEN_WIDTH - AXI_BURST_SIZE + 1;
parameter STATUS_FIFO_ADDR_WIDTH = 5;
parameter OUTPUT_FIFO_ADDR_WIDTH = 5;
// bus width assertions
initial begin
@ -190,6 +192,25 @@ initial begin
end
end
localparam [1:0]
AXI_RESP_OKAY = 2'b00,
AXI_RESP_EXOKAY = 2'b01,
AXI_RESP_SLVERR = 2'b10,
AXI_RESP_DECERR = 2'b11;
localparam [3:0]
DMA_ERROR_NONE = 4'd0,
DMA_ERROR_TIMEOUT = 4'd1,
DMA_ERROR_PARITY = 4'd2,
DMA_ERROR_AXI_RD_SLVERR = 4'd4,
DMA_ERROR_AXI_RD_DECERR = 4'd5,
DMA_ERROR_AXI_WR_SLVERR = 4'd6,
DMA_ERROR_AXI_WR_DECERR = 4'd7,
DMA_ERROR_PCIE_FLR = 4'd8,
DMA_ERROR_PCIE_CPL_POISONED = 4'd9,
DMA_ERROR_PCIE_CPL_STATUS_UR = 4'd10,
DMA_ERROR_PCIE_CPL_STATUS_CA = 4'd11;
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_START = 3'd1,
@ -223,6 +244,7 @@ reg first_cycle_reg = 1'b0, first_cycle_next;
reg input_last_cycle_reg = 1'b0, input_last_cycle_next;
reg output_last_cycle_reg = 1'b0, output_last_cycle_next;
reg last_transfer_reg = 1'b0, last_transfer_next;
reg [1:0] bresp_reg = AXI_RESP_OKAY, bresp_next;
reg [TAG_WIDTH-1:0] tag_reg = {TAG_WIDTH{1'b0}}, tag_next;
reg [AXIS_ID_WIDTH-1:0] axis_id_reg = {AXIS_ID_WIDTH{1'b0}}, axis_id_next;
@ -256,6 +278,7 @@ reg [TAG_WIDTH-1:0] m_axis_write_desc_status_tag_reg = {TAG_WIDTH{1'b0}}, m_axis
reg [AXIS_ID_WIDTH-1:0] m_axis_write_desc_status_id_reg = {AXIS_ID_WIDTH{1'b0}}, m_axis_write_desc_status_id_next;
reg [AXIS_DEST_WIDTH-1:0] m_axis_write_desc_status_dest_reg = {AXIS_DEST_WIDTH{1'b0}}, m_axis_write_desc_status_dest_next;
reg [AXIS_USER_WIDTH-1:0] m_axis_write_desc_status_user_reg = {AXIS_USER_WIDTH{1'b0}}, m_axis_write_desc_status_user_next;
reg [3:0] m_axis_write_desc_status_error_reg = 4'd0, m_axis_write_desc_status_error_next;
reg m_axis_write_desc_status_valid_reg = 1'b0, m_axis_write_desc_status_valid_next;
reg [AXI_ADDR_WIDTH-1:0] m_axi_awaddr_reg = {AXI_ADDR_WIDTH{1'b0}}, m_axi_awaddr_next;
@ -281,8 +304,7 @@ reg [AXI_DATA_WIDTH-1:0] m_axi_wdata_int;
reg [AXI_STRB_WIDTH-1:0] m_axi_wstrb_int;
reg m_axi_wlast_int;
reg m_axi_wvalid_int;
reg m_axi_wready_int_reg = 1'b0;
wire m_axi_wready_int_early;
wire m_axi_wready_int;
assign s_axis_write_desc_ready = s_axis_write_desc_ready_reg;
@ -291,6 +313,7 @@ assign m_axis_write_desc_status_tag = m_axis_write_desc_status_tag_reg;
assign m_axis_write_desc_status_id = m_axis_write_desc_status_id_reg;
assign m_axis_write_desc_status_dest = m_axis_write_desc_status_dest_reg;
assign m_axis_write_desc_status_user = m_axis_write_desc_status_user_reg;
assign m_axis_write_desc_status_error = m_axis_write_desc_status_error_reg;
assign m_axis_write_desc_status_valid = m_axis_write_desc_status_valid_reg;
assign s_axis_write_data_tready = s_axis_write_data_tready_reg;
@ -345,6 +368,7 @@ always @* begin
m_axis_write_desc_status_id_next = m_axis_write_desc_status_id_reg;
m_axis_write_desc_status_dest_next = m_axis_write_desc_status_dest_reg;
m_axis_write_desc_status_user_next = m_axis_write_desc_status_user_reg;
m_axis_write_desc_status_error_next = m_axis_write_desc_status_error_reg;
m_axis_write_desc_status_valid_next = 1'b0;
s_axis_write_data_tready_next = 1'b0;
@ -397,6 +421,12 @@ always @* begin
status_fifo_wr_user = axis_user_reg;
status_fifo_wr_last = 1'b0;
if (m_axi_bready && m_axi_bvalid && (m_axi_bresp == AXI_RESP_SLVERR || m_axi_bresp == AXI_RESP_DECERR)) begin
bresp_next = m_axi_bresp;
end else begin
bresp_next = bresp_reg;
end
case (state_reg)
STATE_IDLE: begin
// idle state - load new descriptor to start operation
@ -480,7 +510,7 @@ always @* begin
addr_next = addr_reg + tr_word_count_next;
op_word_count_next = op_word_count_reg - tr_word_count_next;
s_axis_write_data_tready_next = m_axi_wready_int_early && input_active_next;
s_axis_write_data_tready_next = m_axi_wready_int && input_active_next;
inc_active = 1'b1;
@ -493,9 +523,9 @@ always @* begin
end
end
STATE_WRITE: begin
s_axis_write_data_tready_next = m_axi_wready_int_early && (last_transfer_reg || input_active_reg) && shift_axis_input_tready;
s_axis_write_data_tready_next = m_axi_wready_int && (last_transfer_reg || input_active_reg) && shift_axis_input_tready;
if (m_axi_wready_int_reg && ((s_axis_write_data_tready && shift_axis_tvalid) || (!input_active_reg && !last_transfer_reg) || !shift_axis_input_tready)) begin
if ((s_axis_write_data_tready && shift_axis_tvalid) || (!input_active_reg && !last_transfer_reg) || !shift_axis_input_tready) begin
if (s_axis_write_data_tready && s_axis_write_data_tvalid) begin
transfer_in_save = 1'b1;
@ -659,7 +689,7 @@ always @* begin
end
end
end else begin
s_axis_write_data_tready_next = m_axi_wready_int_early && (last_transfer_reg || input_active_next) && shift_axis_input_tready;
s_axis_write_data_tready_next = m_axi_wready_int && (last_transfer_reg || input_active_next) && shift_axis_input_tready;
state_next = STATE_WRITE;
end
end else begin
@ -669,7 +699,7 @@ always @* begin
STATE_FINISH_BURST: begin
// finish current AXI burst
if (m_axi_wready_int_reg) begin
if (m_axi_wready_int) begin
// update counters
if (input_active_reg) begin
input_cycle_count_next = input_cycle_count_reg - 1;
@ -729,10 +759,21 @@ always @* begin
m_axis_write_desc_status_id_next = status_fifo_id[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]];
m_axis_write_desc_status_dest_next = status_fifo_dest[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]];
m_axis_write_desc_status_user_next = status_fifo_user[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]];
if (bresp_next == AXI_RESP_SLVERR) begin
m_axis_write_desc_status_error_next = DMA_ERROR_AXI_WR_SLVERR;
end else if (bresp_next == AXI_RESP_DECERR) begin
m_axis_write_desc_status_error_next = DMA_ERROR_AXI_WR_DECERR;
end else begin
m_axis_write_desc_status_error_next = DMA_ERROR_NONE;
end
m_axis_write_desc_status_valid_next = status_fifo_last[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]];
status_fifo_rd_ptr_next = status_fifo_rd_ptr_reg + 1;
m_axi_bready_next = 1'b0;
if (status_fifo_last[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]]) begin
bresp_next = AXI_RESP_OKAY;
end
dec_active = 1'b1;
end else begin
// wait for write completion
@ -751,6 +792,7 @@ always @(posedge clk) begin
m_axis_write_desc_status_id_reg <= m_axis_write_desc_status_id_next;
m_axis_write_desc_status_dest_reg <= m_axis_write_desc_status_dest_next;
m_axis_write_desc_status_user_reg <= m_axis_write_desc_status_user_next;
m_axis_write_desc_status_error_reg <= m_axis_write_desc_status_error_next;
m_axis_write_desc_status_valid_reg <= m_axis_write_desc_status_valid_next;
s_axis_write_data_tready_reg <= s_axis_write_data_tready_next;
@ -775,6 +817,7 @@ always @(posedge clk) begin
input_last_cycle_reg <= input_last_cycle_next;
output_last_cycle_reg <= output_last_cycle_next;
last_transfer_reg <= last_transfer_next;
bresp_reg <= bresp_next;
tag_reg <= tag_next;
axis_id_reg <= axis_id_next;
@ -825,6 +868,8 @@ always @(posedge clk) begin
m_axi_awvalid_reg <= 1'b0;
m_axi_bready_reg <= 1'b0;
bresp_reg <= AXI_RESP_OKAY;
save_axis_tlast_reg <= 1'b0;
shift_axis_extra_cycle_reg <= 1'b0;
@ -840,80 +885,53 @@ end
reg [AXI_DATA_WIDTH-1:0] m_axi_wdata_reg = {AXI_DATA_WIDTH{1'b0}};
reg [AXI_STRB_WIDTH-1:0] m_axi_wstrb_reg = {AXI_STRB_WIDTH{1'b0}};
reg m_axi_wlast_reg = 1'b0;
reg m_axi_wvalid_reg = 1'b0, m_axi_wvalid_next;
reg m_axi_wvalid_reg = 1'b0;
reg [AXI_DATA_WIDTH-1:0] temp_m_axi_wdata_reg = {AXI_DATA_WIDTH{1'b0}};
reg [AXI_STRB_WIDTH-1:0] temp_m_axi_wstrb_reg = {AXI_STRB_WIDTH{1'b0}};
reg temp_m_axi_wlast_reg = 1'b0;
reg temp_m_axi_wvalid_reg = 1'b0, temp_m_axi_wvalid_next;
reg [OUTPUT_FIFO_ADDR_WIDTH+1-1:0] out_fifo_wr_ptr_reg = 0;
reg [OUTPUT_FIFO_ADDR_WIDTH+1-1:0] out_fifo_rd_ptr_reg = 0;
reg out_fifo_half_full_reg = 1'b0;
// datapath control
reg store_axi_w_int_to_output;
reg store_axi_w_int_to_temp;
reg store_axi_w_temp_to_output;
wire out_fifo_full = out_fifo_wr_ptr_reg == (out_fifo_rd_ptr_reg ^ {1'b1, {OUTPUT_FIFO_ADDR_WIDTH{1'b0}}});
wire out_fifo_empty = out_fifo_wr_ptr_reg == out_fifo_rd_ptr_reg;
(* ram_style = "distributed" *)
reg [AXI_DATA_WIDTH-1:0] out_fifo_wdata[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
(* ram_style = "distributed" *)
reg [AXI_STRB_WIDTH-1:0] out_fifo_wstrb[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
(* ram_style = "distributed" *)
reg out_fifo_wlast[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
assign m_axi_wready_int = !out_fifo_half_full_reg;
assign m_axi_wdata = m_axi_wdata_reg;
assign m_axi_wstrb = m_axi_wstrb_reg;
assign m_axi_wvalid = m_axi_wvalid_reg;
assign m_axi_wlast = m_axi_wlast_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_axi_wready_int_early = m_axi_wready || (!temp_m_axi_wvalid_reg && (!m_axi_wvalid_reg || !m_axi_wvalid_int));
always @* begin
// transfer sink ready state to source
m_axi_wvalid_next = m_axi_wvalid_reg;
temp_m_axi_wvalid_next = temp_m_axi_wvalid_reg;
store_axi_w_int_to_output = 1'b0;
store_axi_w_int_to_temp = 1'b0;
store_axi_w_temp_to_output = 1'b0;
if (m_axi_wready_int_reg) begin
// input is ready
if (m_axi_wready || !m_axi_wvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_axi_wvalid_next = m_axi_wvalid_int;
store_axi_w_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axi_wvalid_next = m_axi_wvalid_int;
store_axi_w_int_to_temp = 1'b1;
end
end else if (m_axi_wready) begin
// input is not ready, but output is ready
m_axi_wvalid_next = temp_m_axi_wvalid_reg;
temp_m_axi_wvalid_next = 1'b0;
store_axi_w_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
m_axi_wvalid_reg <= m_axi_wvalid_reg && !m_axi_wready;
out_fifo_half_full_reg <= $unsigned(out_fifo_wr_ptr_reg - out_fifo_rd_ptr_reg) >= 2**(OUTPUT_FIFO_ADDR_WIDTH-1);
if (!out_fifo_full && m_axi_wvalid_int) begin
out_fifo_wdata[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axi_wdata_int;
out_fifo_wstrb[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axi_wstrb_int;
out_fifo_wlast[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axi_wlast_int;
out_fifo_wr_ptr_reg <= out_fifo_wr_ptr_reg + 1;
end
if (!out_fifo_empty && (!m_axi_wvalid_reg || m_axi_wready)) begin
m_axi_wdata_reg <= out_fifo_wdata[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
m_axi_wstrb_reg <= out_fifo_wstrb[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
m_axi_wlast_reg <= out_fifo_wlast[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
m_axi_wvalid_reg <= 1'b1;
out_fifo_rd_ptr_reg <= out_fifo_rd_ptr_reg + 1;
end
if (rst) begin
out_fifo_wr_ptr_reg <= 0;
out_fifo_rd_ptr_reg <= 0;
m_axi_wvalid_reg <= 1'b0;
m_axi_wready_int_reg <= 1'b0;
temp_m_axi_wvalid_reg <= 1'b0;
end else begin
m_axi_wvalid_reg <= m_axi_wvalid_next;
m_axi_wready_int_reg <= m_axi_wready_int_early;
temp_m_axi_wvalid_reg <= temp_m_axi_wvalid_next;
end
// datapath
if (store_axi_w_int_to_output) begin
m_axi_wdata_reg <= m_axi_wdata_int;
m_axi_wstrb_reg <= m_axi_wstrb_int;
m_axi_wlast_reg <= m_axi_wlast_int;
end else if (store_axi_w_temp_to_output) begin
m_axi_wdata_reg <= temp_m_axi_wdata_reg;
m_axi_wstrb_reg <= temp_m_axi_wstrb_reg;
m_axi_wlast_reg <= temp_m_axi_wlast_reg;
end
if (store_axi_w_int_to_temp) begin
temp_m_axi_wdata_reg <= m_axi_wdata_int;
temp_m_axi_wstrb_reg <= m_axi_wstrb_int;
temp_m_axi_wlast_reg <= m_axi_wlast_int;
end
end

View File

@ -0,0 +1,247 @@
/*
Copyright (c) 2021 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* AXI4 lite crossbar
*/
module axil_crossbar #
(
// Number of AXI inputs (slave interfaces)
parameter S_COUNT = 4,
// Number of AXI outputs (master interfaces)
parameter M_COUNT = 4,
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 32,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Number of concurrent operations for each slave interface
// S_COUNT concatenated fields of 32 bits
parameter S_ACCEPT = {S_COUNT{32'd16}},
// Number of regions per master interface
parameter M_REGIONS = 1,
// Master interface base addresses
// M_COUNT concatenated fields of M_REGIONS concatenated fields of ADDR_WIDTH bits
// set to zero for default addressing based on M_ADDR_WIDTH
parameter M_BASE_ADDR = 0,
// Master interface address widths
// M_COUNT concatenated fields of M_REGIONS concatenated fields of 32 bits
parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}},
// Read connections between interfaces
// M_COUNT concatenated fields of S_COUNT bits
parameter M_CONNECT_READ = {M_COUNT{{S_COUNT{1'b1}}}},
// Write connections between interfaces
// M_COUNT concatenated fields of S_COUNT bits
parameter M_CONNECT_WRITE = {M_COUNT{{S_COUNT{1'b1}}}},
// Number of concurrent operations for each master interface
// M_COUNT concatenated fields of 32 bits
parameter M_ISSUE = {M_COUNT{32'd16}},
// Secure master (fail operations based on awprot/arprot)
// M_COUNT bits
parameter M_SECURE = {M_COUNT{1'b0}},
// Slave interface AW channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S_AW_REG_TYPE = {S_COUNT{2'd0}},
// Slave interface W channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S_W_REG_TYPE = {S_COUNT{2'd0}},
// Slave interface B channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S_B_REG_TYPE = {S_COUNT{2'd1}},
// Slave interface AR channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S_AR_REG_TYPE = {S_COUNT{2'd0}},
// Slave interface R channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S_R_REG_TYPE = {S_COUNT{2'd2}},
// Master interface AW channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M_AW_REG_TYPE = {M_COUNT{2'd1}},
// Master interface W channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M_W_REG_TYPE = {M_COUNT{2'd2}},
// Master interface B channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M_B_REG_TYPE = {M_COUNT{2'd0}},
// Master interface AR channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M_AR_REG_TYPE = {M_COUNT{2'd1}},
// Master interface R channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M_R_REG_TYPE = {M_COUNT{2'd0}}
)
(
input wire clk,
input wire rst,
/*
* AXI lite slave interfaces
*/
input wire [S_COUNT*ADDR_WIDTH-1:0] s_axil_awaddr,
input wire [S_COUNT*3-1:0] s_axil_awprot,
input wire [S_COUNT-1:0] s_axil_awvalid,
output wire [S_COUNT-1:0] s_axil_awready,
input wire [S_COUNT*DATA_WIDTH-1:0] s_axil_wdata,
input wire [S_COUNT*STRB_WIDTH-1:0] s_axil_wstrb,
input wire [S_COUNT-1:0] s_axil_wvalid,
output wire [S_COUNT-1:0] s_axil_wready,
output wire [S_COUNT*2-1:0] s_axil_bresp,
output wire [S_COUNT-1:0] s_axil_bvalid,
input wire [S_COUNT-1:0] s_axil_bready,
input wire [S_COUNT*ADDR_WIDTH-1:0] s_axil_araddr,
input wire [S_COUNT*3-1:0] s_axil_arprot,
input wire [S_COUNT-1:0] s_axil_arvalid,
output wire [S_COUNT-1:0] s_axil_arready,
output wire [S_COUNT*DATA_WIDTH-1:0] s_axil_rdata,
output wire [S_COUNT*2-1:0] s_axil_rresp,
output wire [S_COUNT-1:0] s_axil_rvalid,
input wire [S_COUNT-1:0] s_axil_rready,
/*
* AXI lite master interfaces
*/
output wire [M_COUNT*ADDR_WIDTH-1:0] m_axil_awaddr,
output wire [M_COUNT*3-1:0] m_axil_awprot,
output wire [M_COUNT-1:0] m_axil_awvalid,
input wire [M_COUNT-1:0] m_axil_awready,
output wire [M_COUNT*DATA_WIDTH-1:0] m_axil_wdata,
output wire [M_COUNT*STRB_WIDTH-1:0] m_axil_wstrb,
output wire [M_COUNT-1:0] m_axil_wvalid,
input wire [M_COUNT-1:0] m_axil_wready,
input wire [M_COUNT*2-1:0] m_axil_bresp,
input wire [M_COUNT-1:0] m_axil_bvalid,
output wire [M_COUNT-1:0] m_axil_bready,
output wire [M_COUNT*ADDR_WIDTH-1:0] m_axil_araddr,
output wire [M_COUNT*3-1:0] m_axil_arprot,
output wire [M_COUNT-1:0] m_axil_arvalid,
input wire [M_COUNT-1:0] m_axil_arready,
input wire [M_COUNT*DATA_WIDTH-1:0] m_axil_rdata,
input wire [M_COUNT*2-1:0] m_axil_rresp,
input wire [M_COUNT-1:0] m_axil_rvalid,
output wire [M_COUNT-1:0] m_axil_rready
);
axil_crossbar_wr #(
.S_COUNT(S_COUNT),
.M_COUNT(M_COUNT),
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.S_ACCEPT(S_ACCEPT),
.M_REGIONS(M_REGIONS),
.M_BASE_ADDR(M_BASE_ADDR),
.M_ADDR_WIDTH(M_ADDR_WIDTH),
.M_CONNECT(M_CONNECT_WRITE),
.M_ISSUE(M_ISSUE),
.M_SECURE(M_SECURE),
.S_AW_REG_TYPE(S_AW_REG_TYPE),
.S_W_REG_TYPE (S_W_REG_TYPE),
.S_B_REG_TYPE (S_B_REG_TYPE)
)
axil_crossbar_wr_inst (
.clk(clk),
.rst(rst),
/*
* AXI lite slave interfaces
*/
.s_axil_awaddr(s_axil_awaddr),
.s_axil_awprot(s_axil_awprot),
.s_axil_awvalid(s_axil_awvalid),
.s_axil_awready(s_axil_awready),
.s_axil_wdata(s_axil_wdata),
.s_axil_wstrb(s_axil_wstrb),
.s_axil_wvalid(s_axil_wvalid),
.s_axil_wready(s_axil_wready),
.s_axil_bresp(s_axil_bresp),
.s_axil_bvalid(s_axil_bvalid),
.s_axil_bready(s_axil_bready),
/*
* AXI lite master interfaces
*/
.m_axil_awaddr(m_axil_awaddr),
.m_axil_awprot(m_axil_awprot),
.m_axil_awvalid(m_axil_awvalid),
.m_axil_awready(m_axil_awready),
.m_axil_wdata(m_axil_wdata),
.m_axil_wstrb(m_axil_wstrb),
.m_axil_wvalid(m_axil_wvalid),
.m_axil_wready(m_axil_wready),
.m_axil_bresp(m_axil_bresp),
.m_axil_bvalid(m_axil_bvalid),
.m_axil_bready(m_axil_bready)
);
axil_crossbar_rd #(
.S_COUNT(S_COUNT),
.M_COUNT(M_COUNT),
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.S_ACCEPT(S_ACCEPT),
.M_REGIONS(M_REGIONS),
.M_BASE_ADDR(M_BASE_ADDR),
.M_ADDR_WIDTH(M_ADDR_WIDTH),
.M_CONNECT(M_CONNECT_READ),
.M_ISSUE(M_ISSUE),
.M_SECURE(M_SECURE),
.S_AR_REG_TYPE(S_AR_REG_TYPE),
.S_R_REG_TYPE (S_R_REG_TYPE)
)
axil_crossbar_rd_inst (
.clk(clk),
.rst(rst),
/*
* AXI lite slave interfaces
*/
.s_axil_araddr(s_axil_araddr),
.s_axil_arprot(s_axil_arprot),
.s_axil_arvalid(s_axil_arvalid),
.s_axil_arready(s_axil_arready),
.s_axil_rdata(s_axil_rdata),
.s_axil_rresp(s_axil_rresp),
.s_axil_rvalid(s_axil_rvalid),
.s_axil_rready(s_axil_rready),
/*
* AXI lite master interfaces
*/
.m_axil_araddr(m_axil_araddr),
.m_axil_arprot(m_axil_arprot),
.m_axil_arvalid(m_axil_arvalid),
.m_axil_arready(m_axil_arready),
.m_axil_rdata(m_axil_rdata),
.m_axil_rresp(m_axil_rresp),
.m_axil_rvalid(m_axil_rvalid),
.m_axil_rready(m_axil_rready)
);
endmodule

View File

@ -0,0 +1,263 @@
/*
Copyright (c) 2021 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* AXI4 lite crossbar address decode and admission control
*/
module axil_crossbar_addr #
(
// Slave interface index
parameter S = 0,
// Number of AXI inputs (slave interfaces)
parameter S_COUNT = 4,
// Number of AXI outputs (master interfaces)
parameter M_COUNT = 4,
// Width of address bus in bits
parameter ADDR_WIDTH = 32,
// Number of regions per master interface
parameter M_REGIONS = 1,
// Master interface base addresses
// M_COUNT concatenated fields of M_REGIONS concatenated fields of ADDR_WIDTH bits
// set to zero for default addressing based on M_ADDR_WIDTH
parameter M_BASE_ADDR = 0,
// Master interface address widths
// M_COUNT concatenated fields of M_REGIONS concatenated fields of 32 bits
parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}},
// Connections between interfaces
// M_COUNT concatenated fields of S_COUNT bits
parameter M_CONNECT = {M_COUNT{{S_COUNT{1'b1}}}},
// Secure master (fail operations based on awprot/arprot)
// M_COUNT bits
parameter M_SECURE = {M_COUNT{1'b0}},
// Enable write command output
parameter WC_OUTPUT = 0
)
(
input wire clk,
input wire rst,
/*
* Address input
*/
input wire [ADDR_WIDTH-1:0] s_axil_aaddr,
input wire [2:0] s_axil_aprot,
input wire s_axil_avalid,
output wire s_axil_aready,
/*
* Address output
*/
output wire [$clog2(M_COUNT)-1:0] m_select,
output wire m_axil_avalid,
input wire m_axil_aready,
/*
* Write command output
*/
output wire [$clog2(M_COUNT)-1:0] m_wc_select,
output wire m_wc_decerr,
output wire m_wc_valid,
input wire m_wc_ready,
/*
* Reply command output
*/
output wire [$clog2(M_COUNT)-1:0] m_rc_select,
output wire m_rc_decerr,
output wire m_rc_valid,
input wire m_rc_ready
);
parameter CL_S_COUNT = $clog2(S_COUNT);
parameter CL_M_COUNT = $clog2(M_COUNT);
// default address computation
function [M_COUNT*M_REGIONS*ADDR_WIDTH-1:0] calcBaseAddrs(input [31:0] dummy);
integer i;
reg [ADDR_WIDTH-1:0] base;
begin
calcBaseAddrs = {M_COUNT*M_REGIONS*ADDR_WIDTH{1'b0}};
base = 0;
for (i = 1; i < M_COUNT*M_REGIONS; i = i + 1) begin
if (M_ADDR_WIDTH[i*32 +: 32]) begin
base = base + 2**M_ADDR_WIDTH[(i-1)*32 +: 32]; // increment
base = base - (base % 2**M_ADDR_WIDTH[i*32 +: 32]); // align
calcBaseAddrs[i * ADDR_WIDTH +: ADDR_WIDTH] = base;
end
end
end
endfunction
parameter M_BASE_ADDR_INT = M_BASE_ADDR ? M_BASE_ADDR : calcBaseAddrs(0);
integer i, j;
// check configuration
initial begin
if (M_REGIONS < 1) begin
$error("Error: need at least 1 region (instance %m)");
$finish;
end
for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin
if (M_ADDR_WIDTH[i*32 +: 32] && (M_ADDR_WIDTH[i*32 +: 32] < 12 || M_ADDR_WIDTH[i*32 +: 32] > ADDR_WIDTH)) begin
$error("Error: address width out of range (instance %m)");
$finish;
end
end
$display("Addressing configuration for axi_crossbar_addr instance %m");
for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin
if (M_ADDR_WIDTH[i*32 +: 32]) begin
$display("%2d (%2d): %x / %02d -- %x-%x", i/M_REGIONS, i%M_REGIONS, M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH], M_ADDR_WIDTH[i*32 +: 32], M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[i*32 +: 32]), M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[i*32 +: 32])));
end
end
for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin
for (j = i+1; j < M_COUNT*M_REGIONS; j = j + 1) begin
if (M_ADDR_WIDTH[i*32 +: 32] && M_ADDR_WIDTH[j*32 +: 32]) begin
if (((M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[i*32 +: 32])) <= (M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[j*32 +: 32])))) && ((M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[j*32 +: 32])) <= (M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[i*32 +: 32]))))) begin
$display("Overlapping regions:");
$display("%2d (%2d): %x / %2d -- %x-%x", i/M_REGIONS, i%M_REGIONS, M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH], M_ADDR_WIDTH[i*32 +: 32], M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[i*32 +: 32]), M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[i*32 +: 32])));
$display("%2d (%2d): %x / %2d -- %x-%x", j/M_REGIONS, j%M_REGIONS, M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH], M_ADDR_WIDTH[j*32 +: 32], M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[j*32 +: 32]), M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[j*32 +: 32])));
$error("Error: address ranges overlap (instance %m)");
$finish;
end
end
end
end
end
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_DECODE = 3'd1;
reg [2:0] state_reg = STATE_IDLE, state_next;
reg s_axil_aready_reg = 0, s_axil_aready_next;
reg [CL_M_COUNT-1:0] m_select_reg = 0, m_select_next;
reg m_axil_avalid_reg = 1'b0, m_axil_avalid_next;
reg m_decerr_reg = 1'b0, m_decerr_next;
reg m_wc_valid_reg = 1'b0, m_wc_valid_next;
reg m_rc_valid_reg = 1'b0, m_rc_valid_next;
assign s_axil_aready = s_axil_aready_reg;
assign m_select = m_select_reg;
assign m_axil_avalid = m_axil_avalid_reg;
assign m_wc_select = m_select_reg;
assign m_wc_decerr = m_decerr_reg;
assign m_wc_valid = m_wc_valid_reg;
assign m_rc_select = m_select_reg;
assign m_rc_decerr = m_decerr_reg;
assign m_rc_valid = m_rc_valid_reg;
reg match;
always @* begin
state_next = STATE_IDLE;
match = 1'b0;
s_axil_aready_next = 1'b0;
m_select_next = m_select_reg;
m_axil_avalid_next = m_axil_avalid_reg && !m_axil_aready;
m_decerr_next = m_decerr_reg;
m_wc_valid_next = m_wc_valid_reg && !m_wc_ready;
m_rc_valid_next = m_rc_valid_reg && !m_rc_ready;
case (state_reg)
STATE_IDLE: begin
// idle state, store values
s_axil_aready_next = 1'b0;
if (s_axil_avalid && !s_axil_aready) begin
match = 1'b0;
for (i = 0; i < M_COUNT; i = i + 1) begin
for (j = 0; j < M_REGIONS; j = j + 1) begin
if (M_ADDR_WIDTH[(i*M_REGIONS+j)*32 +: 32] && (!M_SECURE[i] || !s_axil_aprot[1]) && (M_CONNECT & (1 << (S+i*S_COUNT))) && (s_axil_aaddr >> M_ADDR_WIDTH[(i*M_REGIONS+j)*32 +: 32]) == (M_BASE_ADDR_INT[(i*M_REGIONS+j)*ADDR_WIDTH +: ADDR_WIDTH] >> M_ADDR_WIDTH[(i*M_REGIONS+j)*32 +: 32])) begin
m_select_next = i;
match = 1'b1;
end
end
end
if (match) begin
// address decode successful
m_axil_avalid_next = 1'b1;
m_decerr_next = 1'b0;
m_wc_valid_next = WC_OUTPUT;
m_rc_valid_next = 1'b1;
state_next = STATE_DECODE;
end else begin
// decode error
m_axil_avalid_next = 1'b0;
m_decerr_next = 1'b1;
m_wc_valid_next = WC_OUTPUT;
m_rc_valid_next = 1'b1;
state_next = STATE_DECODE;
end
end else begin
state_next = STATE_IDLE;
end
end
STATE_DECODE: begin
if (!m_axil_avalid_next && (!m_wc_valid_next || !WC_OUTPUT) && !m_rc_valid_next) begin
s_axil_aready_next = 1'b1;
state_next = STATE_IDLE;
end else begin
state_next = STATE_DECODE;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
s_axil_aready_reg <= 1'b0;
m_axil_avalid_reg <= 1'b0;
m_wc_valid_reg <= 1'b0;
m_rc_valid_reg <= 1'b0;
end else begin
state_reg <= state_next;
s_axil_aready_reg <= s_axil_aready_next;
m_axil_avalid_reg <= m_axil_avalid_next;
m_wc_valid_reg <= m_wc_valid_next;
m_rc_valid_reg <= m_rc_valid_next;
end
m_select_reg <= m_select_next;
m_decerr_reg <= m_decerr_next;
end
endmodule

View File

@ -0,0 +1,421 @@
/*
Copyright (c) 2021 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* AXI4 lite crossbar (read)
*/
module axil_crossbar_rd #
(
// Number of AXI inputs (slave interfaces)
parameter S_COUNT = 4,
// Number of AXI outputs (master interfaces)
parameter M_COUNT = 4,
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 32,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Number of concurrent operations for each slave interface
// S_COUNT concatenated fields of 32 bits
parameter S_ACCEPT = {S_COUNT{32'd16}},
// Number of regions per master interface
parameter M_REGIONS = 1,
// Master interface base addresses
// M_COUNT concatenated fields of M_REGIONS concatenated fields of ADDR_WIDTH bits
// set to zero for default addressing based on M_ADDR_WIDTH
parameter M_BASE_ADDR = 0,
// Master interface address widths
// M_COUNT concatenated fields of M_REGIONS concatenated fields of 32 bits
parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}},
// Read connections between interfaces
// M_COUNT concatenated fields of S_COUNT bits
parameter M_CONNECT = {M_COUNT{{S_COUNT{1'b1}}}},
// Number of concurrent operations for each master interface
// M_COUNT concatenated fields of 32 bits
parameter M_ISSUE = {M_COUNT{32'd16}},
// Secure master (fail operations based on awprot/arprot)
// M_COUNT bits
parameter M_SECURE = {M_COUNT{1'b0}},
// Slave interface AR channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S_AR_REG_TYPE = {S_COUNT{2'd0}},
// Slave interface R channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S_R_REG_TYPE = {S_COUNT{2'd2}},
// Master interface AR channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M_AR_REG_TYPE = {M_COUNT{2'd1}},
// Master interface R channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M_R_REG_TYPE = {M_COUNT{2'd0}}
)
(
input wire clk,
input wire rst,
/*
* AXI lite slave interfaces
*/
input wire [S_COUNT*ADDR_WIDTH-1:0] s_axil_araddr,
input wire [S_COUNT*3-1:0] s_axil_arprot,
input wire [S_COUNT-1:0] s_axil_arvalid,
output wire [S_COUNT-1:0] s_axil_arready,
output wire [S_COUNT*DATA_WIDTH-1:0] s_axil_rdata,
output wire [S_COUNT*2-1:0] s_axil_rresp,
output wire [S_COUNT-1:0] s_axil_rvalid,
input wire [S_COUNT-1:0] s_axil_rready,
/*
* AXI lite master interfaces
*/
output wire [M_COUNT*ADDR_WIDTH-1:0] m_axil_araddr,
output wire [M_COUNT*3-1:0] m_axil_arprot,
output wire [M_COUNT-1:0] m_axil_arvalid,
input wire [M_COUNT-1:0] m_axil_arready,
input wire [M_COUNT*DATA_WIDTH-1:0] m_axil_rdata,
input wire [M_COUNT*2-1:0] m_axil_rresp,
input wire [M_COUNT-1:0] m_axil_rvalid,
output wire [M_COUNT-1:0] m_axil_rready
);
parameter CL_S_COUNT = $clog2(S_COUNT);
parameter CL_M_COUNT = $clog2(M_COUNT);
parameter M_COUNT_P1 = M_COUNT+1;
parameter CL_M_COUNT_P1 = $clog2(M_COUNT_P1);
integer i;
// check configuration
initial begin
for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin
if (M_ADDR_WIDTH[i*32 +: 32] && (M_ADDR_WIDTH[i*32 +: 32] < 12 || M_ADDR_WIDTH[i*32 +: 32] > ADDR_WIDTH)) begin
$error("Error: value out of range (instance %m)");
$finish;
end
end
end
wire [S_COUNT*ADDR_WIDTH-1:0] int_s_axil_araddr;
wire [S_COUNT*3-1:0] int_s_axil_arprot;
wire [S_COUNT-1:0] int_s_axil_arvalid;
wire [S_COUNT-1:0] int_s_axil_arready;
wire [S_COUNT*M_COUNT-1:0] int_axil_arvalid;
wire [M_COUNT*S_COUNT-1:0] int_axil_arready;
wire [M_COUNT*DATA_WIDTH-1:0] int_m_axil_rdata;
wire [M_COUNT*2-1:0] int_m_axil_rresp;
wire [M_COUNT-1:0] int_m_axil_rvalid;
wire [M_COUNT-1:0] int_m_axil_rready;
wire [M_COUNT*S_COUNT-1:0] int_axil_rvalid;
wire [S_COUNT*M_COUNT-1:0] int_axil_rready;
generate
genvar m, n;
for (m = 0; m < S_COUNT; m = m + 1) begin : s_ifaces
// response routing FIFO
localparam FIFO_ADDR_WIDTH = $clog2(S_ACCEPT[m*32 +: 32])+1;
reg [FIFO_ADDR_WIDTH+1-1:0] fifo_wr_ptr_reg = 0;
reg [FIFO_ADDR_WIDTH+1-1:0] fifo_rd_ptr_reg = 0;
reg [CL_M_COUNT-1:0] fifo_select[(2**FIFO_ADDR_WIDTH)-1:0];
reg fifo_decerr[(2**FIFO_ADDR_WIDTH)-1:0];
wire [CL_M_COUNT-1:0] fifo_wr_select;
wire fifo_wr_decerr;
wire fifo_wr_en;
wire fifo_rd_en;
reg fifo_half_full_reg = 1'b0;
wire fifo_empty = fifo_rd_ptr_reg == fifo_wr_ptr_reg;
integer i;
initial begin
for (i = 0; i < 2**FIFO_ADDR_WIDTH; i = i + 1) begin
fifo_select[i] = 0;
fifo_decerr[i] = 0;
end
end
always @(posedge clk) begin
if (fifo_wr_en) begin
fifo_select[fifo_wr_ptr_reg[FIFO_ADDR_WIDTH-1:0]] <= fifo_wr_select;
fifo_decerr[fifo_wr_ptr_reg[FIFO_ADDR_WIDTH-1:0]] <= fifo_wr_decerr;
fifo_wr_ptr_reg <= fifo_wr_ptr_reg + 1;
end
if (fifo_rd_en) begin
fifo_rd_ptr_reg <= fifo_rd_ptr_reg + 1;
end
fifo_half_full_reg <= $unsigned(fifo_wr_ptr_reg - fifo_rd_ptr_reg) >= 2**(FIFO_ADDR_WIDTH-1);
if (rst) begin
fifo_wr_ptr_reg <= 0;
fifo_rd_ptr_reg <= 0;
end
end
// address decode and admission control
wire [CL_M_COUNT-1:0] a_select;
wire m_axil_avalid;
wire m_axil_aready;
wire [CL_M_COUNT-1:0] m_rc_select;
wire m_rc_decerr;
wire m_rc_valid;
wire m_rc_ready;
axil_crossbar_addr #(
.S(m),
.S_COUNT(S_COUNT),
.M_COUNT(M_COUNT),
.ADDR_WIDTH(ADDR_WIDTH),
.M_REGIONS(M_REGIONS),
.M_BASE_ADDR(M_BASE_ADDR),
.M_ADDR_WIDTH(M_ADDR_WIDTH),
.M_CONNECT(M_CONNECT),
.M_SECURE(M_SECURE),
.WC_OUTPUT(0)
)
addr_inst (
.clk(clk),
.rst(rst),
/*
* Address input
*/
.s_axil_aaddr(int_s_axil_araddr[m*ADDR_WIDTH +: ADDR_WIDTH]),
.s_axil_aprot(int_s_axil_arprot[m*3 +: 3]),
.s_axil_avalid(int_s_axil_arvalid[m]),
.s_axil_aready(int_s_axil_arready[m]),
/*
* Address output
*/
.m_select(a_select),
.m_axil_avalid(m_axil_avalid),
.m_axil_aready(m_axil_aready),
/*
* Write command output
*/
.m_wc_select(),
.m_wc_decerr(),
.m_wc_valid(),
.m_wc_ready(1'b1),
/*
* Response command output
*/
.m_rc_select(m_rc_select),
.m_rc_decerr(m_rc_decerr),
.m_rc_valid(m_rc_valid),
.m_rc_ready(m_rc_ready)
);
assign int_axil_arvalid[m*M_COUNT +: M_COUNT] = m_axil_avalid << a_select;
assign m_axil_aready = int_axil_arready[a_select*S_COUNT+m];
// response handling
assign fifo_wr_select = m_rc_select;
assign fifo_wr_decerr = m_rc_decerr;
assign fifo_wr_en = m_rc_valid && !fifo_half_full_reg;
assign m_rc_ready = !fifo_half_full_reg;
// write response handling
wire [CL_M_COUNT-1:0] r_select = M_COUNT > 1 ? fifo_select[fifo_rd_ptr_reg[FIFO_ADDR_WIDTH-1:0]] : 0;
wire r_decerr = fifo_decerr[fifo_rd_ptr_reg[FIFO_ADDR_WIDTH-1:0]];
wire r_valid = !fifo_empty;
// read response mux
wire [DATA_WIDTH-1:0] m_axil_rdata_mux = r_decerr ? {DATA_WIDTH{1'b0}} : int_m_axil_rdata[r_select*DATA_WIDTH +: DATA_WIDTH];
wire [1:0] m_axil_rresp_mux = r_decerr ? 2'b11 : int_m_axil_rresp[r_select*2 +: 2];
wire m_axil_rvalid_mux = (r_decerr ? 1'b1 : int_axil_rvalid[r_select*S_COUNT+m]) && r_valid;
wire m_axil_rready_mux;
assign int_axil_rready[m*M_COUNT +: M_COUNT] = (r_valid && m_axil_rready_mux) << r_select;
assign fifo_rd_en = m_axil_rvalid_mux && m_axil_rready_mux && r_valid;
// S side register
axil_register_rd #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.AR_REG_TYPE(S_AR_REG_TYPE[m*2 +: 2]),
.R_REG_TYPE(S_R_REG_TYPE[m*2 +: 2])
)
reg_inst (
.clk(clk),
.rst(rst),
.s_axil_araddr(s_axil_araddr[m*ADDR_WIDTH +: ADDR_WIDTH]),
.s_axil_arprot(s_axil_arprot[m*3 +: 3]),
.s_axil_arvalid(s_axil_arvalid[m]),
.s_axil_arready(s_axil_arready[m]),
.s_axil_rdata(s_axil_rdata[m*DATA_WIDTH +: DATA_WIDTH]),
.s_axil_rresp(s_axil_rresp[m*2 +: 2]),
.s_axil_rvalid(s_axil_rvalid[m]),
.s_axil_rready(s_axil_rready[m]),
.m_axil_araddr(int_s_axil_araddr[m*ADDR_WIDTH +: ADDR_WIDTH]),
.m_axil_arprot(int_s_axil_arprot[m*3 +: 3]),
.m_axil_arvalid(int_s_axil_arvalid[m]),
.m_axil_arready(int_s_axil_arready[m]),
.m_axil_rdata(m_axil_rdata_mux),
.m_axil_rresp(m_axil_rresp_mux),
.m_axil_rvalid(m_axil_rvalid_mux),
.m_axil_rready(m_axil_rready_mux)
);
end // s_ifaces
for (n = 0; n < M_COUNT; n = n + 1) begin : m_ifaces
// response routing FIFO
localparam FIFO_ADDR_WIDTH = $clog2(M_ISSUE[n*32 +: 32])+1;
reg [FIFO_ADDR_WIDTH+1-1:0] fifo_wr_ptr_reg = 0;
reg [FIFO_ADDR_WIDTH+1-1:0] fifo_rd_ptr_reg = 0;
reg [CL_S_COUNT-1:0] fifo_select[(2**FIFO_ADDR_WIDTH)-1:0];
wire [CL_S_COUNT-1:0] fifo_wr_select;
wire fifo_wr_en;
wire fifo_rd_en;
reg fifo_half_full_reg = 1'b0;
wire fifo_empty = fifo_rd_ptr_reg == fifo_wr_ptr_reg;
integer i;
initial begin
for (i = 0; i < 2**FIFO_ADDR_WIDTH; i = i + 1) begin
fifo_select[i] = 0;
end
end
always @(posedge clk) begin
if (fifo_wr_en) begin
fifo_select[fifo_wr_ptr_reg[FIFO_ADDR_WIDTH-1:0]] <= fifo_wr_select;
fifo_wr_ptr_reg <= fifo_wr_ptr_reg + 1;
end
if (fifo_rd_en) begin
fifo_rd_ptr_reg <= fifo_rd_ptr_reg + 1;
end
fifo_half_full_reg <= $unsigned(fifo_wr_ptr_reg - fifo_rd_ptr_reg) >= 2**(FIFO_ADDR_WIDTH-1);
if (rst) begin
fifo_wr_ptr_reg <= 0;
fifo_rd_ptr_reg <= 0;
end
end
// address arbitration
wire [S_COUNT-1:0] a_request;
wire [S_COUNT-1:0] a_acknowledge;
wire [S_COUNT-1:0] a_grant;
wire a_grant_valid;
wire [CL_S_COUNT-1:0] a_grant_encoded;
arbiter #(
.PORTS(S_COUNT),
.ARB_TYPE_ROUND_ROBIN(1),
.ARB_BLOCK(1),
.ARB_BLOCK_ACK(1),
.ARB_LSB_HIGH_PRIORITY(1)
)
a_arb_inst (
.clk(clk),
.rst(rst),
.request(a_request),
.acknowledge(a_acknowledge),
.grant(a_grant),
.grant_valid(a_grant_valid),
.grant_encoded(a_grant_encoded)
);
// address mux
wire [ADDR_WIDTH-1:0] s_axil_araddr_mux = int_s_axil_araddr[a_grant_encoded*ADDR_WIDTH +: ADDR_WIDTH];
wire [2:0] s_axil_arprot_mux = int_s_axil_arprot[a_grant_encoded*3 +: 3];
wire s_axil_arvalid_mux = int_axil_arvalid[a_grant_encoded*M_COUNT+n] && a_grant_valid;
wire s_axil_arready_mux;
assign int_axil_arready[n*S_COUNT +: S_COUNT] = (a_grant_valid && s_axil_arready_mux) << a_grant_encoded;
for (m = 0; m < S_COUNT; m = m + 1) begin
assign a_request[m] = int_axil_arvalid[m*M_COUNT+n] && !a_grant[m] && !fifo_half_full_reg;
assign a_acknowledge[m] = a_grant[m] && int_axil_arvalid[m*M_COUNT+n] && s_axil_arready_mux;
end
assign fifo_wr_select = a_grant_encoded;
assign fifo_wr_en = s_axil_arvalid_mux && s_axil_arready_mux && a_grant_valid;
// read response forwarding
wire [CL_S_COUNT-1:0] r_select = S_COUNT > 1 ? fifo_select[fifo_rd_ptr_reg[FIFO_ADDR_WIDTH-1:0]] : 0;
assign int_axil_rvalid[n*S_COUNT +: S_COUNT] = int_m_axil_rvalid[n] << r_select;
assign int_m_axil_rready[n] = int_axil_rready[r_select*M_COUNT+n];
assign fifo_rd_en = int_m_axil_rvalid[n] && int_m_axil_rready[n];
// M side register
axil_register_rd #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.AR_REG_TYPE(M_AR_REG_TYPE[n*2 +: 2]),
.R_REG_TYPE(M_R_REG_TYPE[n*2 +: 2])
)
reg_inst (
.clk(clk),
.rst(rst),
.s_axil_araddr(s_axil_araddr_mux),
.s_axil_arprot(s_axil_arprot_mux),
.s_axil_arvalid(s_axil_arvalid_mux),
.s_axil_arready(s_axil_arready_mux),
.s_axil_rdata(int_m_axil_rdata[n*DATA_WIDTH +: DATA_WIDTH]),
.s_axil_rresp(int_m_axil_rresp[n*2 +: 2]),
.s_axil_rvalid(int_m_axil_rvalid[n]),
.s_axil_rready(int_m_axil_rready[n]),
.m_axil_araddr(m_axil_araddr[n*ADDR_WIDTH +: ADDR_WIDTH]),
.m_axil_arprot(m_axil_arprot[n*3 +: 3]),
.m_axil_arvalid(m_axil_arvalid[n]),
.m_axil_arready(m_axil_arready[n]),
.m_axil_rdata(m_axil_rdata[n*DATA_WIDTH +: DATA_WIDTH]),
.m_axil_rresp(m_axil_rresp[n*2 +: 2]),
.m_axil_rvalid(m_axil_rvalid[n]),
.m_axil_rready(m_axil_rready[n])
);
end // m_ifaces
endgenerate
endmodule

View File

@ -0,0 +1,529 @@
/*
Copyright (c) 2021 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* AXI4 lite crossbar (write)
*/
module axil_crossbar_wr #
(
// Number of AXI inputs (slave interfaces)
parameter S_COUNT = 4,
// Number of AXI outputs (master interfaces)
parameter M_COUNT = 4,
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 32,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Number of concurrent operations for each slave interface
// S_COUNT concatenated fields of 32 bits
parameter S_ACCEPT = {S_COUNT{32'd16}},
// Number of regions per master interface
parameter M_REGIONS = 1,
// Master interface base addresses
// M_COUNT concatenated fields of M_REGIONS concatenated fields of ADDR_WIDTH bits
// set to zero for default addressing based on M_ADDR_WIDTH
parameter M_BASE_ADDR = 0,
// Master interface address widths
// M_COUNT concatenated fields of M_REGIONS concatenated fields of 32 bits
parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}},
// Write connections between interfaces
// M_COUNT concatenated fields of S_COUNT bits
parameter M_CONNECT = {M_COUNT{{S_COUNT{1'b1}}}},
// Number of concurrent operations for each master interface
// M_COUNT concatenated fields of 32 bits
parameter M_ISSUE = {M_COUNT{32'd16}},
// Secure master (fail operations based on awprot/arprot)
// M_COUNT bits
parameter M_SECURE = {M_COUNT{1'b0}},
// Slave interface AW channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S_AW_REG_TYPE = {S_COUNT{2'd0}},
// Slave interface W channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S_W_REG_TYPE = {S_COUNT{2'd0}},
// Slave interface B channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S_B_REG_TYPE = {S_COUNT{2'd1}},
// Master interface AW channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M_AW_REG_TYPE = {M_COUNT{2'd1}},
// Master interface W channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M_W_REG_TYPE = {M_COUNT{2'd2}},
// Master interface B channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M_B_REG_TYPE = {M_COUNT{2'd0}}
)
(
input wire clk,
input wire rst,
/*
* AXI lite slave interfaces
*/
input wire [S_COUNT*ADDR_WIDTH-1:0] s_axil_awaddr,
input wire [S_COUNT*3-1:0] s_axil_awprot,
input wire [S_COUNT-1:0] s_axil_awvalid,
output wire [S_COUNT-1:0] s_axil_awready,
input wire [S_COUNT*DATA_WIDTH-1:0] s_axil_wdata,
input wire [S_COUNT*STRB_WIDTH-1:0] s_axil_wstrb,
input wire [S_COUNT-1:0] s_axil_wvalid,
output wire [S_COUNT-1:0] s_axil_wready,
output wire [S_COUNT*2-1:0] s_axil_bresp,
output wire [S_COUNT-1:0] s_axil_bvalid,
input wire [S_COUNT-1:0] s_axil_bready,
/*
* AXI lite master interfaces
*/
output wire [M_COUNT*ADDR_WIDTH-1:0] m_axil_awaddr,
output wire [M_COUNT*3-1:0] m_axil_awprot,
output wire [M_COUNT-1:0] m_axil_awvalid,
input wire [M_COUNT-1:0] m_axil_awready,
output wire [M_COUNT*DATA_WIDTH-1:0] m_axil_wdata,
output wire [M_COUNT*STRB_WIDTH-1:0] m_axil_wstrb,
output wire [M_COUNT-1:0] m_axil_wvalid,
input wire [M_COUNT-1:0] m_axil_wready,
input wire [M_COUNT*2-1:0] m_axil_bresp,
input wire [M_COUNT-1:0] m_axil_bvalid,
output wire [M_COUNT-1:0] m_axil_bready
);
parameter CL_S_COUNT = $clog2(S_COUNT);
parameter CL_M_COUNT = $clog2(M_COUNT);
parameter M_COUNT_P1 = M_COUNT+1;
parameter CL_M_COUNT_P1 = $clog2(M_COUNT_P1);
integer i;
// check configuration
initial begin
for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin
if (M_ADDR_WIDTH[i*32 +: 32] && (M_ADDR_WIDTH[i*32 +: 32] < 12 || M_ADDR_WIDTH[i*32 +: 32] > ADDR_WIDTH)) begin
$error("Error: value out of range (instance %m)");
$finish;
end
end
end
wire [S_COUNT*ADDR_WIDTH-1:0] int_s_axil_awaddr;
wire [S_COUNT*3-1:0] int_s_axil_awprot;
wire [S_COUNT-1:0] int_s_axil_awvalid;
wire [S_COUNT-1:0] int_s_axil_awready;
wire [S_COUNT*M_COUNT-1:0] int_axil_awvalid;
wire [M_COUNT*S_COUNT-1:0] int_axil_awready;
wire [S_COUNT*DATA_WIDTH-1:0] int_s_axil_wdata;
wire [S_COUNT*STRB_WIDTH-1:0] int_s_axil_wstrb;
wire [S_COUNT-1:0] int_s_axil_wvalid;
wire [S_COUNT-1:0] int_s_axil_wready;
wire [S_COUNT*M_COUNT-1:0] int_axil_wvalid;
wire [M_COUNT*S_COUNT-1:0] int_axil_wready;
wire [M_COUNT*2-1:0] int_m_axil_bresp;
wire [M_COUNT-1:0] int_m_axil_bvalid;
wire [M_COUNT-1:0] int_m_axil_bready;
wire [M_COUNT*S_COUNT-1:0] int_axil_bvalid;
wire [S_COUNT*M_COUNT-1:0] int_axil_bready;
generate
genvar m, n;
for (m = 0; m < S_COUNT; m = m + 1) begin : s_ifaces
// response routing FIFO
localparam FIFO_ADDR_WIDTH = $clog2(S_ACCEPT[m*32 +: 32])+1;
reg [FIFO_ADDR_WIDTH+1-1:0] fifo_wr_ptr_reg = 0;
reg [FIFO_ADDR_WIDTH+1-1:0] fifo_rd_ptr_reg = 0;
reg [CL_M_COUNT-1:0] fifo_select[(2**FIFO_ADDR_WIDTH)-1:0];
reg fifo_decerr[(2**FIFO_ADDR_WIDTH)-1:0];
wire [CL_M_COUNT-1:0] fifo_wr_select;
wire fifo_wr_decerr;
wire fifo_wr_en;
wire fifo_rd_en;
reg fifo_half_full_reg = 1'b0;
wire fifo_empty = fifo_rd_ptr_reg == fifo_wr_ptr_reg;
integer i;
initial begin
for (i = 0; i < 2**FIFO_ADDR_WIDTH; i = i + 1) begin
fifo_select[i] = 0;
fifo_decerr[i] = 0;
end
end
always @(posedge clk) begin
if (fifo_wr_en) begin
fifo_select[fifo_wr_ptr_reg[FIFO_ADDR_WIDTH-1:0]] <= fifo_wr_select;
fifo_decerr[fifo_wr_ptr_reg[FIFO_ADDR_WIDTH-1:0]] <= fifo_wr_decerr;
fifo_wr_ptr_reg <= fifo_wr_ptr_reg + 1;
end
if (fifo_rd_en) begin
fifo_rd_ptr_reg <= fifo_rd_ptr_reg + 1;
end
fifo_half_full_reg <= $unsigned(fifo_wr_ptr_reg - fifo_rd_ptr_reg) >= 2**(FIFO_ADDR_WIDTH-1);
if (rst) begin
fifo_wr_ptr_reg <= 0;
fifo_rd_ptr_reg <= 0;
end
end
// address decode and admission control
wire [CL_M_COUNT-1:0] a_select;
wire m_axil_avalid;
wire m_axil_aready;
wire [CL_M_COUNT-1:0] m_wc_select;
wire m_wc_decerr;
wire m_wc_valid;
wire m_wc_ready;
wire [CL_M_COUNT-1:0] m_rc_select;
wire m_rc_decerr;
wire m_rc_valid;
wire m_rc_ready;
axil_crossbar_addr #(
.S(m),
.S_COUNT(S_COUNT),
.M_COUNT(M_COUNT),
.ADDR_WIDTH(ADDR_WIDTH),
.M_REGIONS(M_REGIONS),
.M_BASE_ADDR(M_BASE_ADDR),
.M_ADDR_WIDTH(M_ADDR_WIDTH),
.M_CONNECT(M_CONNECT),
.M_SECURE(M_SECURE),
.WC_OUTPUT(1)
)
addr_inst (
.clk(clk),
.rst(rst),
/*
* Address input
*/
.s_axil_aaddr(int_s_axil_awaddr[m*ADDR_WIDTH +: ADDR_WIDTH]),
.s_axil_aprot(int_s_axil_awprot[m*3 +: 3]),
.s_axil_avalid(int_s_axil_awvalid[m]),
.s_axil_aready(int_s_axil_awready[m]),
/*
* Address output
*/
.m_select(a_select),
.m_axil_avalid(m_axil_avalid),
.m_axil_aready(m_axil_aready),
/*
* Write command output
*/
.m_wc_select(m_wc_select),
.m_wc_decerr(m_wc_decerr),
.m_wc_valid(m_wc_valid),
.m_wc_ready(m_wc_ready),
/*
* Response command output
*/
.m_rc_select(m_rc_select),
.m_rc_decerr(m_rc_decerr),
.m_rc_valid(m_rc_valid),
.m_rc_ready(m_rc_ready)
);
assign int_axil_awvalid[m*M_COUNT +: M_COUNT] = m_axil_avalid << a_select;
assign m_axil_aready = int_axil_awready[a_select*S_COUNT+m];
// write command handling
reg [CL_M_COUNT-1:0] w_select_reg = 0, w_select_next;
reg w_drop_reg = 1'b0, w_drop_next;
reg w_select_valid_reg = 1'b0, w_select_valid_next;
assign m_wc_ready = !w_select_valid_reg;
always @* begin
w_select_next = w_select_reg;
w_drop_next = w_drop_reg && !(int_s_axil_wvalid[m] && int_s_axil_wready[m]);
w_select_valid_next = w_select_valid_reg && !(int_s_axil_wvalid[m] && int_s_axil_wready[m]);
if (m_wc_valid && !w_select_valid_reg) begin
w_select_next = m_wc_select;
w_drop_next = m_wc_decerr;
w_select_valid_next = m_wc_valid;
end
end
always @(posedge clk) begin
if (rst) begin
w_select_valid_reg <= 1'b0;
end else begin
w_select_valid_reg <= w_select_valid_next;
end
w_select_reg <= w_select_next;
w_drop_reg <= w_drop_next;
end
// write data forwarding
assign int_axil_wvalid[m*M_COUNT +: M_COUNT] = (int_s_axil_wvalid[m] && w_select_valid_reg && !w_drop_reg) << w_select_reg;
assign int_s_axil_wready[m] = int_axil_wready[w_select_reg*S_COUNT+m] || w_drop_reg;
// response handling
assign fifo_wr_select = m_rc_select;
assign fifo_wr_decerr = m_rc_decerr;
assign fifo_wr_en = m_rc_valid && !fifo_half_full_reg;
assign m_rc_ready = !fifo_half_full_reg;
// write response handling
wire [CL_M_COUNT-1:0] b_select = M_COUNT > 1 ? fifo_select[fifo_rd_ptr_reg[FIFO_ADDR_WIDTH-1:0]] : 0;
wire b_decerr = fifo_decerr[fifo_rd_ptr_reg[FIFO_ADDR_WIDTH-1:0]];
wire b_valid = !fifo_empty;
// write response mux
wire [1:0] m_axil_bresp_mux = b_decerr ? 2'b11 : int_m_axil_bresp[b_select*2 +: 2];
wire m_axil_bvalid_mux = (b_decerr ? 1'b1 : int_axil_bvalid[b_select*S_COUNT+m]) && b_valid;
wire m_axil_bready_mux;
assign int_axil_bready[m*M_COUNT +: M_COUNT] = (b_valid && m_axil_bready_mux) << b_select;
assign fifo_rd_en = m_axil_bvalid_mux && m_axil_bready_mux && b_valid;
// S side register
axil_register_wr #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.AW_REG_TYPE(S_AW_REG_TYPE[m*2 +: 2]),
.W_REG_TYPE(S_W_REG_TYPE[m*2 +: 2]),
.B_REG_TYPE(S_B_REG_TYPE[m*2 +: 2])
)
reg_inst (
.clk(clk),
.rst(rst),
.s_axil_awaddr(s_axil_awaddr[m*ADDR_WIDTH +: ADDR_WIDTH]),
.s_axil_awprot(s_axil_awprot[m*3 +: 3]),
.s_axil_awvalid(s_axil_awvalid[m]),
.s_axil_awready(s_axil_awready[m]),
.s_axil_wdata(s_axil_wdata[m*DATA_WIDTH +: DATA_WIDTH]),
.s_axil_wstrb(s_axil_wstrb[m*STRB_WIDTH +: STRB_WIDTH]),
.s_axil_wvalid(s_axil_wvalid[m]),
.s_axil_wready(s_axil_wready[m]),
.s_axil_bresp(s_axil_bresp[m*2 +: 2]),
.s_axil_bvalid(s_axil_bvalid[m]),
.s_axil_bready(s_axil_bready[m]),
.m_axil_awaddr(int_s_axil_awaddr[m*ADDR_WIDTH +: ADDR_WIDTH]),
.m_axil_awprot(int_s_axil_awprot[m*3 +: 3]),
.m_axil_awvalid(int_s_axil_awvalid[m]),
.m_axil_awready(int_s_axil_awready[m]),
.m_axil_wdata(int_s_axil_wdata[m*DATA_WIDTH +: DATA_WIDTH]),
.m_axil_wstrb(int_s_axil_wstrb[m*STRB_WIDTH +: STRB_WIDTH]),
.m_axil_wvalid(int_s_axil_wvalid[m]),
.m_axil_wready(int_s_axil_wready[m]),
.m_axil_bresp(m_axil_bresp_mux),
.m_axil_bvalid(m_axil_bvalid_mux),
.m_axil_bready(m_axil_bready_mux)
);
end // s_ifaces
for (n = 0; n < M_COUNT; n = n + 1) begin : m_ifaces
// response routing FIFO
localparam FIFO_ADDR_WIDTH = $clog2(M_ISSUE[n*32 +: 32])+1;
reg [FIFO_ADDR_WIDTH+1-1:0] fifo_wr_ptr_reg = 0;
reg [FIFO_ADDR_WIDTH+1-1:0] fifo_rd_ptr_reg = 0;
reg [CL_S_COUNT-1:0] fifo_select[(2**FIFO_ADDR_WIDTH)-1:0];
wire [CL_S_COUNT-1:0] fifo_wr_select;
wire fifo_wr_en;
wire fifo_rd_en;
reg fifo_half_full_reg = 1'b0;
wire fifo_empty = fifo_rd_ptr_reg == fifo_wr_ptr_reg;
integer i;
initial begin
for (i = 0; i < 2**FIFO_ADDR_WIDTH; i = i + 1) begin
fifo_select[i] = 0;
end
end
always @(posedge clk) begin
if (fifo_wr_en) begin
fifo_select[fifo_wr_ptr_reg[FIFO_ADDR_WIDTH-1:0]] <= fifo_wr_select;
fifo_wr_ptr_reg <= fifo_wr_ptr_reg + 1;
end
if (fifo_rd_en) begin
fifo_rd_ptr_reg <= fifo_rd_ptr_reg + 1;
end
fifo_half_full_reg <= $unsigned(fifo_wr_ptr_reg - fifo_rd_ptr_reg) >= 2**(FIFO_ADDR_WIDTH-1);
if (rst) begin
fifo_wr_ptr_reg <= 0;
fifo_rd_ptr_reg <= 0;
end
end
// address arbitration
reg [CL_S_COUNT-1:0] w_select_reg = 0, w_select_next = 0;
reg w_select_valid_reg = 1'b0, w_select_valid_next;
reg w_select_new_reg = 1'b0, w_select_new_next;
wire [S_COUNT-1:0] a_request;
wire [S_COUNT-1:0] a_acknowledge;
wire [S_COUNT-1:0] a_grant;
wire a_grant_valid;
wire [CL_S_COUNT-1:0] a_grant_encoded;
arbiter #(
.PORTS(S_COUNT),
.ARB_TYPE_ROUND_ROBIN(1),
.ARB_BLOCK(1),
.ARB_BLOCK_ACK(1),
.ARB_LSB_HIGH_PRIORITY(1)
)
a_arb_inst (
.clk(clk),
.rst(rst),
.request(a_request),
.acknowledge(a_acknowledge),
.grant(a_grant),
.grant_valid(a_grant_valid),
.grant_encoded(a_grant_encoded)
);
// address mux
wire [ADDR_WIDTH-1:0] s_axil_awaddr_mux = int_s_axil_awaddr[a_grant_encoded*ADDR_WIDTH +: ADDR_WIDTH];
wire [2:0] s_axil_awprot_mux = int_s_axil_awprot[a_grant_encoded*3 +: 3];
wire s_axil_awvalid_mux = int_axil_awvalid[a_grant_encoded*M_COUNT+n] && a_grant_valid;
wire s_axil_awready_mux;
assign int_axil_awready[n*S_COUNT +: S_COUNT] = (a_grant_valid && s_axil_awready_mux) << a_grant_encoded;
for (m = 0; m < S_COUNT; m = m + 1) begin
assign a_request[m] = int_axil_awvalid[m*M_COUNT+n] && !a_grant[m] && !fifo_half_full_reg && !w_select_valid_next;
assign a_acknowledge[m] = a_grant[m] && int_axil_awvalid[m*M_COUNT+n] && s_axil_awready_mux;
end
assign fifo_wr_select = a_grant_encoded;
assign fifo_wr_en = s_axil_awvalid_mux && s_axil_awready_mux && a_grant_valid;
// write data mux
wire [DATA_WIDTH-1:0] s_axil_wdata_mux = int_s_axil_wdata[w_select_reg*DATA_WIDTH +: DATA_WIDTH];
wire [STRB_WIDTH-1:0] s_axil_wstrb_mux = int_s_axil_wstrb[w_select_reg*STRB_WIDTH +: STRB_WIDTH];
wire s_axil_wvalid_mux = int_axil_wvalid[w_select_reg*M_COUNT+n] && w_select_valid_reg;
wire s_axil_wready_mux;
assign int_axil_wready[n*S_COUNT +: S_COUNT] = (w_select_valid_reg && s_axil_wready_mux) << w_select_reg;
// write data routing
always @* begin
w_select_next = w_select_reg;
w_select_valid_next = w_select_valid_reg && !(s_axil_wvalid_mux && s_axil_wready_mux);
w_select_new_next = w_select_new_reg || !a_grant_valid || a_acknowledge;
if (a_grant_valid && !w_select_valid_reg && w_select_new_reg) begin
w_select_next = a_grant_encoded;
w_select_valid_next = a_grant_valid;
w_select_new_next = 1'b0;
end
end
always @(posedge clk) begin
if (rst) begin
w_select_valid_reg <= 1'b0;
w_select_new_reg <= 1'b1;
end else begin
w_select_valid_reg <= w_select_valid_next;
w_select_new_reg <= w_select_new_next;
end
w_select_reg <= w_select_next;
end
// write response forwarding
wire [CL_S_COUNT-1:0] b_select = S_COUNT > 1 ? fifo_select[fifo_rd_ptr_reg[FIFO_ADDR_WIDTH-1:0]] : 0;
assign int_axil_bvalid[n*S_COUNT +: S_COUNT] = int_m_axil_bvalid[n] << b_select;
assign int_m_axil_bready[n] = int_axil_bready[b_select*M_COUNT+n];
assign fifo_rd_en = int_m_axil_bvalid[n] && int_m_axil_bready[n];
// M side register
axil_register_wr #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.AW_REG_TYPE(M_AW_REG_TYPE[n*2 +: 2]),
.W_REG_TYPE(M_W_REG_TYPE[n*2 +: 2]),
.B_REG_TYPE(M_B_REG_TYPE[n*2 +: 2])
)
reg_inst (
.clk(clk),
.rst(rst),
.s_axil_awaddr(s_axil_awaddr_mux),
.s_axil_awprot(s_axil_awprot_mux),
.s_axil_awvalid(s_axil_awvalid_mux),
.s_axil_awready(s_axil_awready_mux),
.s_axil_wdata(s_axil_wdata_mux),
.s_axil_wstrb(s_axil_wstrb_mux),
.s_axil_wvalid(s_axil_wvalid_mux),
.s_axil_wready(s_axil_wready_mux),
.s_axil_bresp(int_m_axil_bresp[n*2 +: 2]),
.s_axil_bvalid(int_m_axil_bvalid[n]),
.s_axil_bready(int_m_axil_bready[n]),
.m_axil_awaddr(m_axil_awaddr[n*ADDR_WIDTH +: ADDR_WIDTH]),
.m_axil_awprot(m_axil_awprot[n*3 +: 3]),
.m_axil_awvalid(m_axil_awvalid[n]),
.m_axil_awready(m_axil_awready[n]),
.m_axil_wdata(m_axil_wdata[n*DATA_WIDTH +: DATA_WIDTH]),
.m_axil_wstrb(m_axil_wstrb[n*STRB_WIDTH +: STRB_WIDTH]),
.m_axil_wvalid(m_axil_wvalid[n]),
.m_axil_wready(m_axil_wready[n]),
.m_axil_bresp(m_axil_bresp[n*2 +: 2]),
.m_axil_bvalid(m_axil_bvalid[n]),
.m_axil_bready(m_axil_bready[n])
);
end // m_ifaces
endgenerate
endmodule

View File

@ -0,0 +1,312 @@
#!/usr/bin/env python
"""
Generates an AXI lite crossbar wrapper with the specified number of ports
"""
import argparse
from jinja2 import Template
def main():
parser = argparse.ArgumentParser(description=__doc__.strip())
parser.add_argument('-p', '--ports', type=int, default=[4], nargs='+', help="number of ports")
parser.add_argument('-n', '--name', type=str, help="module name")
parser.add_argument('-o', '--output', type=str, help="output file name")
args = parser.parse_args()
try:
generate(**args.__dict__)
except IOError as ex:
print(ex)
exit(1)
def generate(ports=4, name=None, output=None):
if type(ports) is int:
m = n = ports
elif len(ports) == 1:
m = n = ports[0]
else:
m, n = ports
if name is None:
name = "axil_crossbar_wrap_{0}x{1}".format(m, n)
if output is None:
output = name + ".v"
print("Generating {0}x{1} port AXI lite crossbar wrapper {2}...".format(m, n, name))
cm = (m-1).bit_length()
cn = (n-1).bit_length()
t = Template(u"""/*
Copyright (c) 2021 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* AXI4 lite {{m}}x{{n}} crossbar (wrapper)
*/
module {{name}} #
(
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 32,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
{%- for p in range(m) %}
// Number of concurrent operations
parameter S{{'%02d'%p}}_ACCEPT = 16,
{%- endfor %}
// Number of regions per master interface
parameter M_REGIONS = 1,
{%- for p in range(n) %}
// Master interface base addresses
// M_REGIONS concatenated fields of ADDR_WIDTH bits
parameter M{{'%02d'%p}}_BASE_ADDR = 0,
// Master interface address widths
// M_REGIONS concatenated fields of 32 bits
parameter M{{'%02d'%p}}_ADDR_WIDTH = {M_REGIONS{32'd24}},
// Read connections between interfaces
// S_COUNT bits
parameter M{{'%02d'%p}}_CONNECT_READ = {{m}}'b{% for p in range(m) %}1{% endfor %},
// Write connections between interfaces
// S_COUNT bits
parameter M{{'%02d'%p}}_CONNECT_WRITE = {{m}}'b{% for p in range(m) %}1{% endfor %},
// Number of concurrent operations for each master interface
parameter M{{'%02d'%p}}_ISSUE = 16,
// Secure master (fail operations based on awprot/arprot)
parameter M{{'%02d'%p}}_SECURE = 0,
{%- endfor %}
{%- for p in range(m) %}
// Slave interface AW channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S{{'%02d'%p}}_AW_REG_TYPE = 0,
// Slave interface W channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S{{'%02d'%p}}_W_REG_TYPE = 0,
// Slave interface B channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S{{'%02d'%p}}_B_REG_TYPE = 1,
// Slave interface AR channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S{{'%02d'%p}}_AR_REG_TYPE = 0,
// Slave interface R channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S{{'%02d'%p}}_R_REG_TYPE = 2,
{%- endfor %}
{%- for p in range(n) %}
// Master interface AW channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M{{'%02d'%p}}_AW_REG_TYPE = 1,
// Master interface W channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M{{'%02d'%p}}_W_REG_TYPE = 2,
// Master interface B channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M{{'%02d'%p}}_B_REG_TYPE = 0,
// Master interface AR channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M{{'%02d'%p}}_AR_REG_TYPE = 1,
// Master interface R channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M{{'%02d'%p}}_R_REG_TYPE = 0{% if not loop.last %},{% endif %}
{%- endfor %}
)
(
input wire clk,
input wire rst,
/*
* AXI lite slave interfaces
*/
{%- for p in range(m) %}
input wire [ADDR_WIDTH-1:0] s{{'%02d'%p}}_axil_awaddr,
input wire [2:0] s{{'%02d'%p}}_axil_awprot,
input wire s{{'%02d'%p}}_axil_awvalid,
output wire s{{'%02d'%p}}_axil_awready,
input wire [DATA_WIDTH-1:0] s{{'%02d'%p}}_axil_wdata,
input wire [STRB_WIDTH-1:0] s{{'%02d'%p}}_axil_wstrb,
input wire s{{'%02d'%p}}_axil_wvalid,
output wire s{{'%02d'%p}}_axil_wready,
output wire [1:0] s{{'%02d'%p}}_axil_bresp,
output wire s{{'%02d'%p}}_axil_bvalid,
input wire s{{'%02d'%p}}_axil_bready,
input wire [ADDR_WIDTH-1:0] s{{'%02d'%p}}_axil_araddr,
input wire [2:0] s{{'%02d'%p}}_axil_arprot,
input wire s{{'%02d'%p}}_axil_arvalid,
output wire s{{'%02d'%p}}_axil_arready,
output wire [DATA_WIDTH-1:0] s{{'%02d'%p}}_axil_rdata,
output wire [1:0] s{{'%02d'%p}}_axil_rresp,
output wire s{{'%02d'%p}}_axil_rvalid,
input wire s{{'%02d'%p}}_axil_rready,
{% endfor %}
/*
* AXI lite master interfaces
*/
{%- for p in range(n) %}
output wire [ADDR_WIDTH-1:0] m{{'%02d'%p}}_axil_awaddr,
output wire [2:0] m{{'%02d'%p}}_axil_awprot,
output wire m{{'%02d'%p}}_axil_awvalid,
input wire m{{'%02d'%p}}_axil_awready,
output wire [DATA_WIDTH-1:0] m{{'%02d'%p}}_axil_wdata,
output wire [STRB_WIDTH-1:0] m{{'%02d'%p}}_axil_wstrb,
output wire m{{'%02d'%p}}_axil_wvalid,
input wire m{{'%02d'%p}}_axil_wready,
input wire [1:0] m{{'%02d'%p}}_axil_bresp,
input wire m{{'%02d'%p}}_axil_bvalid,
output wire m{{'%02d'%p}}_axil_bready,
output wire [ADDR_WIDTH-1:0] m{{'%02d'%p}}_axil_araddr,
output wire [2:0] m{{'%02d'%p}}_axil_arprot,
output wire m{{'%02d'%p}}_axil_arvalid,
input wire m{{'%02d'%p}}_axil_arready,
input wire [DATA_WIDTH-1:0] m{{'%02d'%p}}_axil_rdata,
input wire [1:0] m{{'%02d'%p}}_axil_rresp,
input wire m{{'%02d'%p}}_axil_rvalid,
output wire m{{'%02d'%p}}_axil_rready{% if not loop.last %},{% endif %}
{% endfor -%}
);
localparam S_COUNT = {{m}};
localparam M_COUNT = {{n}};
// parameter sizing helpers
function [ADDR_WIDTH*M_REGIONS-1:0] w_a_r(input [ADDR_WIDTH*M_REGIONS-1:0] val);
w_a_r = val;
endfunction
function [32*M_REGIONS-1:0] w_32_r(input [32*M_REGIONS-1:0] val);
w_32_r = val;
endfunction
function [S_COUNT-1:0] w_s(input [S_COUNT-1:0] val);
w_s = val;
endfunction
function [31:0] w_32(input [31:0] val);
w_32 = val;
endfunction
function [1:0] w_2(input [1:0] val);
w_2 = val;
endfunction
function w_1(input val);
w_1 = val;
endfunction
axil_crossbar #(
.S_COUNT(S_COUNT),
.M_COUNT(M_COUNT),
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.S_ACCEPT({ {% for p in range(m-1,-1,-1) %}w_32(S{{'%02d'%p}}_ACCEPT){% if not loop.last %}, {% endif %}{% endfor %} }),
.M_REGIONS(M_REGIONS),
.M_BASE_ADDR({ {% for p in range(n-1,-1,-1) %}w_a_r(M{{'%02d'%p}}_BASE_ADDR){% if not loop.last %}, {% endif %}{% endfor %} }),
.M_ADDR_WIDTH({ {% for p in range(n-1,-1,-1) %}w_32_r(M{{'%02d'%p}}_ADDR_WIDTH){% if not loop.last %}, {% endif %}{% endfor %} }),
.M_CONNECT_READ({ {% for p in range(n-1,-1,-1) %}w_s(M{{'%02d'%p}}_CONNECT_READ){% if not loop.last %}, {% endif %}{% endfor %} }),
.M_CONNECT_WRITE({ {% for p in range(n-1,-1,-1) %}w_s(M{{'%02d'%p}}_CONNECT_WRITE){% if not loop.last %}, {% endif %}{% endfor %} }),
.M_ISSUE({ {% for p in range(n-1,-1,-1) %}w_32(M{{'%02d'%p}}_ISSUE){% if not loop.last %}, {% endif %}{% endfor %} }),
.M_SECURE({ {% for p in range(n-1,-1,-1) %}w_1(M{{'%02d'%p}}_SECURE){% if not loop.last %}, {% endif %}{% endfor %} }),
.S_AR_REG_TYPE({ {% for p in range(m-1,-1,-1) %}w_2(S{{'%02d'%p}}_AR_REG_TYPE){% if not loop.last %}, {% endif %}{% endfor %} }),
.S_R_REG_TYPE({ {% for p in range(m-1,-1,-1) %}w_2(S{{'%02d'%p}}_R_REG_TYPE){% if not loop.last %}, {% endif %}{% endfor %} }),
.S_AW_REG_TYPE({ {% for p in range(m-1,-1,-1) %}w_2(S{{'%02d'%p}}_AW_REG_TYPE){% if not loop.last %}, {% endif %}{% endfor %} }),
.S_W_REG_TYPE({ {% for p in range(m-1,-1,-1) %}w_2(S{{'%02d'%p}}_W_REG_TYPE){% if not loop.last %}, {% endif %}{% endfor %} }),
.S_B_REG_TYPE({ {% for p in range(m-1,-1,-1) %}w_2(S{{'%02d'%p}}_B_REG_TYPE){% if not loop.last %}, {% endif %}{% endfor %} }),
.M_AR_REG_TYPE({ {% for p in range(n-1,-1,-1) %}w_2(M{{'%02d'%p}}_AR_REG_TYPE){% if not loop.last %}, {% endif %}{% endfor %} }),
.M_R_REG_TYPE({ {% for p in range(n-1,-1,-1) %}w_2(M{{'%02d'%p}}_R_REG_TYPE){% if not loop.last %}, {% endif %}{% endfor %} }),
.M_AW_REG_TYPE({ {% for p in range(n-1,-1,-1) %}w_2(M{{'%02d'%p}}_AW_REG_TYPE){% if not loop.last %}, {% endif %}{% endfor %} }),
.M_W_REG_TYPE({ {% for p in range(n-1,-1,-1) %}w_2(M{{'%02d'%p}}_W_REG_TYPE){% if not loop.last %}, {% endif %}{% endfor %} }),
.M_B_REG_TYPE({ {% for p in range(n-1,-1,-1) %}w_2(M{{'%02d'%p}}_B_REG_TYPE){% if not loop.last %}, {% endif %}{% endfor %} })
)
axil_crossbar_inst (
.clk(clk),
.rst(rst),
.s_axil_awaddr({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_awaddr{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axil_awprot({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_awprot{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axil_awvalid({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_awvalid{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axil_awready({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_awready{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axil_wdata({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_wdata{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axil_wstrb({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_wstrb{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axil_wvalid({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_wvalid{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axil_wready({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_wready{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axil_bresp({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_bresp{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axil_bvalid({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_bvalid{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axil_bready({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_bready{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axil_araddr({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_araddr{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axil_arprot({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_arprot{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axil_arvalid({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_arvalid{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axil_arready({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_arready{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axil_rdata({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_rdata{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axil_rresp({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_rresp{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axil_rvalid({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_rvalid{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axil_rready({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axil_rready{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_awaddr({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_awaddr{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_awprot({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_awprot{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_awvalid({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_awvalid{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_awready({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_awready{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_wdata({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_wdata{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_wstrb({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_wstrb{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_wvalid({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_wvalid{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_wready({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_wready{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_bresp({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_bresp{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_bvalid({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_bvalid{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_bready({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_bready{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_araddr({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_araddr{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_arprot({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_arprot{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_arvalid({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_arvalid{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_arready({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_arready{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_rdata({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_rdata{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_rresp({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_rresp{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_rvalid({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_rvalid{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axil_rready({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axil_rready{% if not loop.last %}, {% endif %}{% endfor %} })
);
endmodule
""")
print(f"Writing file '{output}'...")
with open(output, 'w') as f:
f.write(t.render(
m=m,
n=n,
cm=cm,
cn=cn,
name=name
))
f.flush()
print("Done")
if __name__ == "__main__":
main()

View File

@ -42,7 +42,7 @@ DescBus, DescTransaction, DescSource, DescSink, DescMonitor = define_stream("Des
)
DescStatusBus, DescStatusTransaction, DescStatusSource, DescStatusSink, DescStatusMonitor = define_stream("DescStatus",
signals=["tag", "valid"]
signals=["tag", "error", "valid"]
)
@ -123,6 +123,7 @@ async def run_test(dut, data_in=None, idle_inserter=None, backpressure_inserter=
tb.log.info("status: %s", status)
assert int(status.tag) == cur_tag
assert int(status.error) == 0
tb.log.debug("%s", tb.axi_ram.hexdump_str((write_addr & ~0xf)-16, (((write_addr & 0xf)+length-1) & ~0xf)+48))
@ -156,7 +157,7 @@ rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
@pytest.mark.parametrize("unaligned", [0, 1])
@pytest.mark.parametrize("axi_data_width", [8, 16, 32])
def test_axi_dma(request, axi_data_width, unaligned):
def test_axi_cdma(request, axi_data_width, unaligned):
dut = "axi_cdma"
module = os.path.splitext(os.path.basename(__file__))[0]
toplevel = dut

View File

@ -45,7 +45,7 @@ DescBus, DescTransaction, DescSource, DescSink, DescMonitor = define_stream("Des
)
DescStatusBus, DescStatusTransaction, DescStatusSource, DescStatusSink, DescStatusMonitor = define_stream("DescStatus",
signals=["tag", "valid"],
signals=["tag", "error", "valid"],
optional_signals=["len", "id", "dest", "user"]
)
@ -144,6 +144,7 @@ async def run_test_write(dut, data_in=None, idle_inserter=None, backpressure_ins
assert int(status.len) == min(len(test_data), len(test_data2))
assert int(status.tag) == cur_tag
assert int(status.id) == cur_tag
assert int(status.error) == 0
tb.log.debug("%s", tb.axi_ram.hexdump_str((addr & ~0xf)-16, (((addr & 0xf)+length-1) & ~0xf)+48))
@ -197,6 +198,7 @@ async def run_test_read(dut, data_in=None, idle_inserter=None, backpressure_inse
tb.log.info("read_data: %s", read_data)
assert int(status.tag) == cur_tag
assert int(status.error) == 0
assert read_data.tdata == test_data
assert read_data.tid == cur_tag

View File

@ -44,7 +44,7 @@ DescBus, DescTransaction, DescSource, DescSink, DescMonitor = define_stream("Des
)
DescStatusBus, DescStatusTransaction, DescStatusSource, DescStatusSink, DescStatusMonitor = define_stream("DescStatus",
signals=["tag", "valid"],
signals=["tag", "error", "valid"],
optional_signals=["len", "id", "dest", "user"]
)
@ -129,6 +129,7 @@ async def run_test_read(dut, data_in=None, idle_inserter=None, backpressure_inse
tb.log.info("read_data: %s", read_data)
assert int(status.tag) == cur_tag
assert int(status.error) == 0
assert read_data.tdata == test_data
assert read_data.tid == cur_tag

View File

@ -44,7 +44,7 @@ DescBus, DescTransaction, DescSource, DescSink, DescMonitor = define_stream("Des
)
DescStatusBus, DescStatusTransaction, DescStatusSource, DescStatusSink, DescStatusMonitor = define_stream("DescStatus",
signals=["tag", "valid"],
signals=["tag", "error", "valid"],
optional_signals=["len", "id", "dest", "user"]
)
@ -132,6 +132,7 @@ async def run_test_write(dut, data_in=None, idle_inserter=None, backpressure_ins
assert int(status.len) == min(len(test_data), len(test_data2))
assert int(status.tag) == cur_tag
assert int(status.id) == cur_tag
assert int(status.error) == 0
tb.log.debug("%s", tb.axi_ram.hexdump_str((addr & ~0xf)-16, (((addr & 0xf)+length-1) & ~0xf)+48))

View File

@ -0,0 +1,93 @@
# Copyright (c) 2021 Alex Forencich
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
TOPLEVEL_LANG = verilog
SIM ?= icarus
WAVES ?= 0
COCOTB_HDL_TIMEUNIT = 1ns
COCOTB_HDL_TIMEPRECISION = 1ps
export PARAM_S_COUNT ?= 4
export PARAM_M_COUNT ?= 4
DUT = axil_crossbar
WRAPPER = $(DUT)_wrap_$(PARAM_S_COUNT)x$(PARAM_M_COUNT)
TOPLEVEL = $(WRAPPER)
MODULE = test_$(DUT)
VERILOG_SOURCES += $(WRAPPER).v
VERILOG_SOURCES += ../../rtl/$(DUT).v
VERILOG_SOURCES += ../../rtl/$(DUT)_addr.v
VERILOG_SOURCES += ../../rtl/$(DUT)_rd.v
VERILOG_SOURCES += ../../rtl/$(DUT)_wr.v
VERILOG_SOURCES += ../../rtl/axil_register_rd.v
VERILOG_SOURCES += ../../rtl/axil_register_wr.v
VERILOG_SOURCES += ../../rtl/arbiter.v
VERILOG_SOURCES += ../../rtl/priority_encoder.v
# module parameters
export PARAM_DATA_WIDTH ?= 32
export PARAM_ADDR_WIDTH ?= 32
export PARAM_STRB_WIDTH ?= $(shell expr $(PARAM_DATA_WIDTH) / 8 )
export PARAM_M_REGIONS ?= 1
ifeq ($(SIM), icarus)
PLUSARGS += -fst
COMPILE_ARGS += -P $(TOPLEVEL).DATA_WIDTH=$(PARAM_DATA_WIDTH)
COMPILE_ARGS += -P $(TOPLEVEL).ADDR_WIDTH=$(PARAM_ADDR_WIDTH)
COMPILE_ARGS += -P $(TOPLEVEL).STRB_WIDTH=$(PARAM_STRB_WIDTH)
COMPILE_ARGS += -P $(TOPLEVEL).M_REGIONS=$(PARAM_M_REGIONS)
ifeq ($(WAVES), 1)
VERILOG_SOURCES += iverilog_dump.v
COMPILE_ARGS += -s iverilog_dump
endif
else ifeq ($(SIM), verilator)
COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH
COMPILE_ARGS += -GDATA_WIDTH=$(PARAM_DATA_WIDTH)
COMPILE_ARGS += -GADDR_WIDTH=$(PARAM_ADDR_WIDTH)
COMPILE_ARGS += -GSTRB_WIDTH=$(PARAM_STRB_WIDTH)
COMPILE_ARGS += -GM_REGIONS=$(PARAM_M_REGIONS)
ifeq ($(WAVES), 1)
COMPILE_ARGS += --trace-fst
endif
endif
include $(shell cocotb-config --makefiles)/Makefile.sim
$(WRAPPER).v: ../../rtl/$(DUT)_wrap.py
$< -p $(PARAM_S_COUNT) $(PARAM_M_COUNT)
iverilog_dump.v:
echo 'module iverilog_dump();' > $@
echo 'initial begin' >> $@
echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@
echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@
echo 'end' >> $@
echo 'endmodule' >> $@
clean::
@rm -rf iverilog_dump.v
@rm -rf dump.fst $(TOPLEVEL).fst
@rm -rf *_wrap_*.v

View File

@ -0,0 +1,266 @@
"""
Copyright (c) 2021 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
import itertools
import logging
import os
import random
import subprocess
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 AxiLiteBus, AxiLiteMaster, AxiLiteRam
class TB(object):
def __init__(self, dut):
self.dut = dut
s_count = len(dut.axil_crossbar_inst.s_axil_awvalid)
m_count = len(dut.axil_crossbar_inst.m_axil_awvalid)
self.log = logging.getLogger("cocotb.tb")
self.log.setLevel(logging.DEBUG)
cocotb.fork(Clock(dut.clk, 10, units="ns").start())
self.axil_master = [AxiLiteMaster(AxiLiteBus.from_prefix(dut, f"s{k:02d}_axil"), dut.clk, dut.rst) for k in range(s_count)]
self.axil_ram = [AxiLiteRam(AxiLiteBus.from_prefix(dut, f"m{k:02d}_axil"), dut.clk, dut.rst, size=2**16) for k in range(m_count)]
def set_idle_generator(self, generator=None):
if generator:
for master in self.axil_master:
master.write_if.aw_channel.set_pause_generator(generator())
master.write_if.w_channel.set_pause_generator(generator())
master.read_if.ar_channel.set_pause_generator(generator())
for ram in self.axil_ram:
ram.write_if.b_channel.set_pause_generator(generator())
ram.read_if.r_channel.set_pause_generator(generator())
def set_backpressure_generator(self, generator=None):
if generator:
for master in self.axil_master:
master.write_if.b_channel.set_pause_generator(generator())
master.read_if.r_channel.set_pause_generator(generator())
for ram in self.axil_ram:
ram.write_if.aw_channel.set_pause_generator(generator())
ram.write_if.w_channel.set_pause_generator(generator())
ram.read_if.ar_channel.set_pause_generator(generator())
async def cycle_reset(self):
self.dut.rst.setimmediatevalue(0)
await RisingEdge(self.dut.clk)
await RisingEdge(self.dut.clk)
self.dut.rst <= 1
await RisingEdge(self.dut.clk)
await RisingEdge(self.dut.clk)
self.dut.rst <= 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, s=0, m=0):
tb = TB(dut)
byte_lanes = tb.axil_master[s].write_if.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.axil_ram[m].write(ram_addr-128, b'\xaa'*(length+256))
await tb.axil_master[s].write(addr, test_data)
tb.log.debug("%s", tb.axil_ram[m].hexdump_str((ram_addr & ~0xf)-16, (((ram_addr & 0xf)+length-1) & ~0xf)+48))
assert tb.axil_ram[m].read(ram_addr, length) == test_data
assert tb.axil_ram[m].read(ram_addr-1, 1) == b'\xaa'
assert tb.axil_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, s=0, m=0):
tb = TB(dut)
byte_lanes = tb.axil_master[s].write_if.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.axil_ram[m].write(ram_addr, test_data)
data = await tb.axil_master[s].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.axil_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.fork(worker(tb.axil_master[k % len(tb.axil_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 cocotb.SIM_NAME:
s_count = len(cocotb.top.axil_crossbar_inst.s_axil_awvalid)
m_count = len(cocotb.top.axil_crossbar_inst.m_axil_awvalid)
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("s", range(min(s_count, 2)))
factory.add_option("m", range(min(m_count, 2)))
factory.generate_tests()
factory = TestFactory(run_stress_test)
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'))
@pytest.mark.parametrize("data_width", [8, 16, 32])
@pytest.mark.parametrize("m_count", [1, 4])
@pytest.mark.parametrize("s_count", [1, 4])
def test_axil_crossbar(request, s_count, m_count, data_width):
dut = "axil_crossbar"
wrapper = f"{dut}_wrap_{s_count}x{m_count}"
module = os.path.splitext(os.path.basename(__file__))[0]
toplevel = wrapper
# generate wrapper
wrapper_file = os.path.join(tests_dir, f"{wrapper}.v")
if not os.path.exists(wrapper_file):
subprocess.Popen(
[os.path.join(rtl_dir, f"{dut}_wrap.py"), "-p", f"{s_count}", f"{m_count}"],
cwd=tests_dir
).wait()
verilog_sources = [
wrapper_file,
os.path.join(rtl_dir, f"{dut}.v"),
os.path.join(rtl_dir, f"{dut}_addr.v"),
os.path.join(rtl_dir, f"{dut}_rd.v"),
os.path.join(rtl_dir, f"{dut}_wr.v"),
os.path.join(rtl_dir, "axil_register_rd.v"),
os.path.join(rtl_dir, "axil_register_wr.v"),
os.path.join(rtl_dir, "arbiter.v"),
os.path.join(rtl_dir, "priority_encoder.v"),
]
parameters = {}
parameters['S_COUNT'] = s_count
parameters['M_COUNT'] = m_count
parameters['DATA_WIDTH'] = data_width
parameters['ADDR_WIDTH'] = 32
parameters['STRB_WIDTH'] = parameters['DATA_WIDTH'] // 8
parameters['M_REGIONS'] = 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(
python_search=[tests_dir],
verilog_sources=verilog_sources,
toplevel=toplevel,
module=module,
parameters=parameters,
sim_build=sim_build,
extra_env=extra_env,
)