221961695b450609054ff1172ac7ee9fbbdbb0f8
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
22 from base
import PinSpec
23 from 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
.bank
= Signal(log2_int(self
.n_banks
))
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_banks
)
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
].bank
.eq(bank
)
85 # print(self.requested)
88 # ---------------------------
89 # This section connects the periphs to the assigned banks
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
].bank_ports
[num
].o
.eq(pads
[pad
][mux
].o
)
99 comb
+= muxes
[pad
].bank_ports
[num
].oe
.eq(pads
[pad
][mux
].oe
)
100 comb
+= pads
[pad
][mux
].i
.eq(muxes
[pad
].bank_ports
[num
].i
)
101 elif sig_type
== iotypes
['+']:
102 comb
+= muxes
[pad
].bank_ports
[num
].o
.eq(pads
[pad
][mux
])
103 elif sig_type
== iotypes
['-']:
104 comb
+= pads
[pad
][mux
].eq(muxes
[pad
].bank_ports
[num
].i
)
105 # ---------------------------
106 # Here is where the muxes are assigned to the actual pads
107 # ---------------------------
108 for pad
in pads
.keys():
109 comb
+= pads
[pad
]["pad"].o
.eq(muxes
[pad
].out_port
.o
)
110 comb
+= pads
[pad
]["pad"].oe
.eq(muxes
[pad
].out_port
.oe
)
111 comb
+= muxes
[pad
].out_port
.i
.eq(pads
[pad
]["pad"].i
)
116 for pad
in list(self
.pads
.keys()):
117 for field
in self
.pads
[pad
]["pad"].fields
.values():
119 for mux
in self
.pads
[pad
].keys():
120 if type(self
.pads
[pad
][mux
]) == Signal
:
121 yield self
.pads
[pad
][mux
]
123 for field
in self
.pads
[pad
][mux
].fields
.values():
130 def set_bank(dut
, bank
, delay
=1e-6):
131 yield dut
.bank
.eq(bank
)
136 Set the gpio output based on given data sequence, checked at pad.o
137 Then sends the same byte via pad.i to gpio input
139 def gpio(gpio
, pad
, data
, delay
=1e-6):
140 # Output test - Control GPIO output
143 n_bits
= len(bin(data
)[2:])
145 for i
in range(0, n_bits
):
146 bit
= (data
>> i
) & 0x1
151 assert data
== read
, f
"GPIO Sent: %x | Pad Read: %x" % (data
, read
)
152 # Input test - Control Pad input
156 for i
in range(0, n_bits
):
157 bit
= (read
>> i
) & 0x1
162 assert read2
== read
, f
"Pad Sent: %x | GPIO Read: %x" % (data
, read
)
169 Sends a byte via uart tx, checked at output pad
170 Then sends the same byte via input pad to uart rx
171 Input and output pads are different, so must specify both
173 def uart_send(tx
, rx
, pad_tx
, pad_rx
, byte
, delay
=1e-6):
174 # Drive uart tx - check the word seen at the Pad
179 yield tx
.eq(0) # start bit
182 # send one byte, lsb first
183 for i
in range(0, 8):
184 bit
= (byte
>> i
) & 0x1
187 test_bit
= yield pad_tx
.o
188 read |
= (test_bit
<< i
)
189 yield tx
.eq(1) # stop bit
191 assert byte
== read
, f
"UART Sent: %x | Pad Read: %x" % (byte
, read
)
192 # Drive Pad i - check word at uart rx
195 yield pad_rx
.i
.eq(0) # start bit
198 for i
in range(0, 8):
199 bit
= (read
>> i
) & 0x1
200 yield pad_rx
.i
.eq(bit
)
203 read2 |
= (test_bit
<< i
)
204 yield pad_rx
.i
.eq(1) # stop bit
206 assert read
== read2
, f
"Pad Sent: %x | UART Read: %x" % (read
, read2
)
210 Sends a byte via SDA.o (peripheral side), checked at output pad
211 Then sends the same byte via input pad to master SDA.i
212 This transaction doesn't make the distinction between read/write bit.
214 def i2c_send(sda
, scl
, sda_pad
, byte
, delay
=1e-6):
216 # No pull-up on line implemented, set high instead
221 yield sda_pad
.i
.eq(1)
224 yield sda
.o
.eq(0) # start bit
226 for i
in range(0, 8):
227 bit
= (byte
>> i
) & 0x1
232 temp
= yield sda_pad
.o
235 yield sda
.o
.eq(1) # Master releases SDA line
237 assert byte
== read
, f
"I2C Sent: %x | Pad Read: %x" % (byte
, read
)
239 yield sda_pad
.i
.eq(0)
244 # Send byte back to master
246 for i
in range(0, 8):
247 bit
= (read
>> i
) & 0x1
248 yield sda_pad
.i
.eq(bit
)
255 assert read
== read2
, f
"Pad Sent: %x | I2C Read: %x" % (read
, read2
)
263 # Stop condition - SDA line high after SCL high
268 yield sda
.o
.eq(1) # 'release' the SDA line
270 # Test the GPIO/UART/I2C connectivity
271 def test_man_pinmux(dut
, requested
):
272 # TODO: Convert to automatic
273 # [{"pad":%s, "bank":%d}, {"pad":%s, "bank":%d},...]
274 #gpios = [{"padname":"N1", "bank":GPIO_BANK},
275 # {"padname":"N2", "bank":GPIO_BANK}]
276 # [[txPAD, MUXx, rxPAD, MUXx],...] - diff banks not supported yet
277 uarts
= [{"txpadname":"N1", "rxpadname":"N2", "bank":UART_BANK
}]
278 # [[sdaPAD, MUXx, sclPAD, MUXx],...] - diff banks not supported yet
279 i2cs
= [{"sdapadname":"N1", "sclpadname":"N2", "bank":I2C_BANK
}]
283 for pad
in requested
.keys():
284 for mux
in requested
[pad
].keys():
285 periph
= requested
[pad
][mux
][0]
288 # [{"padname":%s, "bank": %d}, ...]
289 gpios
.append({"padname":pad
, "bank": int(mux
[3])})
298 for gpio_periph
in gpios
:
299 padname
= gpio_periph
["padname"]
300 gpio_bank
= gpio_periph
["bank"]
301 gp
= dut
.pads
[padname
]["mux%d" % gpio_bank
]
302 pad
= dut
.pads
[padname
]["pad"]
303 yield from set_bank(dut
, gpio_bank
)
304 yield from gpio(gp
, pad
, 0x5a5)
307 for uart_periph
in uarts
:
308 txpadname
= uart_periph
["txpadname"]
309 rxpadname
= uart_periph
["rxpadname"]
310 uart_bank
= uart_periph
["bank"]
311 tx
= dut
.pads
[txpadname
]["mux%d" % uart_bank
]
312 rx
= dut
.pads
[rxpadname
]["mux%d" % uart_bank
]
313 txpad
= dut
.pads
[txpadname
]["pad"]
314 rxpad
= dut
.pads
[rxpadname
]["pad"]
315 yield from set_bank(dut
, UART_BANK
)
316 yield from uart_send(tx
, rx
, txpad
, rxpad
, 0x42)
319 for i2c_periph
in i2cs
:
320 sdapadname
= i2c_periph
["sdapadname"]
321 sclpadname
= i2c_periph
["sclpadname"]
322 i2c_bank
= i2c_periph
["bank"]
323 sda
= dut
.pads
[sdapadname
]["mux%d" % i2c_bank
]
324 scl
= dut
.pads
[sclpadname
]["mux%d" % i2c_bank
]
325 sdapad
= dut
.pads
[sdapadname
]["pad"]
327 yield from set_bank(dut
, I2C_BANK
)
328 yield from i2c_send(sda
, scl
, sdapad
, 0x67)
330 def gen_gtkw_doc(module_name
, requested
, filename
):
331 # GTKWave doc generation
334 'in': {'color': 'orange'},
335 'out': {'color': 'yellow'},
336 'debug': {'module': 'top', 'color': 'red'}
338 # Create a trace list, each block expected to be a tuple()
342 for pad
in requested
.keys():
343 temp
= len(requested
[pad
].keys())
346 temp_traces
= ("Pad %s" % pad
, [])
348 temp_traces
[1].append(('%s__i' % pad
, 'in'))
349 temp_traces
[1].append(('%s__o' % pad
, 'out'))
350 temp_traces
[1].append(('%s__oe' % pad
, 'out'))
351 for mux
in requested
[pad
].keys():
352 periph
= requested
[pad
][mux
][0]
353 unit_num
= requested
[pad
][mux
][1]
354 if len(requested
[pad
][mux
]) == 3:
355 pin
= requested
[pad
][mux
][2]
360 temp_traces
[1].append(('gp%d__i' % unit_num
, 'in'))
361 temp_traces
[1].append(('gp%d__o' % unit_num
, 'out'))
362 temp_traces
[1].append(('gp%d__oe' % unit_num
, 'out'))
363 elif periph
== "uart":
365 temp_traces
[1].append(('tx%d__o' % unit_num
, 'out'))
366 temp_traces
[1].append(('tx%d__oe' % unit_num
, 'out'))
369 temp_traces
[1].append(('rx%d' % unit_num
, 'in'))
371 elif periph
== "i2c":
372 temp_traces
[1].append(('%s%d__i' % (pin
, unit_num
), 'in'))
373 temp_traces
[1].append(('%s%d__o' % (pin
, unit_num
), 'out'))
374 temp_traces
[1].append(('%s%d__oe' % (pin
, unit_num
), 'out'))
375 traces
.append(temp_traces
)
378 temp_traces
= ('Misc', [
379 ('bank[%d:0]' % ((n_banks
-1).bit_length()-1), 'in')
381 traces
.append(temp_traces
)
385 write_gtkw(filename
+".gtkw", filename
+".vcd", traces
, style
,
389 def sim_man_pinmux():
390 filename
= "test_man_pinmux"
391 requested
= {"N1": {"mux%d" % GPIO_BANK
: ["gpio", 0, '0*'],
392 "mux%d" % UART_BANK
: ["uart", 0, 'tx+'],
393 "mux%d" % I2C_BANK
: ["i2c", 0, 'sda*']},
394 "N2": {"mux%d" % GPIO_BANK
: ["gpio", 1, '*'],
395 "mux%d" % UART_BANK
: ["uart", 0, 'rx-'],
396 "mux%d" % I2C_BANK
: ["i2c", 0, 'scl*']},
397 "N3": {"mux%d" % GPIO_BANK
: ["gpio", 2, '0*']},
398 "N4": {"mux%d" % GPIO_BANK
: ["gpio", 3, '0*']}
400 dut
= ManPinmux(requested
)
401 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
402 with
open(filename
+".il", "w") as f
:
406 m
.submodules
.manpinmux
= dut
410 sim
.add_process(wrap(test_man_pinmux(dut
, requested
)))
411 sim_writer
= sim
.write_vcd(filename
+".vcd")
414 gen_gtkw_doc("top.manpinmux", dut
.requested
, filename
)
416 if __name__
== '__main__':
421 #testspec = PinSpec()
423 'A': (4, 4), # (num of pads, num of banks)?
433 function_names
= {'TWI0': 'I2C 0',
434 'UART0': 'UART (TX/RX) 0',
436 ps
= PinSpec(pinbanks
, fixedpins
, function_names
)
437 # Unit number, (Bank, pin #), mux, start, num # pins
438 ps
.gpio("", ('A', 0), 0, 0, 4)
439 ps
.uart("0", ('A', 0), 1)
440 ps
.i2c("0", ('A', 0), 2)
443 #print(ps.gpio.pinouts, ps.gpio.bankspec, ps.gpio.pinfn, ps.gpio.fname)
445 desc_dict_keys = ['UART0', 'TWI0', 'GPIOA_A0', 'GPIOA_A1', 'GPIOA_A2', 'GPIOA_A3']
448 desc = {'UART0': 'Basic serial TX/RX serial port',
449 'TWI0': 'I2C interface',
450 'GPIOA_A0': 'Test GPIO0',
451 'GPIOA_A1': 'Test GPIO1',
452 'GPIOA_A2': 'Test GPIO2',
453 'GPIOA_A3': 'Test GPIO3'}
454 ps.add_scenario("Test Manual Pinmux", desc_dict_keys, eint, pwm, desc)
456 print("---------------------------------")
457 #with open("test.mdwn", "w") as of:
458 # pinout, bankspec, pin_spec, fixedpins = ps.write(of)
459 #print("---------------------------------")
461 bk
= ps
.pinbanks
.keys()
463 muxwidth
= ps
.muxwidths
[bank
]
464 print(bank
, muxwidth
)
465 pinidx
= sorted(ps
.keys())
467 print("---------------------------------")
470 for mux
in range(muxwidth
):
472 print("Mux %d : NC" % mux
)
474 name
, assigned_bank
= pdata
[mux
]
475 print("Mux %d : %s" % (mux
, name
))