6e0fd9a7b04a2d3ccec5e02efdbe8eb287880e6d
[pinmux.git] / src / spec / iomux.py
1 """Simple GPIO peripheral on wishbone
2
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
5
6 Modified for use with pinmux, will probably change the class name later.
7 """
8 from random import randint
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
17
18 from nmutil.gtkw import write_gtkw
19
20 cxxsim = False
21 if cxxsim:
22 from nmigen.sim.cxxsim import Simulator, Settle
23 else:
24 from nmigen.sim import Simulator, Settle
25
26 io_layout = (("i", 1),
27 ("oe", 1),
28 ("o", 1)
29 )
30
31 class IOMuxBlockSingle(Elaboratable):
32
33 def __init__(self):
34 print("1-bit IO Mux Block")
35 self.n_banks = 4
36 self.bank = Signal(log2_int(self.n_banks))
37
38 temp = []
39 for i in range(self.n_banks):
40 temp_str = "bank{}".format(i)
41 temp.append(Record(name=temp_str, layout=io_layout))
42 self.bank_ports = Array(temp)
43
44 self.out_port = Record(name="IO", layout=io_layout)
45
46 #self.b0 = Record(name="b0", layout=io_layout)
47 #self.b1 = Record(name="b1", layout=io_layout)
48
49 def elaborate(self, platform):
50 m = Module()
51 comb, sync = m.d.comb, m.d.sync
52
53 bank = self.bank
54 bank_ports = self.bank_ports
55 #b0 = self.b0
56 #b1 = self.b1
57 out_port = self.out_port
58
59 sync += out_port.o.eq(bank_ports[0].o)
60 sync += out_port.oe.eq(bank_ports[0].oe)
61 sync += bank_ports[0].i.eq(out_port.i)
62
63 # Connect IO Pad output port to one of the peripheral IOs
64 # Connect peripheral inputs to the IO pad input
65
66 bank_range = range(self.n_banks)
67 # const
68 BANK0_WB = 0
69 BANK1_P1 = 1
70 BANK2_P2 = 2
71 BANK3_P3 = 3
72
73 with m.Switch(bank):
74 with m.Case(BANK0_WB):
75 self.connect_bank_to_io(sync, BANK0_WB)
76 with m.Case(BANK1_P1):
77 self.connect_bank_to_io(sync, BANK1_P1)
78 with m.Case(BANK2_P2):
79 self.connect_bank_to_io(sync, BANK2_P2)
80 with m.Case(BANK3_P3):
81 self.connect_bank_to_io(sync, BANK3_P3)
82 return m
83
84 def connect_bank_to_io(self, domain, bank_arg):
85 domain += self.out_port.o.eq(self.bank_ports[bank_arg].o)
86 domain += self.out_port.oe.eq(self.bank_ports[bank_arg].oe)
87 domain += self.bank_ports[bank_arg].i.eq(self.out_port.i)
88
89 temp_list = list(range(self.n_banks))
90 temp_list.pop(temp_list.index(bank_arg))
91 print("Banks with input hardwired to 0: {}".format(temp_list))
92 for j in range(len(temp_list)):
93 unused_bank = temp_list[j]
94 domain += self.bank_ports[unused_bank].i.eq(0)
95
96 def __iter__(self):
97 """ Get member signals for Verilog form. """
98 for field in self.out_port.fields.values():
99 yield field
100 for bank in range(len(self.bank_ports)):
101 for field in self.bank_ports[bank].fields.values():
102 yield field
103 yield self.bank
104
105 def ports(self):
106 return list(self)
107
108 def gen_gtkw_doc(module_name, n_banks, filename):
109 # GTKWave doc generation
110 style = {
111 '': {'base': 'hex'},
112 'in': {'color': 'orange'},
113 'out': {'color': 'yellow'},
114 'debug': {'module': 'top', 'color': 'red'}
115 }
116
117 # Create a trace list, each block expected to be a tuple()
118 traces = []
119 for bank in range(0, n_banks):
120 temp_traces = ('Bank{}'.format(bank), [
121 ('bank{}__i'.format(bank), 'in'),
122 ('bank{}__o'.format(bank), 'out'),
123 ('bank{}__oe'.format(bank), 'out')
124 ])
125 traces.append(temp_traces)
126
127 temp_traces = ('Misc', [
128 ('clk'),
129 ('bank[1:0]', 'in')
130 ])
131 traces.append(temp_traces)
132 temp_traces = ('IO port to pad', [
133 ('IO__i', 'in'),
134 ('IO__o', 'out'),
135 ('IO__oe', 'out')
136 ])
137 traces.append(temp_traces)
138 #print(traces)
139
140 write_gtkw(filename+".gtkw", filename+".vcd", traces, style,
141 module=module_name)
142
143 def sim_iomux():
144 filename = "test_pinmux" # Doesn't include extension
145 dut = IOMuxBlockSingle()
146 vl = rtlil.convert(dut, ports=dut.ports())
147 with open(filename+".il", "w") as f:
148 f.write(vl)
149
150 m = Module()
151 m.submodules.pinmux = dut
152
153 sim = Simulator(m)
154 sim.add_clock(1e-6)
155
156 sim.add_sync_process(wrap(test_iomux(dut)))
157 sim_writer = sim.write_vcd(filename+".vcd")
158 with sim_writer:
159 sim.run()
160
161 gen_gtkw_doc("top.pinmux", dut.n_banks, filename)
162
163 # Method for toggling i/o/oe of a particular bank port,
164 # while bank_sel has three different values:
165 # value before, given value, value after
166 # when rand is True, previous and consecutive values are
167 # random (but NOT equal to given bank_sel)
168 def test_single_bank(dut, bank, rand=True):
169 if rand:
170 print("Randomising the prev and next banks")
171 prev_bank=bank
172 while(prev_bank == bank):
173 prev_bank = randint(0, dut.n_banks-1)
174 next_bank=bank
175 while(next_bank == bank):
176 next_bank = randint(0, dut.n_banks-1)
177 else:
178 if bank == 0:
179 prev_bank = dut.n_banks
180 else:
181 prev_bank = bank - 1
182
183 if bank == dut.n_banks:
184 next_bank = 0
185 else:
186 next_bank = bank + 1
187
188 print("Prev={}, Given={}, Next={}".format(prev_bank, bank, next_bank))
189
190 yield dut.bank.eq(prev_bank)
191 yield
192 yield dut.bank_ports[bank].o.eq(0)
193 yield dut.bank_ports[bank].oe.eq(0)
194 yield dut.out_port.i.eq(0)
195 yield
196 yield
197
198 yield dut.bank.eq(bank)
199 yield
200
201 test_o = yield dut.out_port.o
202 test_oe = yield dut.out_port.oe
203 test_i = yield dut.bank_ports[bank].i
204 assert(test_o == 0)
205 assert(test_oe == 0)
206 assert(test_i == 0)
207
208 yield dut.bank_ports[bank].o.eq(1)
209 yield
210 yield dut.bank_ports[bank].oe.eq(1)
211 yield
212 yield dut.out_port.i.eq(1)
213 yield
214 yield
215
216 test_o = yield dut.out_port.o
217 test_oe = yield dut.out_port.oe
218 test_i = yield dut.bank_ports[bank].i
219 #print(test_o, test_oe, test_i)
220 assert(test_o == 1)
221 assert(test_oe == 1)
222 assert(test_i == 1)
223
224 yield dut.bank.eq(next_bank)
225 yield
226 yield
227 yield dut.bank_ports[bank].o.eq(0)
228 yield dut.bank_ports[bank].oe.eq(0)
229 yield dut.out_port.i.eq(0)
230 yield
231 yield
232
233 def test_iomux(dut):
234 print("------START----------------------")
235 #print(dir(dut.bank_ports[0]))
236 #print(dut.bank_ports[0].fields)
237
238 # TODO: turn into methods
239 yield from test_single_bank(dut, 0)
240 yield from test_single_bank(dut, 1)
241 yield from test_single_bank(dut, 2)
242 yield from test_single_bank(dut, 3)
243
244 print("Finished the 1-bit IO mux block test!")
245
246 if __name__ == '__main__':
247 sim_iomux()
248