feat(stage2): Trying to make the dict keys needed to access IOTypes dict
[pinmux.git] / src / 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 spec.iomux import IOMuxBlockSingle
22 from spec.base import PinSpec
23 from spec.jtag import iotypes
24 from spec.pinfunctions import pinspec
25
26 #import code
27
28 io_layout = (("i", 1),
29 ("oe", 1),
30 ("o", 1)
31 )
32
33 uart_layout = (("rx", 1),
34 ("tx", 1),
35 ("oe", 1)
36 )
37 uart_tx_layout = (("o", 1),
38 ("oe", 1)
39 )
40 GPIO_MUX = 0
41 UART_MUX = 1
42 I2C_MUX = 2
43
44 """
45 Really basic example, uart tx/rx and i2c sda/scl pinmux
46 """
47 class ManPinmux(Elaboratable):
48 def __init__(self, requested):
49 print("Test Manual Pinmux!")
50
51 self.requested = requested
52 self.n_ports = 4
53 self.port = Signal(log2_int(self.n_ports))
54 self.pads = {}
55 self.muxes = {}
56 # Automatically create the necessary periph/pad Records/Signals
57 # depending on the given dict specification
58 for pad in self.requested.keys():
59 self.pads[pad] = {}
60 self.pads[pad]["pad"] = Record(name=pad, layout=io_layout)
61 self.muxes[pad] = IOMuxBlockSingle(self.n_ports)
62 for mux in self.requested[pad].keys():
63 periph = self.requested[pad][mux][0]
64 unit = self.requested[pad][mux][1]
65 sig = self.requested[pad][mux][2][:-1]
66 sig_type = iotypes[self.requested[pad][mux][2][-1]]
67 #print(sig, sig_type)
68 if sig_type == iotypes['*']:
69 self.pads[pad][mux] = Record(name="%s%d" % (sig, unit),
70 layout=io_layout)
71 elif sig_type == iotypes['+']:
72 self.pads[pad][mux] = Signal(name="%s%d_o" % (sig, unit))
73 elif sig_type == iotypes['-']:
74 self.pads[pad][mux] = Signal(name="%s%d_i" % (sig, unit))
75 print(self.pads)
76
77 def elaborate(self, platform):
78 m = Module()
79 comb, sync = m.d.comb, m.d.sync
80 muxes = self.muxes
81 port = self.port
82 pads = self.pads
83 for pad in pads.keys():
84 m.submodules[pad+"_mux"] = muxes[pad]
85 # all muxes controlled by the same multi-bit signal
86 comb += muxes[pad].port.eq(port)
87
88 # print(self.requested)
89 # print(self.pads)
90
91 # ---------------------------
92 # This section connects the periphs to the assigned ports
93 # ---------------------------
94 for pad in pads.keys():
95 for mux in self.requested[pad].keys():
96 periph = self.requested[pad][mux][0]
97 num = int(mux[3])
98 sig = self.requested[pad][mux][2][:-1]
99 sig_type = iotypes[self.requested[pad][mux][2][-1]]
100 if sig_type == iotypes['*']:
101 comb += muxes[pad].periph_ports[num].o.eq(pads[pad][mux].o)
102 comb += muxes[pad].periph_ports[num].oe.eq(
103 pads[pad][mux].oe)
104 comb += pads[pad][mux].i.eq(muxes[pad].periph_ports[num].i)
105 elif sig_type == iotypes['+']:
106 comb += muxes[pad].periph_ports[num].o.eq(pads[pad][mux])
107 elif sig_type == iotypes['-']:
108 comb += pads[pad][mux].eq(muxes[pad].periph_ports[num].i)
109 # ---------------------------
110 # Here is where the muxes are assigned to the actual pads
111 # ---------------------------
112 for pad in pads.keys():
113 comb += pads[pad]["pad"].o.eq(muxes[pad].out_port.o)
114 comb += pads[pad]["pad"].oe.eq(muxes[pad].out_port.oe)
115 comb += muxes[pad].out_port.i.eq(pads[pad]["pad"].i)
116
117 return m
118
119 def __iter__(self):
120 for pad in list(self.pads.keys()):
121 for field in self.pads[pad]["pad"].fields.values():
122 yield field
123 for mux in self.pads[pad].keys():
124 if type(self.pads[pad][mux]) == Signal:
125 yield self.pads[pad][mux]
126 else:
127 for field in self.pads[pad][mux].fields.values():
128 yield field
129 yield self.port
130
131 def ports(self):
132 return list(self)
133
134 def set_port(dut, port, delay=1e-6):
135 yield dut.port.eq(port)
136 yield Delay(delay)
137
138 """
139 GPIO test function
140 Set the gpio output based on given data sequence, checked at pad.o
141 Then sends the same byte via pad.i to gpio input
142 """
143 def gpio(gpio, pad, data, delay=1e-6):
144 # Output test - Control GPIO output
145 yield gpio.oe.eq(1)
146 yield Delay(delay)
147 n_bits = len(bin(data)[2:])
148 read = 0
149 for i in range(0, n_bits):
150 bit = (data >> i) & 0x1
151 yield gpio.o.eq(bit)
152 yield Delay(delay)
153 temp = yield pad.o
154 read |= (temp << i)
155 assert data == read, f"GPIO Sent: %x | Pad Read: %x" % (data, read)
156 # Input test - Control Pad input
157 yield gpio.oe.eq(0)
158 yield Delay(delay)
159 read2 = 0
160 for i in range(0, n_bits):
161 bit = (read >> i) & 0x1
162 yield pad.i.eq(bit)
163 yield Delay(delay)
164 temp = yield gpio.i
165 read2 |= (temp << i)
166 assert read2 == read, f"Pad Sent: %x | GPIO Read: %x" % (data, read)
167 # reset input signal
168 yield pad.i.eq(0)
169 yield Delay(delay)
170
171 """
172 UART test function
173 Sends a byte via uart tx, checked at output pad
174 Then sends the same byte via input pad to uart rx
175 Input and output pads are different, so must specify both
176 """
177 def uart_send(tx, rx, pad_tx, pad_rx, byte, delay=1e-6):
178 # Drive uart tx - check the word seen at the Pad
179 print(type(tx))
180 #yield tx.oe.eq(1)
181 yield tx.eq(1)
182 yield Delay(2*delay)
183 yield tx.eq(0) # start bit
184 yield Delay(delay)
185 read = 0
186 # send one byte, lsb first
187 for i in range(0, 8):
188 bit = (byte >> i) & 0x1
189 yield tx.eq(bit)
190 yield Delay(delay)
191 test_bit = yield pad_tx.o
192 read |= (test_bit << i)
193 yield tx.eq(1) # stop bit
194 yield Delay(delay)
195 assert byte == read, f"UART Sent: %x | Pad Read: %x" % (byte, read)
196 # Drive Pad i - check word at uart rx
197 yield pad_rx.i.eq(1)
198 yield Delay(2*delay)
199 yield pad_rx.i.eq(0) # start bit
200 yield Delay(delay)
201 read2 = 0
202 for i in range(0, 8):
203 bit = (read >> i) & 0x1
204 yield pad_rx.i.eq(bit)
205 yield Delay(delay)
206 test_bit = yield rx
207 read2 |= (test_bit << i)
208 yield pad_rx.i.eq(1) # stop bit
209 yield Delay(delay)
210 assert read == read2, f"Pad Sent: %x | UART Read: %x" % (read, read2)
211
212 """
213 I2C test function
214 Sends a byte via SDA.o (peripheral side), checked at output pad
215 Then sends the same byte via input pad to master SDA.i
216 This transaction doesn't make the distinction between read/write bit.
217 """
218 def i2c_send(sda, scl, sda_pad, byte, delay=1e-6):
219 # No checking yet
220 # No pull-up on line implemented, set high instead
221 yield sda.oe.eq(1)
222 yield sda.o.eq(1)
223 yield scl.oe.eq(1)
224 yield scl.o.eq(1)
225 yield sda_pad.i.eq(1)
226 yield Delay(delay)
227 read = 0
228 yield sda.o.eq(0) # start bit
229 yield Delay(delay)
230 for i in range(0, 8):
231 bit = (byte >> i) & 0x1
232 yield sda.o.eq(bit)
233 yield scl.o.eq(0)
234 yield Delay(delay/2)
235 yield scl.o.eq(1)
236 temp = yield sda_pad.o
237 read |= (temp << i)
238 yield Delay(delay/2)
239 yield sda.o.eq(1) # Master releases SDA line
240 yield sda.oe.eq(0)
241 assert byte == read, f"I2C Sent: %x | Pad Read: %x" % (byte, read)
242 # Slave ACK
243 yield sda_pad.i.eq(0)
244 yield scl.o.eq(0)
245 yield Delay(delay/2)
246 yield scl.o.eq(1)
247 yield Delay(delay/2)
248 # Send byte back to master
249 read2 = 0
250 for i in range(0, 8):
251 bit = (read >> i) & 0x1
252 yield sda_pad.i.eq(bit)
253 yield scl.o.eq(0)
254 yield Delay(delay/2)
255 yield scl.o.eq(1)
256 temp = yield sda.i
257 read2 |= (temp << i)
258 yield Delay(delay/2)
259 assert read == read2, f"Pad Sent: %x | I2C Read: %x" % (read, read2)
260 # Master ACK
261 yield sda.oe.eq(1)
262 yield sda.o.eq(0)
263 yield scl.o.eq(0)
264 yield Delay(delay/2)
265 yield scl.o.eq(1)
266 yield Delay(delay/2)
267 # Stop condition - SDA line high after SCL high
268 yield scl.o.eq(0)
269 yield Delay(delay/2)
270 yield scl.o.eq(1)
271 yield Delay(delay/2)
272 yield sda.o.eq(1) # 'release' the SDA line
273
274 # Test the GPIO/UART/I2C connectivity
275 def test_man_pinmux(dut, requested):
276 # TODO: Convert to automatic
277 # [{"pad":%s, "port":%d}, {"pad":%s, "port":%d},...]
278 #gpios = [{"padname":"N1", "port":GPIO_MUX},
279 # {"padname":"N2", "port":GPIO_MUX}]
280 # [[txPAD, MUXx, rxPAD, MUXx],...] - diff ports not supported yet
281 uarts = [{"txpadname":"N1", "rxpadname":"N2", "mux":UART_MUX}]
282 # [[sdaPAD, MUXx, sclPAD, MUXx],...] - diff ports not supported yet
283 i2cs = [{"sdapadname":"N1", "sclpadname":"N2", "mux":I2C_MUX}]
284
285 gpios = []
286 delay = 1e-6
287 for pad in requested.keys():
288 for mux in requested[pad].keys():
289 periph = requested[pad][mux][0]
290
291 if periph == "gpio":
292 # [{"padname":%s, "port": %d}, ...]
293 gpios.append({"padname":pad, "mux": int(mux[3])})
294 if periph == "uart":
295 # TODO:
296 pass
297 if periph == "i2c":
298 # TODO:
299 pass
300 print(gpios)
301 # GPIO test
302 for gpio_periph in gpios:
303 padname = gpio_periph["padname"]
304 gpio_port = gpio_periph["mux"]
305 gp = dut.pads[padname]["mux%d" % gpio_port]
306 pad = dut.pads[padname]["pad"]
307 yield from set_port(dut, gpio_port)
308 yield from gpio(gp, pad, 0x5a5)
309
310 # UART test
311 for uart_periph in uarts:
312 txpadname = uart_periph["txpadname"]
313 rxpadname = uart_periph["rxpadname"]
314 uart_port = uart_periph["mux"]
315 tx = dut.pads[txpadname]["mux%d" % uart_port]
316 rx = dut.pads[rxpadname]["mux%d" % uart_port]
317 txpad = dut.pads[txpadname]["pad"]
318 rxpad = dut.pads[rxpadname]["pad"]
319 yield from set_port(dut, UART_MUX)
320 yield from uart_send(tx, rx, txpad, rxpad, 0x42)
321
322 # I2C test
323 for i2c_periph in i2cs:
324 sdapadname = i2c_periph["sdapadname"]
325 sclpadname = i2c_periph["sclpadname"]
326 i2c_port = i2c_periph["mux"]
327 sda = dut.pads[sdapadname]["mux%d" % i2c_port]
328 scl = dut.pads[sclpadname]["mux%d" % i2c_port]
329 sdapad = dut.pads[sdapadname]["pad"]
330
331 yield from set_port(dut, I2C_MUX)
332 yield from i2c_send(sda, scl, sdapad, 0x67)
333
334 def gen_gtkw_doc(module_name, requested, filename):
335 # GTKWave doc generation
336 style = {
337 '': {'base': 'hex'},
338 'in': {'color': 'orange'},
339 'out': {'color': 'yellow'},
340 'debug': {'module': 'top', 'color': 'red'}
341 }
342 # Create a trace list, each block expected to be a tuple()
343 traces = []
344 temp = 0
345 n_ports = 0
346 for pad in requested.keys():
347 temp = len(requested[pad].keys())
348 if n_ports < temp:
349 n_ports = temp
350 temp_traces = ("Pad %s" % pad, [])
351 # Pad signals
352 temp_traces[1].append(('%s__i' % pad, 'in'))
353 temp_traces[1].append(('%s__o' % pad, 'out'))
354 temp_traces[1].append(('%s__oe' % pad, 'out'))
355 for mux in requested[pad].keys():
356 periph = requested[pad][mux][0]
357 unit_num = requested[pad][mux][1]
358 if len(requested[pad][mux]) == 3:
359 pin = requested[pad][mux][2]
360 else:
361 pin = "io"
362
363 if periph == "gpio":
364 temp_traces[1].append(('gp%d__i' % unit_num, 'in'))
365 temp_traces[1].append(('gp%d__o' % unit_num, 'out'))
366 temp_traces[1].append(('gp%d__oe' % unit_num, 'out'))
367 elif periph == "uart":
368 if pin == "tx":
369 temp_traces[1].append(('tx%d__o' % unit_num, 'out'))
370 temp_traces[1].append(('tx%d__oe' % unit_num, 'out'))
371 pass
372 elif pin == "rx":
373 temp_traces[1].append(('rx%d' % unit_num, 'in'))
374 pass
375 elif periph == "i2c":
376 temp_traces[1].append(('%s%d__i' % (pin, unit_num), 'in'))
377 temp_traces[1].append(('%s%d__o' % (pin, unit_num), 'out'))
378 temp_traces[1].append(('%s%d__oe' % (pin, unit_num), 'out'))
379 traces.append(temp_traces)
380
381 # master port signal
382 temp_traces = ('Misc', [
383 ('port[%d:0]' % ((n_ports-1).bit_length()-1), 'in')
384 ])
385 traces.append(temp_traces)
386
387 #print(traces)
388
389 write_gtkw(filename+".gtkw", filename+".vcd", traces, style,
390 module=module_name)
391
392
393 def sim_man_pinmux():
394 filename = "test_man_pinmux"
395 requested = {"N1": {"mux%d" % GPIO_MUX: ["gpio", 0, '0*'],
396 "mux%d" % UART_MUX: ["uart", 0, 'tx+'],
397 "mux%d" % I2C_MUX: ["i2c", 0, 'sda*']},
398 "N2": {"mux%d" % GPIO_MUX: ["gpio", 1, '*'],
399 "mux%d" % UART_MUX: ["uart", 0, 'rx-'],
400 "mux%d" % I2C_MUX: ["i2c", 0, 'scl*']},
401 "N3": {"mux%d" % GPIO_MUX: ["gpio", 2, '0*']},
402 "N4": {"mux%d" % GPIO_MUX: ["gpio", 3, '0*']}
403 }
404 dut = ManPinmux(requested)
405 vl = rtlil.convert(dut, ports=dut.ports())
406 with open(filename+".il", "w") as f:
407 f.write(vl)
408
409 m = Module()
410 m.submodules.manpinmux = dut
411
412 sim = Simulator(m)
413
414 sim.add_process(wrap(test_man_pinmux(dut, requested)))
415 sim_writer = sim.write_vcd(filename+".vcd")
416 with sim_writer:
417 sim.run()
418 gen_gtkw_doc("top.manpinmux", dut.requested, filename)
419
420 if __name__ == '__main__':
421 sim_man_pinmux()
422 #pinbanks = []
423 #fixedpins = []
424 #function_names = []
425 #testspec = PinSpec()
426 pinbanks = {
427 'A': (4, 4), # bankname: (num of pins, muxwidth)
428 'B': (2, 4),
429 #'C': (24, 1),
430 #'D': (93, 1),
431 }
432 fixedpins = {
433 'POWER_GPIO': [
434 'VDD_GPIOB',
435 'GND_GPIOB',
436 ]}
437 function_names = {'TWI0': 'I2C 0',
438 'UART0': 'UART (TX/RX) 0',
439 }
440 ps = PinSpec(pinbanks, fixedpins, function_names)
441 # Unit number, (Bank, pin #), mux, start, num # pins
442 ps.gpio("", ('A', 0), 0, 0, 4)
443 ps.gpio("2", ('B', 0), 0, 0, 2)
444 ps.uart("0", ('A', 0), 1)
445 ps.i2c("0", ('A', 0), 2)
446
447 print(dir(ps.gpio))
448 #print(ps.gpio.pinouts, ps.gpio.bankspec, ps.gpio.pinfn, ps.gpio.fname)
449 """
450 desc_dict_keys = ['UART0', 'TWI0', 'GPIOA_A0', 'GPIOA_A1', 'GPIOA_A2',
451 'GPIOA_A3']
452 eint = []
453 pwm = []
454 desc = {'UART0': 'Basic serial TX/RX serial port',
455 'TWI0': 'I2C interface',
456 'GPIOA_A0': 'Test GPIO0',
457 'GPIOA_A1': 'Test GPIO1',
458 'GPIOA_A2': 'Test GPIO2',
459 'GPIOA_A3': 'Test GPIO3'}
460 ps.add_scenario("Test Manual Pinmux", desc_dict_keys, eint, pwm, desc)
461 """
462 print("---------------------------------")
463 #with open("test.mdwn", "w") as of:
464 # pinout, bankspec, pin_spec, fixedpins = ps.write(of)
465 #print("---------------------------------")
466
467 bk = ps.pinbanks.keys()
468 for bank in bk:
469 muxwidth = ps.muxwidths[bank]
470 print(bank, muxwidth)
471 pinidx = sorted(ps.keys())
472 for pin in pinidx:
473 print("---------------------------------")
474 print(pin)
475 pdata = ps.get(pin)
476 for mux in range(muxwidth):
477 if mux not in pdata:
478 print("Mux %d : NC" % mux)
479 else:
480 name, assigned_bank = pdata[mux]
481 print("Mux %d : %s" % (mux, name))
482
483 print(ps.items())
484 print(ps.byspec)
485 print(ps.fnspec)
486 # Create local list of peripheral names defined in pinfunctions.py
487 defined_func = []
488 for pfunc in pinspec:
489 defined_func.append(pfunc[0])
490
491 for pin in ps.items():
492 pin_no = pin[0]
493 #print(pin)
494 for mux in pin[1].keys():
495 bank = pin[1][mux][1]
496 signal_str = pin[1][mux][0]
497 pad = "%s%d" % (bank, pin_no)
498 # Get the signal name prefix
499 index_under = signal_str.find('_')
500 # periph format: [periph+suffix]
501 # GPIO periph format: [periph+bank+suffix]
502 # Problem is that GPIO has a different suffix to UART/TWI.
503 # Assuming that other peripherals may have their own name formats.
504 # keep stripping last chars from string until remainder matches
505 # one of the existing peripheral names
506 # probably very inefficient...
507 # NO ERROR CHECKING
508 periph = signal_str[:index_under]
509 func = signal_str[index_under+1:]
510 while periph != '':
511 if periph in defined_func:
512 break # Found valid periph
513 periph = periph.rstrip(periph[-1])
514 # key to use in PinSpec.byspec has format: [perith+':'+suffix]
515 # need to get the suffix from Pin object
516 index = len(periph)
517 print(signal_str[index:index_under])
518 # TODO: FIx
519 fnspec_key = periph + bank
520 #suffix = ps.fnspec[fnspec_key][fnspec_key]
521 print(pad, signal_str, signal_str[:index_under], periph, func)
522 #code.interact(local=locals())