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
, pad_names
):
44 print("Test Manual Pinmux!")
46 self
.requested
= {"N1": {"mux%d" % GPIO_BANK
: ["gpio", 0],
47 "mux%d" % UART_BANK
: ["uart", 0, "tx"],
48 "mux%d" % I2C_BANK
: ["i2c", 0, "sda"]},
49 "N2": {"mux%d" % GPIO_BANK
: ["gpio", 1],
50 "mux%d" % UART_BANK
: ["uart", 0, "rx"],
51 "mux%d" % I2C_BANK
: ["i2c", 0, "scl"]}
54 self
.iomux1
= IOMuxBlockSingle(self
.n_banks
)
55 self
.iomux2
= IOMuxBlockSingle(self
.n_banks
)
56 self
.bank
= Signal(log2_int(self
.n_banks
))
57 self
.pads
= {pad_names
[0]:{}, pad_names
[1]:{}}
58 for pad
in self
.requested
.keys():
59 self
.pads
[pad
]["pad"] = Record(name
=pad
, layout
=io_layout
)
61 for mux
in self
.requested
[pad
].keys():
62 periph
= self
.requested
[pad
][mux
][0]
63 unit_num
= self
.requested
[pad
][mux
][1]
64 if len(self
.requested
[pad
][mux
]) == 3:
65 pin
= self
.requested
[pad
][mux
][2]
69 self
.pads
[pad
][mux
] = Record(name
="gp%d" % unit_num
,
71 elif periph
== "uart":
73 self
.pads
[pad
][mux
] = Record(name
="tx%d" % unit_num
,
74 layout
=uart_tx_layout
)
76 self
.pads
[pad
][mux
] = Signal(name
="rx%d" % unit_num
)
79 self
.pads
[pad
][mux
] = Record(name
="sda%d" % unit_num
,
82 self
.pads
[pad
][mux
] = Record(name
="scl%d" % unit_num
,
85 def elaborate(self
, platform
):
87 comb
, sync
= m
.d
.comb
, m
.d
.sync
90 m
.submodules
.iomux1
= iomux1
91 m
.submodules
.iomux2
= iomux2
94 pad0
= self
.pads
["N1"]["pad"]
95 gp0
= self
.pads
["N1"]["mux%d" % GPIO_BANK
]
96 gp1
= self
.pads
["N2"]["mux%d" % GPIO_BANK
]
97 tx
= self
.pads
["N1"]["mux%d" % UART_BANK
]
98 rx
= self
.pads
["N2"]["mux%d" % UART_BANK
]
99 sda
= self
.pads
["N1"]["mux%d" % I2C_BANK
]
100 scl
= self
.pads
["N2"]["mux%d" % I2C_BANK
]
103 comb
+= iomux1
.bank
.eq(bank
)
104 comb
+= iomux2
.bank
.eq(bank
)
106 # ---------------------------
107 # This section is muxing only - doesn'care about pad names
108 # ---------------------------
109 # gpio - gpio0 on Pad1, gpio1 on Pad2
110 comb
+= iomux1
.bank_ports
[GPIO_BANK
].o
.eq(gp0
.o
)
111 comb
+= iomux1
.bank_ports
[GPIO_BANK
].oe
.eq(gp0
.oe
)
112 comb
+= gp0
.i
.eq(iomux1
.bank_ports
[GPIO_BANK
].i
)
113 comb
+= iomux2
.bank_ports
[GPIO_BANK
].o
.eq(gp1
.o
)
114 comb
+= iomux2
.bank_ports
[GPIO_BANK
].oe
.eq(gp1
.oe
)
115 comb
+= gp1
.i
.eq(iomux2
.bank_ports
[GPIO_BANK
].i
)
116 # uart Pad 1 tx, Pad 2 rx
117 comb
+= iomux1
.bank_ports
[UART_BANK
].o
.eq(tx
.o
)
118 comb
+= iomux1
.bank_ports
[UART_BANK
].oe
.eq(tx
.oe
)
119 comb
+= rx
.eq(iomux2
.bank_ports
[UART_BANK
].i
)
120 # i2c Pad 1 sda, Pad 2 scl
121 comb
+= iomux1
.bank_ports
[I2C_BANK
].o
.eq(sda
.o
)
122 comb
+= iomux1
.bank_ports
[I2C_BANK
].oe
.eq(sda
.oe
)
123 comb
+= sda
.i
.eq(iomux1
.bank_ports
[I2C_BANK
].i
)
124 comb
+= iomux2
.bank_ports
[I2C_BANK
].o
.eq(scl
.o
)
125 comb
+= iomux2
.bank_ports
[I2C_BANK
].oe
.eq(scl
.oe
)
126 comb
+= scl
.i
.eq(iomux2
.bank_ports
[I2C_BANK
].i
)
128 # ---------------------------
129 # Here is where the muxes are assigned to the actual pads
130 # ---------------------------
131 # TODO: for-loop to autoconnect muxes to pads (n_pads var?)
132 comb
+= pads
['N1']["pad"].o
.eq(iomux1
.out_port
.o
)
133 comb
+= pads
['N1']["pad"].oe
.eq(iomux1
.out_port
.oe
)
134 comb
+= iomux1
.out_port
.i
.eq(pads
['N1']["pad"].i
)
135 comb
+= pads
['N2']["pad"].o
.eq(iomux2
.out_port
.o
)
136 comb
+= pads
['N2']["pad"].oe
.eq(iomux2
.out_port
.oe
)
137 comb
+= iomux2
.out_port
.i
.eq(pads
['N2']["pad"].i
)
142 for pad
in list(self
.pads
.keys()):
143 for field
in self
.pads
[pad
]["pad"].fields
.values():
145 #for field in self.uart.fields.values():
147 #for field in self.i2c["sda"].fields.values():
149 #for field in self.i2c["scl"].fields.values():
156 def set_bank(dut
, bank
, delay
=1e-6):
157 yield dut
.bank
.eq(bank
)
162 Set the gpio output based on given data sequence, checked at pad.o
163 Then sends the same byte via pad.i to gpio input
165 def gpio(gpio
, pad
, data
, delay
=1e-6):
166 # Output test - Control GPIO output
169 n_bits
= len(bin(data
)[2:])
171 for i
in range(0, n_bits
):
172 bit
= (data
>> i
) & 0x1
177 assert data
== read
, f
"GPIO Sent: %x | Pad Read: %x" % (data
, read
)
178 # Input test - Control Pad input
182 for i
in range(0, n_bits
):
183 bit
= (read
>> i
) & 0x1
188 assert read2
== read
, f
"Pad Sent: %x | GPIO Read: %x" % (data
, read
)
195 Sends a byte via uart tx, checked at output pad
196 Then sends the same byte via input pad to uart rx
197 Input and output pads are different, so must specify both
199 def uart_send(tx
, rx
, pad_tx
, pad_rx
, byte
, delay
=1e-6):
200 # Drive uart tx - check the word seen at the Pad
204 yield tx
.o
.eq(0) # start bit
207 # send one byte, lsb first
208 for i
in range(0, 8):
209 bit
= (byte
>> i
) & 0x1
212 test_bit
= yield pad_tx
.o
213 read |
= (test_bit
<< i
)
214 yield tx
.o
.eq(1) # stop bit
216 assert byte
== read
, f
"UART Sent: %x | Pad Read: %x" % (byte
, read
)
217 # Drive Pad i - check word at uart rx
220 yield pad_rx
.i
.eq(0) # start bit
223 for i
in range(0, 8):
224 bit
= (read
>> i
) & 0x1
225 yield pad_rx
.i
.eq(bit
)
228 read2 |
= (test_bit
<< i
)
229 yield pad_rx
.i
.eq(1) # stop bit
231 assert read
== read2
, f
"Pad Sent: %x | UART Read: %x" % (read
, read2
)
235 Sends a byte via SDA.o (peripheral side), checked at output pad
236 Then sends the same byte via input pad to master SDA.i
237 This transaction doesn't make the distinction between read/write bit.
239 def i2c_send(sda
, scl
, sda_pad
, byte
, delay
=1e-6):
241 # No pull-up on line implemented, set high instead
246 yield sda_pad
.i
.eq(1)
249 yield sda
.o
.eq(0) # start bit
251 for i
in range(0, 8):
252 bit
= (byte
>> i
) & 0x1
257 temp
= yield sda_pad
.o
260 yield sda
.o
.eq(1) # Master releases SDA line
262 assert byte
== read
, f
"I2C Sent: %x | Pad Read: %x" % (byte
, read
)
264 yield sda_pad
.i
.eq(0)
269 # Send byte back to master
271 for i
in range(0, 8):
272 bit
= (read
>> i
) & 0x1
273 yield sda_pad
.i
.eq(bit
)
280 assert read
== read2
, f
"Pad Sent: %x | I2C Read: %x" % (read
, read2
)
288 # Stop condition - SDA line high after SCL high
293 yield sda
.o
.eq(1) # 'release' the SDA line
295 # Test the GPIO/UART/I2C connectivity
296 def test_man_pinmux(dut
, pad_names
):
299 yield from set_bank(dut
, GPIO_BANK
)
300 yield from gpio(dut
.pads
["N1"]["mux%d" % GPIO_BANK
],
301 dut
.pads
["N1"]["pad"], 0x5a5)
302 yield from gpio(dut
.pads
["N2"]["mux%d" % GPIO_BANK
],
303 dut
.pads
["N2"]["pad"], 0x5a5)
305 yield from set_bank(dut
, UART_BANK
)
306 yield from uart_send(dut
.pads
["N1"]["mux%d" % UART_BANK
],
307 dut
.pads
["N2"]["mux%d" % UART_BANK
],
308 dut
.pads
['N1']["pad"], dut
.pads
['N2']["pad"], 0x42)
309 #yield dut.pads['N2'].i.eq(0)
312 yield from set_bank(dut
, I2C_BANK
)
313 yield from i2c_send(dut
.pads
["N1"]["mux%d" % I2C_BANK
],
314 dut
.pads
["N2"]["mux%d" % I2C_BANK
],
315 dut
.pads
['N1']["pad"], 0x67)
317 def sim_man_pinmux():
318 filename
= "test_man_pinmux"
319 pad_names
= ["N1", "N2"]
320 dut
= ManPinmux(pad_names
)
321 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
322 with
open(filename
+".il", "w") as f
:
326 m
.submodules
.manpinmux
= dut
330 sim
.add_process(wrap(test_man_pinmux(dut
, pad_names
)))
331 sim_writer
= sim
.write_vcd(filename
+".vcd")
334 #gen_gtkw_doc("top.manpinmux", dut.n_banks, filename)
336 if __name__
== '__main__':