db92c637ea66947c28e97e242f1ea9762c73e486
3 pinmux documented here https://libre-soc.org/docs/pinmux/
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
13 from nmutil
.gtkw
import write_gtkw
17 from nmigen
.sim
.cxxsim
import Simulator
, Settle
, Delay
19 from nmigen
.sim
import Simulator
, Settle
, Delay
21 from spec
.iomux
import IOMuxBlockSingle
22 from spec
.base
import PinSpec
23 from spec
.jtag
import iotypes
24 from spec
.pinfunctions
import pinspec
28 io_layout
= (("i", 1),
33 uart_layout
= (("rx", 1),
37 uart_tx_layout
= (("o", 1),
45 Really basic example, uart tx/rx and i2c sda/scl pinmux
47 class ManPinmux(Elaboratable
):
48 def __init__(self
, requested
):
49 print("Test Manual Pinmux!")
51 self
.requested
= requested
53 self
.port
= Signal(log2_int(self
.n_ports
))
56 # Automatically create the necessary periph/pad Records/Signals
57 # depending on the given dict specification
58 for pad
in self
.requested
.keys():
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]]
68 if sig_type
== iotypes
['*']:
69 self
.pads
[pad
][mux
] = Record(name
="%s%d" % (sig
, unit
),
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
))
77 def elaborate(self
, platform
):
79 comb
, sync
= m
.d
.comb
, m
.d
.sync
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
)
88 # print(self.requested)
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]
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(
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
)
120 for pad
in list(self
.pads
.keys()):
121 for field
in self
.pads
[pad
]["pad"].fields
.values():
123 for mux
in self
.pads
[pad
].keys():
124 if type(self
.pads
[pad
][mux
]) == Signal
:
125 yield self
.pads
[pad
][mux
]
127 for field
in self
.pads
[pad
][mux
].fields
.values():
134 def set_port(dut
, port
, delay
=1e-6):
135 yield dut
.port
.eq(port
)
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
143 def gpio(gpio
, pad
, data
, delay
=1e-6):
144 # Output test - Control GPIO output
147 n_bits
= len(bin(data
)[2:])
149 for i
in range(0, n_bits
):
150 bit
= (data
>> i
) & 0x1
155 assert data
== read
, f
"GPIO Sent: %x | Pad Read: %x" % (data
, read
)
156 # Input test - Control Pad input
160 for i
in range(0, n_bits
):
161 bit
= (read
>> i
) & 0x1
166 assert read2
== read
, f
"Pad Sent: %x | GPIO Read: %x" % (data
, read
)
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
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
183 yield tx
.eq(0) # start bit
186 # send one byte, lsb first
187 for i
in range(0, 8):
188 bit
= (byte
>> i
) & 0x1
191 test_bit
= yield pad_tx
.o
192 read |
= (test_bit
<< i
)
193 yield tx
.eq(1) # stop bit
195 assert byte
== read
, f
"UART Sent: %x | Pad Read: %x" % (byte
, read
)
196 # Drive Pad i - check word at uart rx
199 yield pad_rx
.i
.eq(0) # start bit
202 for i
in range(0, 8):
203 bit
= (read
>> i
) & 0x1
204 yield pad_rx
.i
.eq(bit
)
207 read2 |
= (test_bit
<< i
)
208 yield pad_rx
.i
.eq(1) # stop bit
210 assert read
== read2
, f
"Pad Sent: %x | UART Read: %x" % (read
, read2
)
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.
218 def i2c_send(sda
, scl
, sda_pad
, byte
, delay
=1e-6):
220 # No pull-up on line implemented, set high instead
225 yield sda_pad
.i
.eq(1)
228 yield sda
.o
.eq(0) # start bit
230 for i
in range(0, 8):
231 bit
= (byte
>> i
) & 0x1
236 temp
= yield sda_pad
.o
239 yield sda
.o
.eq(1) # Master releases SDA line
241 assert byte
== read
, f
"I2C Sent: %x | Pad Read: %x" % (byte
, read
)
243 yield sda_pad
.i
.eq(0)
248 # Send byte back to master
250 for i
in range(0, 8):
251 bit
= (read
>> i
) & 0x1
252 yield sda_pad
.i
.eq(bit
)
259 assert read
== read2
, f
"Pad Sent: %x | I2C Read: %x" % (read
, read2
)
267 # Stop condition - SDA line high after SCL high
272 yield sda
.o
.eq(1) # 'release' the SDA line
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
}]
287 for pad
in requested
.keys():
288 for mux
in requested
[pad
].keys():
289 periph
= requested
[pad
][mux
][0]
292 # [{"padname":%s, "port": %d}, ...]
293 gpios
.append({"padname":pad
, "mux": int(mux
[3])})
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)
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)
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"]
331 yield from set_port(dut
, I2C_MUX
)
332 yield from i2c_send(sda
, scl
, sdapad
, 0x67)
334 def gen_gtkw_doc(module_name
, requested
, filename
):
335 # GTKWave doc generation
338 'in': {'color': 'orange'},
339 'out': {'color': 'yellow'},
340 'debug': {'module': 'top', 'color': 'red'}
342 # Create a trace list, each block expected to be a tuple()
346 for pad
in requested
.keys():
347 temp
= len(requested
[pad
].keys())
350 temp_traces
= ("Pad %s" % pad
, [])
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]
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":
369 temp_traces
[1].append(('tx%d__o' % unit_num
, 'out'))
370 temp_traces
[1].append(('tx%d__oe' % unit_num
, 'out'))
373 temp_traces
[1].append(('rx%d' % unit_num
, 'in'))
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
)
382 temp_traces
= ('Misc', [
383 ('port[%d:0]' % ((n_ports
-1).bit_length()-1), 'in')
385 traces
.append(temp_traces
)
389 write_gtkw(filename
+".gtkw", filename
+".vcd", traces
, style
,
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*']}
404 dut
= ManPinmux(requested
)
405 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
406 with
open(filename
+".il", "w") as f
:
410 m
.submodules
.manpinmux
= dut
414 sim
.add_process(wrap(test_man_pinmux(dut
, requested
)))
415 sim_writer
= sim
.write_vcd(filename
+".vcd")
418 gen_gtkw_doc("top.manpinmux", dut
.requested
, filename
)
420 if __name__
== '__main__':
425 #testspec = PinSpec()
427 'A': (4, 4), # bankname: (num of pins, muxwidth)
437 function_names
= {'TWI0': 'I2C 0',
438 'UART0': 'UART (TX/RX) 0',
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)
448 #print(ps.gpio.pinouts, ps.gpio.bankspec, ps.gpio.pinfn, ps.gpio.fname)
450 desc_dict_keys = ['UART0', 'TWI0', 'GPIOA_A0', 'GPIOA_A1', 'GPIOA_A2',
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)
462 print("---------------------------------")
463 #with open("test.mdwn", "w") as of:
464 # pinout, bankspec, pin_spec, fixedpins = ps.write(of)
465 #print("---------------------------------")
467 bk
= ps
.pinbanks
.keys()
469 muxwidth
= ps
.muxwidths
[bank
]
470 print(bank
, muxwidth
)
471 pinidx
= sorted(ps
.keys())
473 print("---------------------------------")
476 for mux
in range(muxwidth
):
478 print("Mux %d : NC" % mux
)
480 name
, assigned_bank
= pdata
[mux
]
481 print("Mux %d : %s" % (mux
, name
))
486 # Create local list of peripheral names defined in pinfunctions.py
488 for pfunc
in pinspec
:
489 defined_func
.append(pfunc
[0])
491 for pin
in ps
.items():
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...
508 periph
= signal_str
[:index_under
]
509 func
= signal_str
[index_under
+1:]
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
517 print(signal_str
[index
:index_under
])
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())