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