single i/o/oe pin IOMux working (test needs improving).
[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 def test_iomux(dut):
164 print("------START----------------------")
165 #print(dir(dut.bank_ports[0]))
166 #print(dut.bank_ports[0].fields)
167
168 # TODO: turn into methods
169 yield dut.bank_ports[0].o.eq(1)
170 yield dut.bank.eq(0)
171 yield
172 yield dut.bank_ports[0].o.eq(1)
173 yield
174 yield dut.bank_ports[1].o.eq(1)
175 yield
176 yield dut.bank_ports[0].oe.eq(1)
177 yield
178 yield dut.bank.eq(1)
179 yield
180
181 yield dut.bank_ports[0].o.eq(0)
182 yield
183 yield dut.bank_ports[1].o.eq(0)
184 yield
185 yield dut.bank_ports[1].oe.eq(1)
186 yield
187 yield dut.bank.eq(0)
188 yield
189
190 yield dut.bank.eq(1)
191 yield
192 yield dut.bank_ports[1].o.eq(1)
193 yield
194 yield dut.bank_ports[2].o.eq(1)
195 yield
196 yield dut.bank_ports[1].oe.eq(1)
197 yield
198 yield dut.bank.eq(2)
199 yield
200
201 yield dut.bank_ports[1].o.eq(0)
202 yield
203 yield dut.bank_ports[2].o.eq(0)
204 yield
205 yield dut.bank_ports[2].oe.eq(1)
206 yield
207 yield dut.bank.eq(0)
208 yield
209
210 print("Finished the 1-bit IO mux block test!")
211
212 if __name__ == '__main__':
213 sim_iomux()
214