Fixed GPIO block issue that accessed out of bounds Array()
[pinmux.git] / src / spec / pinmux.py
1 """
2 1-bit pinmux case
3
4 """
5 from random import randint
6 #from math import ceil, floor
7 from nmigen import Elaboratable, Module, Signal, Record, Array, Cat
8 from nmigen.hdl.rec import Layout
9 from nmigen.utils import log2_int
10 from nmigen.cli import rtlil
11 from soc.minerva.wishbone import make_wb_layout
12 from nmutil.util import wrap
13 #from soc.bus.test.wb_rw import wb_read, wb_write
14
15 from nmutil.gtkw import write_gtkw
16
17 cxxsim = False
18 if cxxsim:
19 from nmigen.sim.cxxsim import Simulator, Settle, Delay
20 else:
21 from nmigen.sim import Simulator, Settle, Delay
22
23 from iomux import IOMuxBlockSingle, io_layout
24 from simple_gpio import SimpleGPIO, GPIOManager, csrbus_layout
25
26 class PinMuxBlockSingle(Elaboratable):
27
28 def __init__(self, wb_wordsize):
29 print("1-bit Pin Mux Block with JTAG")
30 self.n_banks = 4
31 self.n_gpios = 1
32 self.wb_wordsize = wb_wordsize # 4 Bytes, 32-bits
33
34 # Create WB bus for the GPIO block
35 class Spec: pass
36 spec = Spec()
37 spec.addr_wid = 30
38 spec.mask_wid = 4
39 spec.reg_wid = self.wb_wordsize*8
40 self.bus = Record(make_wb_layout(spec), name="pinmux_wb")
41
42 temp = []
43 for i in range(1, self.n_banks):
44 temp_str = "periph{}".format(i)
45 temp.append(Record(name=temp_str, layout=io_layout))
46 self.periph_ports = Array(temp)
47
48 self.pad_port = Record(name="IOPad", layout=io_layout)
49
50 self.iomux = IOMuxBlockSingle()
51 self.gpio = SimpleGPIO(self.wb_wordsize, self.n_gpios)
52 # This is probably easier to extend in future by bringing out WB
53 # interface to top-level
54 #self.bus = self.gpio.bus
55
56 def elaborate(self, platform):
57 m = Module()
58 comb, sync = m.d.comb, m.d.sync
59 iomux = self.iomux
60 gpio = self.gpio
61 bus = self.bus
62 periph_ports = self.periph_ports
63 pad_port = self.pad_port
64
65 # Add blocks to submodules
66 m.submodules.iomux = iomux
67 m.submodules.gpio = gpio
68
69 # Connect up modules and signals
70 # WB bus connection
71 m.d.comb += [gpio.bus.adr.eq(bus.adr),
72 gpio.bus.dat_w.eq(bus.dat_w),
73 bus.dat_r.eq(gpio.bus.dat_r),
74 gpio.bus.sel.eq(bus.sel),
75 gpio.bus.cyc.eq(bus.cyc),
76 gpio.bus.stb.eq(bus.stb),
77 bus.ack.eq(gpio.bus.ack),
78 gpio.bus.we.eq(bus.we),
79 bus.err.eq(gpio.bus.err),
80 gpio.bus.cti.eq(bus.cti), # Cycle Type Identifier
81 gpio.bus.bte.eq(bus.bte) # Burst Type Extension
82 ]
83
84 m.d.comb += iomux.bank.eq(gpio.gpio_ports[0].bank)
85
86 # WB GPIO always bank0
87 m.d.comb += iomux.bank_ports[0].o.eq(gpio.gpio_ports[0].o)
88 m.d.comb += iomux.bank_ports[0].oe.eq(gpio.gpio_ports[0].oe)
89 m.d.comb += gpio.gpio_ports[0].i.eq(iomux.bank_ports[0].i)
90
91 # banks1-3 external
92 for bank in range(0, self.n_banks-1):
93 m.d.comb += iomux.bank_ports[bank+1].o.eq(periph_ports[bank].o)
94 m.d.comb += iomux.bank_ports[bank+1].oe.eq(periph_ports[bank].oe)
95 m.d.comb += periph_ports[bank].i.eq(iomux.bank_ports[bank+1].i)
96
97 m.d.comb += pad_port.o.eq(iomux.out_port.o)
98 m.d.comb += pad_port.oe.eq(iomux.out_port.oe)
99 m.d.comb += iomux.out_port.i.eq(pad_port.i)
100
101 return m
102
103 def __iter__(self):
104 """ Get member signals for Verilog form. """
105 for field in self.pad_port.fields.values():
106 yield field
107 for field in self.gpio.bus.fields.values():
108 yield field
109 for bank in range(len(self.periph_ports)):
110 for field in self.periph_ports[bank].fields.values():
111 yield field
112
113 def ports(self):
114 return list(self)
115
116 def gen_gtkw_doc(module_name, wordsize, n_banks, filename):
117 # GTKWave doc generation
118 style = {
119 '': {'base': 'hex'},
120 'in': {'color': 'orange'},
121 'out': {'color': 'yellow'},
122 'debug': {'module': 'top', 'color': 'red'}
123 }
124
125 # Create a trace list, each block expected to be a tuple()
126 traces = []
127 wb_data_width = wordsize*8
128 wb_traces = ('Wishbone Bus', [
129 ('gpio_wb__cyc', 'in'),
130 ('gpio_wb__stb', 'in'),
131 ('gpio_wb__we', 'in'),
132 ('gpio_wb__adr[27:0]', 'in'),
133 ('gpio_wb__dat_w[{}:0]'.format(wb_data_width-1), 'in'),
134 ('gpio_wb__dat_r[{}:0]'.format(wb_data_width-1), 'out'),
135 ('gpio_wb__ack', 'out'),
136 ])
137 traces.append(wb_traces)
138
139 for bank in range(0, n_banks):
140 temp_traces = ('Bank{}'.format(bank), [
141 ('bank{}__i'.format(bank), 'in'),
142 ('bank{}__o'.format(bank), 'out'),
143 ('bank{}__oe'.format(bank), 'out')
144 ])
145 traces.append(temp_traces)
146
147 temp_traces = ('Misc', [
148 ('bank[1:0]', 'in')
149 ])
150 traces.append(temp_traces)
151 temp_traces = ('IO port to pad', [
152 ('IO__i', 'in'),
153 ('IO__o', 'out'),
154 ('IO__oe', 'out')
155 ])
156 traces.append(temp_traces)
157 #print(traces)
158
159 write_gtkw(filename+".gtkw", filename+".vcd", traces, style,
160 module=module_name)
161
162 def sim_iomux():
163 filename = "test_gpio_pinmux" # Doesn't include extension
164 wb_wordsize = 4
165 dut = PinMuxBlockSingle(wb_wordsize)
166 vl = rtlil.convert(dut, ports=dut.ports())
167 with open(filename+".il", "w") as f:
168 f.write(vl)
169
170 print("Bus dir:")
171 print(dut.gpio.bus.adr)
172 print(dut.gpio.bus.fields)
173
174 m = Module()
175 m.submodules.pinmux = dut
176
177 sim = Simulator(m)
178 sim.add_clock(1e-6)
179
180 sim.add_sync_process(wrap(test_gpio_pinmux(dut)))
181 sim_writer = sim.write_vcd(filename+".vcd")
182 with sim_writer:
183 sim.run()
184
185 gen_gtkw_doc("top.pinmux", wb_wordsize, dut.n_banks, filename)
186
187 def test_gpio_pinmux(dut):
188 print("------START----------------------")
189 #print(dir(dut.bank_ports[0]))
190 #print(dut.bank_ports[0].fields)
191
192 gpios = GPIOManager(dut.gpio, csrbus_layout, dut.bus)
193
194 oe = 1
195 ie = 0
196 puen = 0
197 pden = 1
198 outval = 0
199 bank = 0
200 yield from gpios.config("0", oe=1, ie=0, puen=0, pden=1, outval=0, bank=2)
201
202 yield
203 yield dut.periph_ports[0].o.eq(1)
204 yield dut.periph_ports[0].oe.eq(1)
205 yield dut.pad_port.i.eq(1)
206 yield
207 yield from gpios.config("0", oe=0, ie=0, puen=0, pden=1, outval=0, bank=0)
208 yield from gpios.rd_input("0")
209
210 print("Finished the 1-bit IO mux block test!")
211
212 if __name__ == '__main__':
213 sim_iomux()
214