feat(stage2.py): Converted iomux pad/perith connections to for-loop
[pinmux.git] / src / spec / stage2.py
1 #!/usr/bin/env python3
2 """
3 pinmux documented here https://libre-soc.org/docs/pinmux/
4 """
5 from nmigen import Elaboratable, Module, Signal, Record, Array, Cat
6 from nmigen.hdl.rec import Layout
7 from nmigen.utils import log2_int
8 from nmigen.cli import rtlil
9 from soc.minerva.wishbone import make_wb_layout
10 from nmutil.util import wrap
11 #from soc.bus.test.wb_rw import wb_read, wb_write
12
13 from nmutil.gtkw import write_gtkw
14
15 cxxsim = False
16 if cxxsim:
17 from nmigen.sim.cxxsim import Simulator, Settle, Delay
18 else:
19 from nmigen.sim import Simulator, Settle, Delay
20
21 from iomux import IOMuxBlockSingle
22
23 io_layout = (("i", 1),
24 ("oe", 1),
25 ("o", 1)
26 )
27
28 uart_layout = (("rx", 1),
29 ("tx", 1),
30 ("oe", 1)
31 )
32 uart_tx_layout = (("o", 1),
33 ("oe", 1)
34 )
35 GPIO_BANK = 0
36 UART_BANK = 1
37 I2C_BANK = 2
38
39 """
40 Really basic example, uart tx/rx and i2c sda/scl pinmux
41 """
42 class ManPinmux(Elaboratable):
43 def __init__(self, pad_names):
44 print("Test Manual Pinmux!")
45
46 self.requested = {"N1": {"mux%d" % GPIO_BANK: ["gpio", 0],
47 "mux%d" % UART_BANK: ["uart", 0, "tx"],
48 "mux%d" % I2C_BANK: ["i2c", 0, "sda"]},
49 "N2": {"mux%d" % GPIO_BANK: ["gpio", 1],
50 "mux%d" % UART_BANK: ["uart", 0, "rx"],
51 "mux%d" % I2C_BANK: ["i2c", 0, "scl"]}
52 }
53 self.n_banks = 4
54 self.bank = Signal(log2_int(self.n_banks))
55 self.pads = {}
56 self.muxes = {}
57 for pad in self.requested.keys():
58 self.pads[pad] = {}
59 self.pads[pad]["pad"] = Record(name=pad, layout=io_layout)
60 self.muxes[pad] = IOMuxBlockSingle(self.n_banks)
61 for mux in self.requested[pad].keys():
62 periph = self.requested[pad][mux][0]
63 unit_num = self.requested[pad][mux][1]
64 if len(self.requested[pad][mux]) == 3:
65 pin = self.requested[pad][mux][2]
66 else:
67 pin = "io"
68 if periph == "gpio":
69 self.pads[pad][mux] = Record(name="gp%d" % unit_num,
70 layout=io_layout)
71 elif periph == "uart":
72 if pin == "tx":
73 self.pads[pad][mux] = Record(name="tx%d" % unit_num,
74 layout=uart_tx_layout)
75 elif pin == "rx":
76 self.pads[pad][mux] = Signal(name="rx%d" % unit_num)
77 elif periph == "i2c":
78 if pin == "sda":
79 self.pads[pad][mux] = Record(name="sda%d" % unit_num,
80 layout=io_layout)
81 elif pin == "scl":
82 self.pads[pad][mux] = Record(name="scl%d" % unit_num,
83 layout=io_layout)
84
85 def elaborate(self, platform):
86 m = Module()
87 comb, sync = m.d.comb, m.d.sync
88 muxes = self.muxes
89 bank = self.bank
90 # TODO: replace with pin specific
91 iomux1 = muxes["N1"]
92 iomux2 = muxes["N2"]
93 for pad in self.pads.keys():
94 m.submodules[pad+"_mux"] = muxes[pad]
95 # all muxes controlled by the same multi-bit signal
96 comb += muxes[pad].bank.eq(bank)
97 pads = self.pads
98 # print(self.requested)
99 # print(self.pads)
100
101 # ---------------------------
102 # This section connects the periphs to the assigned banks
103 # ---------------------------
104 for pad in self.pads.keys():
105 for mux in self.requested[pad].keys():
106 periph = self.requested[pad][mux][0]
107 num = int(mux[3])
108 if len(self.requested[pad][mux]) == 3:
109 pin = self.requested[pad][mux][2]
110 else:
111 pin = "io"
112 if periph == "gpio" or periph == "i2c":
113 comb += muxes[pad].bank_ports[num].o.eq(pads[pad][mux].o)
114 comb += muxes[pad].bank_ports[num].oe.eq(pads[pad][mux].oe)
115 comb += pads[pad][mux].i.eq(muxes[pad].bank_ports[num].i)
116 elif periph == "uart":
117 if pin == "tx":
118 comb += muxes[pad].bank_ports[num].o.eq(
119 pads[pad][mux].o)
120 comb += muxes[pad].bank_ports[num].oe.eq(
121 pads[pad][mux].oe)
122 elif pin == "rx":
123 comb += pads[pad][mux].eq(muxes[pad].bank_ports[num].i)
124
125 # ---------------------------
126 # Here is where the muxes are assigned to the actual pads
127 # ---------------------------
128 for pad in self.pads.keys():
129 comb += pads[pad]["pad"].o.eq(muxes[pad].out_port.o)
130 comb += pads[pad]["pad"].oe.eq(muxes[pad].out_port.oe)
131 comb += muxes[pad].out_port.i.eq(pads[pad]["pad"].i)
132
133 return m
134
135 def __iter__(self):
136 for pad in list(self.pads.keys()):
137 for field in self.pads[pad]["pad"].fields.values():
138 yield field
139
140 #for field in self.uart.fields.values():
141 # yield field
142 #for field in self.i2c["sda"].fields.values():
143 # yield field
144 #for field in self.i2c["scl"].fields.values():
145 # yield field
146 yield self.bank
147
148 def ports(self):
149 return list(self)
150
151 def set_bank(dut, bank, delay=1e-6):
152 yield dut.bank.eq(bank)
153 yield Delay(delay)
154
155 """
156 GPIO test function
157 Set the gpio output based on given data sequence, checked at pad.o
158 Then sends the same byte via pad.i to gpio input
159 """
160 def gpio(gpio, pad, data, delay=1e-6):
161 # Output test - Control GPIO output
162 yield gpio.oe.eq(1)
163 yield Delay(delay)
164 n_bits = len(bin(data)[2:])
165 read = 0
166 for i in range(0, n_bits):
167 bit = (data >> i) & 0x1
168 yield gpio.o.eq(bit)
169 yield Delay(delay)
170 temp = yield pad.o
171 read |= (temp << i)
172 assert data == read, f"GPIO Sent: %x | Pad Read: %x" % (data, read)
173 # Input test - Control Pad input
174 yield gpio.oe.eq(0)
175 yield Delay(delay)
176 read2 = 0
177 for i in range(0, n_bits):
178 bit = (read >> i) & 0x1
179 yield pad.i.eq(bit)
180 yield Delay(delay)
181 temp = yield gpio.i
182 read2 |= (temp << i)
183 assert read2 == read, f"Pad Sent: %x | GPIO Read: %x" % (data, read)
184 # reset input signal
185 yield pad.i.eq(0)
186 yield Delay(delay)
187
188 """
189 UART test function
190 Sends a byte via uart tx, checked at output pad
191 Then sends the same byte via input pad to uart rx
192 Input and output pads are different, so must specify both
193 """
194 def uart_send(tx, rx, pad_tx, pad_rx, byte, delay=1e-6):
195 # Drive uart tx - check the word seen at the Pad
196 yield tx.oe.eq(1)
197 yield tx.o.eq(1)
198 yield Delay(2*delay)
199 yield tx.o.eq(0) # start bit
200 yield Delay(delay)
201 read = 0
202 # send one byte, lsb first
203 for i in range(0, 8):
204 bit = (byte >> i) & 0x1
205 yield tx.o.eq(bit)
206 yield Delay(delay)
207 test_bit = yield pad_tx.o
208 read |= (test_bit << i)
209 yield tx.o.eq(1) # stop bit
210 yield Delay(delay)
211 assert byte == read, f"UART Sent: %x | Pad Read: %x" % (byte, read)
212 # Drive Pad i - check word at uart rx
213 yield pad_rx.i.eq(1)
214 yield Delay(2*delay)
215 yield pad_rx.i.eq(0) # start bit
216 yield Delay(delay)
217 read2 = 0
218 for i in range(0, 8):
219 bit = (read >> i) & 0x1
220 yield pad_rx.i.eq(bit)
221 yield Delay(delay)
222 test_bit = yield rx
223 read2 |= (test_bit << i)
224 yield pad_rx.i.eq(1) # stop bit
225 yield Delay(delay)
226 assert read == read2, f"Pad Sent: %x | UART Read: %x" % (read, read2)
227
228 """
229 I2C test function
230 Sends a byte via SDA.o (peripheral side), checked at output pad
231 Then sends the same byte via input pad to master SDA.i
232 This transaction doesn't make the distinction between read/write bit.
233 """
234 def i2c_send(sda, scl, sda_pad, byte, delay=1e-6):
235 # No checking yet
236 # No pull-up on line implemented, set high instead
237 yield sda.oe.eq(1)
238 yield sda.o.eq(1)
239 yield scl.oe.eq(1)
240 yield scl.o.eq(1)
241 yield sda_pad.i.eq(1)
242 yield Delay(delay)
243 read = 0
244 yield sda.o.eq(0) # start bit
245 yield Delay(delay)
246 for i in range(0, 8):
247 bit = (byte >> i) & 0x1
248 yield sda.o.eq(bit)
249 yield scl.o.eq(0)
250 yield Delay(delay/2)
251 yield scl.o.eq(1)
252 temp = yield sda_pad.o
253 read |= (temp << i)
254 yield Delay(delay/2)
255 yield sda.o.eq(1) # Master releases SDA line
256 yield sda.oe.eq(0)
257 assert byte == read, f"I2C Sent: %x | Pad Read: %x" % (byte, read)
258 # Slave ACK
259 yield sda_pad.i.eq(0)
260 yield scl.o.eq(0)
261 yield Delay(delay/2)
262 yield scl.o.eq(1)
263 yield Delay(delay/2)
264 # Send byte back to master
265 read2 = 0
266 for i in range(0, 8):
267 bit = (read >> i) & 0x1
268 yield sda_pad.i.eq(bit)
269 yield scl.o.eq(0)
270 yield Delay(delay/2)
271 yield scl.o.eq(1)
272 temp = yield sda.i
273 read2 |= (temp << i)
274 yield Delay(delay/2)
275 assert read == read2, f"Pad Sent: %x | I2C Read: %x" % (read, read2)
276 # Master ACK
277 yield sda.oe.eq(1)
278 yield sda.o.eq(0)
279 yield scl.o.eq(0)
280 yield Delay(delay/2)
281 yield scl.o.eq(1)
282 yield Delay(delay/2)
283 # Stop condition - SDA line high after SCL high
284 yield scl.o.eq(0)
285 yield Delay(delay/2)
286 yield scl.o.eq(1)
287 yield Delay(delay/2)
288 yield sda.o.eq(1) # 'release' the SDA line
289
290 # Test the GPIO/UART/I2C connectivity
291 def test_man_pinmux(dut, pad_names):
292 delay = 1e-6
293 # GPIO test
294 yield from set_bank(dut, GPIO_BANK)
295 yield from gpio(dut.pads["N1"]["mux%d" % GPIO_BANK],
296 dut.pads["N1"]["pad"], 0x5a5)
297 yield from gpio(dut.pads["N2"]["mux%d" % GPIO_BANK],
298 dut.pads["N2"]["pad"], 0x5a5)
299 # UART test
300 yield from set_bank(dut, UART_BANK)
301 yield from uart_send(dut.pads["N1"]["mux%d" % UART_BANK],
302 dut.pads["N2"]["mux%d" % UART_BANK],
303 dut.pads['N1']["pad"], dut.pads['N2']["pad"], 0x42)
304 #yield dut.pads['N2'].i.eq(0)
305 #yield Delay(delay)
306 # I2C test
307 yield from set_bank(dut, I2C_BANK)
308 yield from i2c_send(dut.pads["N1"]["mux%d" % I2C_BANK],
309 dut.pads["N2"]["mux%d" % I2C_BANK],
310 dut.pads['N1']["pad"], 0x67)
311
312 def sim_man_pinmux():
313 filename = "test_man_pinmux"
314 pad_names = ["N1", "N2"]
315 dut = ManPinmux(pad_names)
316 vl = rtlil.convert(dut, ports=dut.ports())
317 with open(filename+".il", "w") as f:
318 f.write(vl)
319
320 m = Module()
321 m.submodules.manpinmux = dut
322
323 sim = Simulator(m)
324
325 sim.add_process(wrap(test_man_pinmux(dut, pad_names)))
326 sim_writer = sim.write_vcd(filename+".vcd")
327 with sim_writer:
328 sim.run()
329 #gen_gtkw_doc("top.manpinmux", dut.n_banks, filename)
330
331 if __name__ == '__main__':
332 sim_man_pinmux()