7c966655187f90bc7f6ec1f0373317fc015d2b28
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
, ps
):
49 print("Test Manual Pinmux!")
50 self
.gen_pinmux_dict(ps
)
52 # Automatically create the necessary periph/pad Records/Signals
53 # depending on the given dict specification
54 for pad
in self
.requested
.keys():
56 self
.pads
[pad
]["pad"] = Record(name
=pad
, layout
=io_layout
)
57 self
.muxes
[pad
] = IOMuxBlockSingle(self
.n_ports
)
58 for mux
in self
.requested
[pad
].keys():
59 periph
= self
.requested
[pad
][mux
]["periph"]
60 suffix
= self
.requested
[pad
][mux
]["suffix"]
61 sig
= self
.requested
[pad
][mux
]["signal"][:-1]
62 sig_type
= iotypes
[self
.requested
[pad
][mux
]["signal"][-1]]
64 if sig_type
== iotypes
['*']:
65 self
.pads
[pad
][mux
] = Record(name
="%s%s" % (sig
, suffix
),
67 elif sig_type
== iotypes
['+']:
68 self
.pads
[pad
][mux
] = Signal(name
="%s%s_o" % (sig
, suffix
))
69 elif sig_type
== iotypes
['-']:
70 self
.pads
[pad
][mux
] = Signal(name
="%s%s_i" % (sig
, suffix
))
73 def elaborate(self
, platform
):
75 comb
, sync
= m
.d
.comb
, m
.d
.sync
79 for pad
in pads
.keys():
80 m
.submodules
[pad
+"_mux"] = muxes
[pad
]
81 # all muxes controlled by the same multi-bit signal
82 comb
+= muxes
[pad
].port
.eq(port
)
84 # print(self.requested)
87 # ---------------------------
88 # This section connects the periphs to the assigned ports
89 # ---------------------------
90 for pad
in pads
.keys():
91 for mux
in self
.requested
[pad
].keys():
92 periph
= self
.requested
[pad
][mux
]["periph"]
93 #suffix = self.requested[pad][mux]["suffix"]
94 sig
= self
.requested
[pad
][mux
]["signal"][:-1]
95 sig_type
= iotypes
[self
.requested
[pad
][mux
]["signal"][-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 gen_pinmux_dict(self
, ps
):
132 #print("---------------------------------")
133 #with open("test.mdwn", "w") as of:
134 # pinout, bankspec, pin_spec, fixedpins = ps.write(of)
135 #print("---------------------------------")
142 self
.port
= Signal(log2_int(self
.n_ports
))
146 # Create local list of peripheral names defined in pinfunctions.py
148 for pfunc
in pinspec
:
149 defined_func
.append(pfunc
[0])
151 for pin
in ps
.items():
153 for mux
in pin
[1].keys():
154 bank
= pin
[1][mux
][1]
155 signal_str
= pin
[1][mux
][0]
156 pad
= "%s%d" % (bank
, pin_no
)
157 # Get the signal name prefix
158 index_under
= signal_str
.find('_')
160 periph format: [periph+suffix]
161 GPIO periph format: [periph+bank+suffix]
162 Problem is that GPIO has a different suffix to UART/TWI.
163 Assuming that other peripherals may have their own name formats.
164 keep stripping last chars from string until remainder matches
165 one of the existing peripheral names
166 probably very inefficient...
169 periph
= signal_str
[:index_under
]
170 func
= signal_str
[index_under
+1:]
172 if periph
in defined_func
:
173 break # Found valid periph
174 periph
= periph
.rstrip(periph
[-1])
176 # flag for peripheral string, needed as GPIO has a diff format
177 # to UART and TWI, TODO: may need to check for other periph
179 check_string
= periph
+ bank
181 check_string
= periph
183 # Find the suffix for the specified periph/pin
185 for a
in ps
.fnspec
.items():
187 if check_string
in key
:
188 print(key
, a
[1][key
])
189 suffix
= a
[1][key
].suffix
193 # key to use in PinSpec.byspec has format: [perith+':'+suffix]
194 # need to get the suffix from Pin object
196 #print(signal_str[index:index_under])
198 for sig_spec
in ps
.byspec
[periph
+':'+suffix
]:
201 #suffix = ps.fnspec[fnspec_key][fnspec_key]
202 print(pad
, signal_str
, signal_str
[:index_under
],
203 periph
, func
, suffix
, signal
, mux
)
204 print("Now adding to internal pinmux dict")
205 if not (pad
in self
.requested
.keys()):
206 self
.requested
[pad
] = {}
207 self
.requested
[pad
][mux
] = {"periph":periph
, "suffix":suffix
,
209 print(self
.requested
)
211 def set_port(dut
, port
, delay
=1e-6):
212 yield dut
.port
.eq(port
)
217 Set the gpio output based on given data sequence, checked at pad.o
218 Then sends the same byte via pad.i to gpio input
220 def gpio(gpio
, pad
, data
, delay
=1e-6):
221 # Output test - Control GPIO output
224 n_bits
= len(bin(data
)[2:])
226 for i
in range(0, n_bits
):
227 bit
= (data
>> i
) & 0x1
232 assert data
== read
, f
"GPIO Sent: %x | Pad Read: %x" % (data
, read
)
233 # Input test - Control Pad input
237 for i
in range(0, n_bits
):
238 bit
= (read
>> i
) & 0x1
243 assert read2
== read
, f
"Pad Sent: %x | GPIO Read: %x" % (data
, read
)
250 Sends a byte via uart tx, checked at output pad
251 Then sends the same byte via input pad to uart rx
252 Input and output pads are different, so must specify both
254 def uart_send(tx
, rx
, pad_tx
, pad_rx
, byte
, delay
=1e-6):
255 # Drive uart tx - check the word seen at the Pad
260 yield tx
.eq(0) # start bit
263 # send one byte, lsb first
264 for i
in range(0, 8):
265 bit
= (byte
>> i
) & 0x1
268 test_bit
= yield pad_tx
.o
269 read |
= (test_bit
<< i
)
270 yield tx
.eq(1) # stop bit
272 assert byte
== read
, f
"UART Sent: %x | Pad Read: %x" % (byte
, read
)
273 # Drive Pad i - check word at uart rx
276 yield pad_rx
.i
.eq(0) # start bit
279 for i
in range(0, 8):
280 bit
= (read
>> i
) & 0x1
281 yield pad_rx
.i
.eq(bit
)
284 read2 |
= (test_bit
<< i
)
285 yield pad_rx
.i
.eq(1) # stop bit
287 assert read
== read2
, f
"Pad Sent: %x | UART Read: %x" % (read
, read2
)
291 Sends a byte via SDA.o (peripheral side), checked at output pad
292 Then sends the same byte via input pad to master SDA.i
293 This transaction doesn't make the distinction between read/write bit.
295 def i2c_send(sda
, scl
, sda_pad
, byte
, delay
=1e-6):
297 # No pull-up on line implemented, set high instead
302 yield sda_pad
.i
.eq(1)
305 yield sda
.o
.eq(0) # start bit
307 for i
in range(0, 8):
308 bit
= (byte
>> i
) & 0x1
313 temp
= yield sda_pad
.o
316 yield sda
.o
.eq(1) # Master releases SDA line
318 assert byte
== read
, f
"I2C Sent: %x | Pad Read: %x" % (byte
, read
)
320 yield sda_pad
.i
.eq(0)
325 # Send byte back to master
327 for i
in range(0, 8):
328 bit
= (read
>> i
) & 0x1
329 yield sda_pad
.i
.eq(bit
)
336 assert read
== read2
, f
"Pad Sent: %x | I2C Read: %x" % (read
, read2
)
344 # Stop condition - SDA line high after SCL high
349 yield sda
.o
.eq(1) # 'release' the SDA line
351 # Test the GPIO/UART/I2C connectivity
352 def test_man_pinmux(dut
):
353 requested
= dut
.requested
354 # TODO: Convert to automatic
355 # [{"pad":%s, "port":%d}, {"pad":%s, "port":%d},...]
356 #gpios = [{"padname":"N1", "port":GPIO_MUX},
357 # {"padname":"N2", "port":GPIO_MUX}]
358 # [[txPAD, MUXx, rxPAD, MUXx],...] - diff ports not supported yet
359 #uarts = [{"txpadname":"N1", "rxpadname":"N2", "mux":UART_MUX}]
361 # [[sdaPAD, MUXx, sclPAD, MUXx],...] - diff ports not supported yet
362 #i2cs = [{"sdapadname":"N1", "sclpadname":"N2", "mux":I2C_MUX}]
367 for pad
in requested
.keys():
368 for mux
in requested
[pad
].keys():
369 periph
= requested
[pad
][mux
]["periph"]
370 suffix
= requested
[pad
][mux
]["suffix"]
372 # [{"padname":%s, "port": %d}, ...]
373 gpios
.append({"padname":pad
, "mux": mux
})
375 # Make sure dict exists
376 if not (suffix
in uarts
.keys()):
379 if requested
[pad
][mux
]["signal"][:-1] == "TX":
380 uarts
[suffix
]["txpadname"] = pad
381 uarts
[suffix
]["txmux"] = mux
382 elif requested
[pad
][mux
]["signal"][:-1] == "RX":
383 uarts
[suffix
]["rxpadname"] = pad
384 uarts
[suffix
]["rxmux"] = mux
386 if not (suffix
in i2cs
.keys()):
388 if requested
[pad
][mux
]["signal"][:-1] == "SDA":
389 i2cs
[suffix
]["sdapadname"] = pad
390 i2cs
[suffix
]["sdamux"] = mux
391 elif requested
[pad
][mux
]["signal"][:-1] == "SCL":
392 i2cs
[suffix
]["sclpadname"] = pad
393 i2cs
[suffix
]["sclmux"] = mux
399 for gpio_periph
in gpios
:
400 padname
= gpio_periph
["padname"]
401 gpio_port
= gpio_periph
["mux"]
402 gp
= dut
.pads
[padname
][gpio_port
]
403 pad
= dut
.pads
[padname
]["pad"]
404 yield from set_port(dut
, gpio_port
)
405 yield from gpio(gp
, pad
, 0x5a5)
408 for suffix
in uarts
.keys():
409 txpadname
= uarts
[suffix
]["txpadname"]
410 rxpadname
= uarts
[suffix
]["rxpadname"]
411 uart_port
= uarts
[suffix
]["txmux"] # TODO: Assuming same mux setting
412 tx
= dut
.pads
[txpadname
][uart_port
]
413 rx
= dut
.pads
[rxpadname
][uart_port
]
414 txpad
= dut
.pads
[txpadname
]["pad"]
415 rxpad
= dut
.pads
[rxpadname
]["pad"]
416 yield from set_port(dut
, UART_MUX
)
417 yield from uart_send(tx
, rx
, txpad
, rxpad
, 0x42)
420 for suffix
in i2cs
.keys():
421 sdapadname
= i2cs
[suffix
]["sdapadname"]
422 sclpadname
= i2cs
[suffix
]["sclpadname"]
423 i2c_port
= i2cs
[suffix
]["sdamux"] # TODO: Assuming same mux setting
424 sda
= dut
.pads
[sdapadname
][i2c_port
]
425 scl
= dut
.pads
[sclpadname
][i2c_port
]
426 sdapad
= dut
.pads
[sdapadname
]["pad"]
428 yield from set_port(dut
, I2C_MUX
)
429 yield from i2c_send(sda
, scl
, sdapad
, 0x67)
431 def gen_gtkw_doc(module_name
, requested
, filename
):
432 # GTKWave doc generation
435 'in': {'color': 'orange'},
436 'out': {'color': 'yellow'},
437 'debug': {'module': 'top', 'color': 'red'}
439 # Create a trace list, each block expected to be a tuple()
443 for pad
in requested
.keys():
444 temp
= len(requested
[pad
].keys())
447 temp_traces
= ("Pad %s" % pad
, [])
449 temp_traces
[1].append(('%s__i' % pad
, 'in'))
450 temp_traces
[1].append(('%s__o' % pad
, 'out'))
451 temp_traces
[1].append(('%s__oe' % pad
, 'out'))
452 for mux
in requested
[pad
].keys():
453 periph
= requested
[pad
][mux
]["periph"]
454 suffix
= requested
[pad
][mux
]["suffix"]
456 pin
= requested
[pad
][mux
]["signal"][:-1]
459 temp_traces
[1].append(('gp%d__i' % suffix
, 'in'))
460 temp_traces
[1].append(('gp%d__o' % suffix
, 'out'))
461 temp_traces
[1].append(('gp%d__oe' % suffix
, 'out'))
462 elif periph
== "uart":
464 temp_traces
[1].append(('tx%d__o' % suffix
, 'out'))
465 temp_traces
[1].append(('tx%d__oe' % suffix
, 'out'))
468 temp_traces
[1].append(('rx%d' % suffix
, 'in'))
470 elif periph
== "i2c":
471 temp_traces
[1].append(('%s%d__i' % (pin
, suffix
), 'in'))
472 temp_traces
[1].append(('%s%d__o' % (pin
, suffix
), 'out'))
473 temp_traces
[1].append(('%s%d__oe' % (pin
, suffix
), 'out'))
474 traces
.append(temp_traces
)
477 temp_traces
= ('Misc', [
478 ('port[%d:0]' % ((n_ports
-1).bit_length()-1), 'in')
480 traces
.append(temp_traces
)
484 write_gtkw(filename
+".gtkw", filename
+".vcd", traces
, style
,
488 def sim_man_pinmux(ps
):
489 filename
= "test_man_pinmux"
491 requested = {"N1": {"mux%d" % GPIO_MUX: ["gpio", 0, '0*'],
492 "mux%d" % UART_MUX: ["uart", 0, 'tx+'],
493 "mux%d" % I2C_MUX: ["i2c", 0, 'sda*']},
494 "N2": {"mux%d" % GPIO_MUX: ["gpio", 1, '*'],
495 "mux%d" % UART_MUX: ["uart", 0, 'rx-'],
496 "mux%d" % I2C_MUX: ["i2c", 0, 'scl*']},
497 "N3": {"mux%d" % GPIO_MUX: ["gpio", 2, '0*']},
498 "N4": {"mux%d" % GPIO_MUX: ["gpio", 3, '0*']}
502 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
503 with
open(filename
+".il", "w") as f
:
507 m
.submodules
.manpinmux
= dut
511 sim
.add_process(wrap(test_man_pinmux(dut
)))
512 sim_writer
= sim
.write_vcd(filename
+".vcd")
515 gen_gtkw_doc("top.manpinmux", dut
.requested
, filename
)
518 if __name__
== '__main__':
522 #testspec = PinSpec()
524 'A': (4, 4), # bankname: (num of pins, muxwidth)
534 function_names
= {'TWI0': 'I2C 0',
535 'UART0': 'UART (TX/RX) 0',
537 ps
= PinSpec(pinbanks
, fixedpins
, function_names
)
538 # Unit number, (Bank, pin #), mux, start, num # pins
539 ps
.gpio("", ('A', 0), 0, 0, 4)
540 ps
.gpio("2", ('B', 0), 0, 0, 2)
541 ps
.uart("0", ('A', 0), 1)
542 ps
.i2c("0", ('A', 0), 2)
546 desc_dict_keys = ['UART0', 'TWI0', 'GPIOA_A0', 'GPIOA_A1', 'GPIOA_A2',
550 desc = {'UART0': 'Basic serial TX/RX serial port',
551 'TWI0': 'I2C interface',
552 'GPIOA_A0': 'Test GPIO0',
553 'GPIOA_A1': 'Test GPIO1',
554 'GPIOA_A2': 'Test GPIO2',
555 'GPIOA_A3': 'Test GPIO3'}
556 ps.add_scenario("Test Manual Pinmux", desc_dict_keys, eint, pwm, desc)
559 #code.interact(local=locals())