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
25 io_layout
= (("i", 1),
30 uart_layout
= (("rx", 1),
34 uart_tx_layout
= (("o", 1),
42 Really basic example, uart tx/rx and i2c sda/scl pinmux
44 class ManPinmux(Elaboratable
):
45 def __init__(self
, requested
):
46 print("Test Manual Pinmux!")
48 self
.requested
= requested
50 self
.port
= Signal(log2_int(self
.n_ports
))
53 # Automatically create the necessary periph/pad Records/Signals
54 # depending on the given dict specification
55 for pad
in self
.requested
.keys():
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]]
65 if sig_type
== iotypes
['*']:
66 self
.pads
[pad
][mux
] = Record(name
="%s%d" % (sig
, unit
),
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
))
74 def elaborate(self
, platform
):
76 comb
, sync
= m
.d
.comb
, m
.d
.sync
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
)
85 # print(self.requested)
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]
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(
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
)
117 for pad
in list(self
.pads
.keys()):
118 for field
in self
.pads
[pad
]["pad"].fields
.values():
120 for mux
in self
.pads
[pad
].keys():
121 if type(self
.pads
[pad
][mux
]) == Signal
:
122 yield self
.pads
[pad
][mux
]
124 for field
in self
.pads
[pad
][mux
].fields
.values():
131 def set_port(dut
, port
, delay
=1e-6):
132 yield dut
.port
.eq(port
)
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
140 def gpio(gpio
, pad
, data
, delay
=1e-6):
141 # Output test - Control GPIO output
144 n_bits
= len(bin(data
)[2:])
146 for i
in range(0, n_bits
):
147 bit
= (data
>> i
) & 0x1
152 assert data
== read
, f
"GPIO Sent: %x | Pad Read: %x" % (data
, read
)
153 # Input test - Control Pad input
157 for i
in range(0, n_bits
):
158 bit
= (read
>> i
) & 0x1
163 assert read2
== read
, f
"Pad Sent: %x | GPIO Read: %x" % (data
, read
)
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
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
180 yield tx
.eq(0) # start bit
183 # send one byte, lsb first
184 for i
in range(0, 8):
185 bit
= (byte
>> i
) & 0x1
188 test_bit
= yield pad_tx
.o
189 read |
= (test_bit
<< i
)
190 yield tx
.eq(1) # stop bit
192 assert byte
== read
, f
"UART Sent: %x | Pad Read: %x" % (byte
, read
)
193 # Drive Pad i - check word at uart rx
196 yield pad_rx
.i
.eq(0) # start bit
199 for i
in range(0, 8):
200 bit
= (read
>> i
) & 0x1
201 yield pad_rx
.i
.eq(bit
)
204 read2 |
= (test_bit
<< i
)
205 yield pad_rx
.i
.eq(1) # stop bit
207 assert read
== read2
, f
"Pad Sent: %x | UART Read: %x" % (read
, read2
)
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.
215 def i2c_send(sda
, scl
, sda_pad
, byte
, delay
=1e-6):
217 # No pull-up on line implemented, set high instead
222 yield sda_pad
.i
.eq(1)
225 yield sda
.o
.eq(0) # start bit
227 for i
in range(0, 8):
228 bit
= (byte
>> i
) & 0x1
233 temp
= yield sda_pad
.o
236 yield sda
.o
.eq(1) # Master releases SDA line
238 assert byte
== read
, f
"I2C Sent: %x | Pad Read: %x" % (byte
, read
)
240 yield sda_pad
.i
.eq(0)
245 # Send byte back to master
247 for i
in range(0, 8):
248 bit
= (read
>> i
) & 0x1
249 yield sda_pad
.i
.eq(bit
)
256 assert read
== read2
, f
"Pad Sent: %x | I2C Read: %x" % (read
, read2
)
264 # Stop condition - SDA line high after SCL high
269 yield sda
.o
.eq(1) # 'release' the SDA line
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
}]
284 for pad
in requested
.keys():
285 for mux
in requested
[pad
].keys():
286 periph
= requested
[pad
][mux
][0]
289 # [{"padname":%s, "port": %d}, ...]
290 gpios
.append({"padname":pad
, "mux": int(mux
[3])})
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)
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)
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"]
328 yield from set_port(dut
, I2C_MUX
)
329 yield from i2c_send(sda
, scl
, sdapad
, 0x67)
331 def gen_gtkw_doc(module_name
, requested
, filename
):
332 # GTKWave doc generation
335 'in': {'color': 'orange'},
336 'out': {'color': 'yellow'},
337 'debug': {'module': 'top', 'color': 'red'}
339 # Create a trace list, each block expected to be a tuple()
343 for pad
in requested
.keys():
344 temp
= len(requested
[pad
].keys())
347 temp_traces
= ("Pad %s" % pad
, [])
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]
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":
366 temp_traces
[1].append(('tx%d__o' % unit_num
, 'out'))
367 temp_traces
[1].append(('tx%d__oe' % unit_num
, 'out'))
370 temp_traces
[1].append(('rx%d' % unit_num
, 'in'))
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
)
379 temp_traces
= ('Misc', [
380 ('port[%d:0]' % ((n_ports
-1).bit_length()-1), 'in')
382 traces
.append(temp_traces
)
386 write_gtkw(filename
+".gtkw", filename
+".vcd", traces
, style
,
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*']}
401 dut
= ManPinmux(requested
)
402 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
403 with
open(filename
+".il", "w") as f
:
407 m
.submodules
.manpinmux
= dut
411 sim
.add_process(wrap(test_man_pinmux(dut
, requested
)))
412 sim_writer
= sim
.write_vcd(filename
+".vcd")
415 gen_gtkw_doc("top.manpinmux", dut
.requested
, filename
)
417 if __name__
== '__main__':
422 #testspec = PinSpec()
424 'A': (4, 4), # bankname: (num of pins, muxwidth)
434 function_names
= {'TWI0': 'I2C 0',
435 'UART0': 'UART (TX/RX) 0',
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)
445 #print(ps.gpio.pinouts, ps.gpio.bankspec, ps.gpio.pinfn, ps.gpio.fname)
447 desc_dict_keys = ['UART0', 'TWI0', 'GPIOA_A0', 'GPIOA_A1', 'GPIOA_A2',
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)
459 print("---------------------------------")
460 #with open("test.mdwn", "w") as of:
461 # pinout, bankspec, pin_spec, fixedpins = ps.write(of)
462 #print("---------------------------------")
464 bk
= ps
.pinbanks
.keys()
466 muxwidth
= ps
.muxwidths
[bank
]
467 print(bank
, muxwidth
)
468 pinidx
= sorted(ps
.keys())
470 print("---------------------------------")
473 for mux
in range(muxwidth
):
475 print("Mux %d : NC" % mux
)
477 name
, assigned_bank
= pdata
[mux
]
478 print("Mux %d : %s" % (mux
, name
))