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