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