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