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 iomux
import IOMuxBlockSingle
23 io_layout
= (("i", 1),
28 uart_layout
= (("rx", 1),
32 uart_tx_layout
= (("o", 1),
40 Really basic example, uart tx/rx and i2c sda/scl pinmux
42 class ManPinmux(Elaboratable
):
43 def __init__(self
, requested
):
44 print("Test Manual Pinmux!")
46 self
.requested
= requested
48 self
.bank
= Signal(log2_int(self
.n_banks
))
51 # Automatically create the necessary periph/pad Records/Signals
52 # depending on the given dict specification
53 for pad
in self
.requested
.keys():
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]
65 self
.pads
[pad
][mux
] = Record(name
="gp%d" % unit_num
,
67 elif periph
== "uart":
69 self
.pads
[pad
][mux
] = Record(name
="tx%d" % unit_num
,
70 layout
=uart_tx_layout
)
72 self
.pads
[pad
][mux
] = Signal(name
="rx%d" % unit_num
)
75 self
.pads
[pad
][mux
] = Record(name
="sda%d" % unit_num
,
78 self
.pads
[pad
][mux
] = Record(name
="scl%d" % unit_num
,
81 def elaborate(self
, platform
):
83 comb
, sync
= m
.d
.comb
, m
.d
.sync
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
)
92 # print(self.requested)
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]
102 if len(self
.requested
[pad
][mux
]) == 3:
103 pin
= self
.requested
[pad
][mux
][2]
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":
112 comb
+= muxes
[pad
].bank_ports
[num
].o
.eq(
114 comb
+= muxes
[pad
].bank_ports
[num
].oe
.eq(
117 comb
+= pads
[pad
][mux
].eq(muxes
[pad
].bank_ports
[num
].i
)
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
)
130 for pad
in list(self
.pads
.keys()):
131 for field
in self
.pads
[pad
]["pad"].fields
.values():
133 for mux
in self
.pads
[pad
].keys():
134 if type(self
.pads
[pad
][mux
]) == Signal
:
135 yield self
.pads
[pad
][mux
]
137 for field
in self
.pads
[pad
][mux
].fields
.values():
144 def set_bank(dut
, bank
, delay
=1e-6):
145 yield dut
.bank
.eq(bank
)
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
153 def gpio(gpio
, pad
, data
, delay
=1e-6):
154 # Output test - Control GPIO output
157 n_bits
= len(bin(data
)[2:])
159 for i
in range(0, n_bits
):
160 bit
= (data
>> i
) & 0x1
165 assert data
== read
, f
"GPIO Sent: %x | Pad Read: %x" % (data
, read
)
166 # Input test - Control Pad input
170 for i
in range(0, n_bits
):
171 bit
= (read
>> i
) & 0x1
176 assert read2
== read
, f
"Pad Sent: %x | GPIO Read: %x" % (data
, read
)
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
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
192 yield tx
.o
.eq(0) # start bit
195 # send one byte, lsb first
196 for i
in range(0, 8):
197 bit
= (byte
>> i
) & 0x1
200 test_bit
= yield pad_tx
.o
201 read |
= (test_bit
<< i
)
202 yield tx
.o
.eq(1) # stop bit
204 assert byte
== read
, f
"UART Sent: %x | Pad Read: %x" % (byte
, read
)
205 # Drive Pad i - check word at uart rx
208 yield pad_rx
.i
.eq(0) # start bit
211 for i
in range(0, 8):
212 bit
= (read
>> i
) & 0x1
213 yield pad_rx
.i
.eq(bit
)
216 read2 |
= (test_bit
<< i
)
217 yield pad_rx
.i
.eq(1) # stop bit
219 assert read
== read2
, f
"Pad Sent: %x | UART Read: %x" % (read
, read2
)
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.
227 def i2c_send(sda
, scl
, sda_pad
, byte
, delay
=1e-6):
229 # No pull-up on line implemented, set high instead
234 yield sda_pad
.i
.eq(1)
237 yield sda
.o
.eq(0) # start bit
239 for i
in range(0, 8):
240 bit
= (byte
>> i
) & 0x1
245 temp
= yield sda_pad
.o
248 yield sda
.o
.eq(1) # Master releases SDA line
250 assert byte
== read
, f
"I2C Sent: %x | Pad Read: %x" % (byte
, read
)
252 yield sda_pad
.i
.eq(0)
257 # Send byte back to master
259 for i
in range(0, 8):
260 bit
= (read
>> i
) & 0x1
261 yield sda_pad
.i
.eq(bit
)
268 assert read
== read2
, f
"Pad Sent: %x | I2C Read: %x" % (read
, read2
)
276 # Stop condition - SDA line high after SCL high
281 yield sda
.o
.eq(1) # 'release' the SDA line
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
}]
296 for pad
in requested
.keys():
297 for mux
in requested
[pad
].keys():
298 periph
= requested
[pad
][mux
][0]
301 # [{"padname":%s, "bank": %d}, ...]
302 gpios
.append({"padname":pad
, "bank": int(mux
[3])})
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)
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)
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"]
340 yield from set_bank(dut
, I2C_BANK
)
341 yield from i2c_send(sda
, scl
, sdapad
, 0x67)
343 def gen_gtkw_doc(module_name
, requested
, filename
):
344 # GTKWave doc generation
347 'in': {'color': 'orange'},
348 'out': {'color': 'yellow'},
349 'debug': {'module': 'top', 'color': 'red'}
351 # Create a trace list, each block expected to be a tuple()
355 for pad
in requested
.keys():
356 temp
= len(requested
[pad
].keys())
359 temp_traces
= ("Pad %s" % pad
, [])
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]
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":
378 temp_traces
[1].append(('tx%d__o' % unit_num
, 'out'))
379 temp_traces
[1].append(('tx%d__oe' % unit_num
, 'out'))
382 temp_traces
[1].append(('rx%d' % unit_num
, 'in'))
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
)
391 temp_traces
= ('Misc', [
392 ('bank[%d:0]' % ((n_banks
-1).bit_length()-1), 'in')
394 traces
.append(temp_traces
)
398 write_gtkw(filename
+".gtkw", filename
+".vcd", traces
, style
,
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]}
413 dut
= ManPinmux(requested
)
414 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
415 with
open(filename
+".il", "w") as f
:
419 m
.submodules
.manpinmux
= dut
423 sim
.add_process(wrap(test_man_pinmux(dut
, requested
)))
424 sim_writer
= sim
.write_vcd(filename
+".vcd")
427 gen_gtkw_doc("top.manpinmux", dut
.requested
, filename
)
429 if __name__
== '__main__':