83f22d174506c23a9a79f82ac8c94a600a38c895
1 """Simple GPIO peripheral on wishbone
3 This is an extremely simple GPIO peripheral intended for use in XICS
4 testing, however it could also be used as an actual GPIO peripheral
6 Modified for use with pinmux, will probably change the class name later.
8 from random
import randint
, shuffle
9 #from math import ceil, floor
10 from nmigen
import Elaboratable
, Module
, Signal
, Record
, Array
, Cat
11 from nmigen
.hdl
.rec
import Layout
12 from nmigen
.utils
import log2_int
13 from nmigen
.cli
import rtlil
14 #from soc.minerva.wishbone import make_wb_layout
15 from nmutil
.util
import wrap
16 #from soc.bus.test.wb_rw import wb_read, wb_write
18 from nmutil
.gtkw
import write_gtkw
22 from nmigen
.sim
.cxxsim
import Simulator
, Settle
, Delay
24 from nmigen
.sim
import Simulator
, Settle
, Delay
26 io_layout
= (("i", 1),
31 class IOMuxBlockSingle(Elaboratable
):
33 def __init__(self
, n_banks
=4):
34 print("1-bit IO Mux Block")
35 self
.n_banks
= n_banks
36 self
.bank
= Signal(log2_int(self
.n_banks
))
39 for i
in range(self
.n_banks
):
41 temp
.append(Record(name
=name
, layout
=io_layout
))
42 self
.bank_ports
= Array(temp
)
44 self
.out_port
= Record(name
="IO", layout
=io_layout
)
46 def elaborate(self
, platform
):
48 comb
, sync
= m
.d
.comb
, m
.d
.sync
51 bank_ports
= self
.bank_ports
52 out_port
= self
.out_port
54 # Connect IO Pad output port to one of the peripheral IOs
55 # Connect peripheral inputs to the IO pad input
56 comb
+= self
.out_port
.o
.eq(self
.bank_ports
[bank
].o
)
57 comb
+= self
.out_port
.oe
.eq(self
.bank_ports
[bank
].oe
)
59 comb
+= self
.bank_ports
[bank
].i
.eq(self
.out_port
.i
)
63 def connect_bank_to_io(self
, domain
, bank_arg
):
64 domain
+= self
.out_port
.o
.eq(self
.bank_ports
[bank_arg
].o
)
65 domain
+= self
.out_port
.oe
.eq(self
.bank_ports
[bank_arg
].oe
)
66 domain
+= self
.bank_ports
[bank_arg
].i
.eq(self
.out_port
.i
)
69 """ Get member signals for Verilog form. """
70 for field
in self
.out_port
.fields
.values():
72 for bank
in range(self
.n_banks
):
73 for field
in self
.bank_ports
[bank
].fields
.values():
80 # Method to test a particular bank port
81 # when rand_order is True, previous and consecutive banks are
82 # random (but NOT equal to given bank)
83 def test_single_bank(dut
, bank
, rand_order
=True, delay
=1e-6):
85 print("Randomising the prev and next banks")
87 while(prev_bank
== bank
):
88 prev_bank
= randint(0, dut
.n_banks
-1)
90 while(next_bank
== bank
):
91 next_bank
= randint(0, dut
.n_banks
-1)
93 # Set the prev and next banks as consecutive banks
95 prev_bank
= dut
.n_banks
- 1
99 if bank
== dut
.n_banks
:
104 print("Prev=%d, Given=%d, Next=%d" % (prev_bank
, bank
, next_bank
))
106 # Clear o/oe, delay, set port i
107 # Set to previous bank, delay
109 # Set to desired bank
113 # Set to next bank, delay
115 yield dut
.bank_ports
[bank
].o
.eq(0)
117 yield dut
.bank_ports
[bank
].oe
.eq(0)
119 yield dut
.out_port
.i
.eq(1)
122 yield dut
.bank
.eq(prev_bank
)
125 test_i
= yield dut
.bank_ports
[bank
].i
128 yield dut
.bank
.eq(bank
)
131 test_o
= yield dut
.out_port
.o
132 test_oe
= yield dut
.out_port
.oe
133 test_i
= yield dut
.bank_ports
[bank
].i
138 yield dut
.bank_ports
[bank
].o
.eq(1)
140 yield dut
.bank_ports
[bank
].oe
.eq(1)
143 test_o
= yield dut
.out_port
.o
144 test_oe
= yield dut
.out_port
.oe
148 yield dut
.bank
.eq(next_bank
)
151 test_i
= yield dut
.bank_ports
[bank
].i
154 def test_iomux(dut
, rand_order
=True):
155 print("------START----------------------")
156 #print(dir(dut.bank_ports[0]))
157 #print(dut.bank_ports[0].fields)
159 # Produce a test list of bank values
160 test_bank_vec
= list(range(0, dut
.n_banks
))
161 #print(test_bank_vec)
162 # Randomise for wider testing
164 shuffle(test_bank_vec
)
165 #print(test_bank_vec)
166 for i
in range(dut
.n_banks
):
167 yield from test_single_bank(dut
, test_bank_vec
[i
], rand_order
)
169 print("Finished the 1-bit IO mux block test!")
171 def gen_gtkw_doc(module_name
, n_banks
, filename
):
172 # GTKWave doc generation
175 'in': {'color': 'orange'},
176 'out': {'color': 'yellow'},
177 'debug': {'module': 'top', 'color': 'red'}
180 # Create a trace list, each block expected to be a tuple()
182 for bank
in range(0, n_banks
):
183 temp_traces
= ('Bank%d' % bank
, [
184 ('bank%d__i' % bank
, 'in'),
185 ('bank%d__o' % bank
, 'out'),
186 ('bank%d__oe' % bank
, 'out')
188 traces
.append(temp_traces
)
190 temp_traces
= ('Misc', [
191 ('bank[%d:0]' % ((n_banks
-1).bit_length()-1), 'in')
193 traces
.append(temp_traces
)
194 temp_traces
= ('IO port to pad', [
199 traces
.append(temp_traces
)
202 write_gtkw(filename
+".gtkw", filename
+".vcd", traces
, style
,
205 def sim_iomux(rand_order
=True):
206 filename
= "test_iomux" # Doesn't include extension
208 dut
= IOMuxBlockSingle(n_banks
)
209 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
210 with
open(filename
+".il", "w") as f
:
214 m
.submodules
.pinmux
= dut
218 sim
.add_process(wrap(test_iomux(dut
, rand_order
)))
219 sim_writer
= sim
.write_vcd(filename
+".vcd")
223 gen_gtkw_doc("top.pinmux", dut
.n_banks
, filename
)
227 if __name__
== '__main__':
228 sim_iomux(rand_order
=True)