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 # This block produces an N-to-1 mux with N 3-bit periph ports and one pad port.
32 # The peripheral ports are intended to be wired to peripheral functions,
33 # while the pad port will connect to the I/O pad.
34 # Peripheral and output ports have o/oe/i signals, and the port signal is used
35 # to select between the peripheral ports.
36 class IOMuxBlockSingle(Elaboratable
):
38 def __init__(self
, n_ports
=4):
39 print("1-bit IO Mux Block")
40 self
.n_ports
= n_ports
41 portsize
= n_ports
.bit_length()
42 self
.port
= Signal(portsize
)
45 for i
in range(self
.n_ports
):
47 temp
.append(Record(name
=name
, layout
=io_layout
))
48 self
.periph_ports
= Array(temp
)
50 self
.out_port
= Record(name
="IO", layout
=io_layout
)
52 def elaborate(self
, platform
):
54 comb
, sync
= m
.d
.comb
, m
.d
.sync
57 periph_ports
= self
.periph_ports
58 out_port
= self
.out_port
60 # Connect IO Pad output port to one of the peripheral IOs
61 # Connect peripheral inputs to the IO pad input
62 comb
+= self
.out_port
.o
.eq(self
.periph_ports
[port
].o
)
63 comb
+= self
.out_port
.oe
.eq(self
.periph_ports
[port
].oe
)
65 comb
+= self
.periph_ports
[port
].i
.eq(self
.out_port
.i
)
69 def connect_port_to_io(self
, domain
, port_arg
):
70 domain
+= self
.out_port
.o
.eq(self
.periph_ports
[port_arg
].o
)
71 domain
+= self
.out_port
.oe
.eq(self
.periph_ports
[port_arg
].oe
)
72 domain
+= self
.periph_ports
[port_arg
].i
.eq(self
.out_port
.i
)
75 """ Get member signals for Verilog form. """
76 for field
in self
.out_port
.fields
.values():
78 for port
in range(self
.n_ports
):
79 for field
in self
.periph_ports
[port
].fields
.values():
86 # Method to test a particular peripheral port
87 # when rand_order is True, previous and consecutive ports are
88 # random (but NOT equal to given port)
89 def test_single_port(dut
, port
, rand_order
=True, delay
=1e-6):
91 print("Randomising the prev and next ports")
93 while(prev_port
== port
):
94 prev_port
= randint(0, dut
.n_ports
-1)
96 while(next_port
== port
):
97 next_port
= randint(0, dut
.n_ports
-1)
99 # Set the prev and next ports as consecutive ports
101 prev_port
= dut
.n_ports
- 1
105 if port
== dut
.n_ports
:
110 print("Prev=%d, Given=%d, Next=%d" % (prev_port
, port
, next_port
))
112 # Clear o/oe, delay, set port i
113 # Set to previous port, delay
115 # Set to desired port
119 # Set to next port, delay
121 yield dut
.periph_ports
[port
].o
.eq(0)
123 yield dut
.periph_ports
[port
].oe
.eq(0)
125 yield dut
.out_port
.i
.eq(1)
128 yield dut
.port
.eq(prev_port
)
131 test_i
= yield dut
.periph_ports
[port
].i
134 yield dut
.port
.eq(port
)
137 test_o
= yield dut
.out_port
.o
138 test_oe
= yield dut
.out_port
.oe
139 test_i
= yield dut
.periph_ports
[port
].i
144 yield dut
.periph_ports
[port
].o
.eq(1)
146 yield dut
.periph_ports
[port
].oe
.eq(1)
149 test_o
= yield dut
.out_port
.o
150 test_oe
= yield dut
.out_port
.oe
154 yield dut
.port
.eq(next_port
)
157 test_i
= yield dut
.periph_ports
[port
].i
160 def test_iomux(dut
, rand_order
=True):
161 print("------START----------------------")
162 #print(dir(dut.periph_ports[0]))
163 #print(dut.periph_ports[0].fields)
165 # Produce a test list of port values
166 test_port_vec
= list(range(0, dut
.n_ports
))
167 #print(test_port_vec)
168 # Randomise for wider testing
170 shuffle(test_port_vec
)
171 #print(test_port_vec)
172 for i
in range(dut
.n_ports
):
173 yield from test_single_port(dut
, test_port_vec
[i
], rand_order
)
175 print("Finished the 1-bit IO mux block test!")
177 def gen_gtkw_doc(module_name
, n_ports
, filename
):
178 # GTKWave doc generation
181 'in': {'color': 'orange'},
182 'out': {'color': 'yellow'},
183 'debug': {'module': 'top', 'color': 'red'}
186 # Create a trace list, each block expected to be a tuple()
188 for port
in range(0, n_ports
):
189 temp_traces
= ('Bank%d' % port
, [
190 ('port%d__i' % port
, 'in'),
191 ('port%d__o' % port
, 'out'),
192 ('port%d__oe' % port
, 'out')
194 traces
.append(temp_traces
)
196 temp_traces
= ('Misc', [
197 ('port[%d:0]' % ((n_ports
-1).bit_length()-1), 'in')
199 traces
.append(temp_traces
)
200 temp_traces
= ('IO port to pad', [
205 traces
.append(temp_traces
)
208 write_gtkw(filename
+".gtkw", filename
+".vcd", traces
, style
,
211 def sim_iomux(rand_order
=True):
212 filename
= "test_iomux" # Doesn't include extension
214 dut
= IOMuxBlockSingle(n_ports
)
215 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
216 with
open(filename
+".il", "w") as f
:
220 m
.submodules
.pinmux
= dut
224 sim
.add_process(wrap(test_iomux(dut
, rand_order
)))
225 sim_writer
= sim
.write_vcd(filename
+".vcd")
229 gen_gtkw_doc("top.pinmux", dut
.n_ports
, filename
)
233 if __name__
== '__main__':
234 sim_iomux(rand_order
=True)