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