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:
commit
07292b7dda
@ -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
|
||||
|
@ -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
|
||||
]
|
||||
]
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
247
fpga/lib/axi/rtl/axil_crossbar.v
Normal file
247
fpga/lib/axi/rtl/axil_crossbar.v
Normal 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
|
263
fpga/lib/axi/rtl/axil_crossbar_addr.v
Normal file
263
fpga/lib/axi/rtl/axil_crossbar_addr.v
Normal 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
|
421
fpga/lib/axi/rtl/axil_crossbar_rd.v
Normal file
421
fpga/lib/axi/rtl/axil_crossbar_rd.v
Normal 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
|
529
fpga/lib/axi/rtl/axil_crossbar_wr.v
Normal file
529
fpga/lib/axi/rtl/axil_crossbar_wr.v
Normal 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
|
312
fpga/lib/axi/rtl/axil_crossbar_wrap.py
Executable file
312
fpga/lib/axi/rtl/axil_crossbar_wrap.py
Executable 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()
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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))
|
||||
|
||||
|
93
fpga/lib/axi/tb/axil_crossbar/Makefile
Normal file
93
fpga/lib/axi/tb/axil_crossbar/Makefile
Normal 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
|
266
fpga/lib/axi/tb/axil_crossbar/test_axil_crossbar.py
Normal file
266
fpga/lib/axi/tb/axil_crossbar/test_axil_crossbar.py
Normal 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,
|
||||
)
|
Loading…
x
Reference in New Issue
Block a user