fcc8db43c60be0347923759d545d348161823afb
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
.bank
= Signal(log2_int(self
.n_banks
))
57 for pad
in self
.requested
.keys():
59 self
.pads
[pad
]["pad"] = Record(name
=pad
, layout
=io_layout
)
60 self
.muxes
[pad
] = IOMuxBlockSingle(self
.n_banks
)
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
89 # TODO: replace with pin specific
92 for pad
in self
.pads
.keys():
93 m
.submodules
[pad
+"_mux"] = muxes
[pad
]
96 pad0
= self
.pads
["N1"]["pad"]
97 gp0
= self
.pads
["N1"]["mux%d" % GPIO_BANK
]
98 gp1
= self
.pads
["N2"]["mux%d" % GPIO_BANK
]
99 tx
= self
.pads
["N1"]["mux%d" % UART_BANK
]
100 rx
= self
.pads
["N2"]["mux%d" % UART_BANK
]
101 sda
= self
.pads
["N1"]["mux%d" % I2C_BANK
]
102 scl
= self
.pads
["N2"]["mux%d" % I2C_BANK
]
105 comb
+= iomux1
.bank
.eq(bank
)
106 comb
+= iomux2
.bank
.eq(bank
)
108 # ---------------------------
109 # This section is muxing only - doesn'care about pad names
110 # ---------------------------
111 # gpio - gpio0 on Pad1, gpio1 on Pad2
112 comb
+= iomux1
.bank_ports
[GPIO_BANK
].o
.eq(gp0
.o
)
113 comb
+= iomux1
.bank_ports
[GPIO_BANK
].oe
.eq(gp0
.oe
)
114 comb
+= gp0
.i
.eq(iomux1
.bank_ports
[GPIO_BANK
].i
)
115 comb
+= iomux2
.bank_ports
[GPIO_BANK
].o
.eq(gp1
.o
)
116 comb
+= iomux2
.bank_ports
[GPIO_BANK
].oe
.eq(gp1
.oe
)
117 comb
+= gp1
.i
.eq(iomux2
.bank_ports
[GPIO_BANK
].i
)
118 # uart Pad 1 tx, Pad 2 rx
119 comb
+= iomux1
.bank_ports
[UART_BANK
].o
.eq(tx
.o
)
120 comb
+= iomux1
.bank_ports
[UART_BANK
].oe
.eq(tx
.oe
)
121 comb
+= rx
.eq(iomux2
.bank_ports
[UART_BANK
].i
)
122 # i2c Pad 1 sda, Pad 2 scl
123 comb
+= iomux1
.bank_ports
[I2C_BANK
].o
.eq(sda
.o
)
124 comb
+= iomux1
.bank_ports
[I2C_BANK
].oe
.eq(sda
.oe
)
125 comb
+= sda
.i
.eq(iomux1
.bank_ports
[I2C_BANK
].i
)
126 comb
+= iomux2
.bank_ports
[I2C_BANK
].o
.eq(scl
.o
)
127 comb
+= iomux2
.bank_ports
[I2C_BANK
].oe
.eq(scl
.oe
)
128 comb
+= scl
.i
.eq(iomux2
.bank_ports
[I2C_BANK
].i
)
130 # ---------------------------
131 # Here is where the muxes are assigned to the actual pads
132 # ---------------------------
133 # TODO: for-loop to autoconnect muxes to pads (n_pads var?)
134 comb
+= pads
['N1']["pad"].o
.eq(iomux1
.out_port
.o
)
135 comb
+= pads
['N1']["pad"].oe
.eq(iomux1
.out_port
.oe
)
136 comb
+= iomux1
.out_port
.i
.eq(pads
['N1']["pad"].i
)
137 comb
+= pads
['N2']["pad"].o
.eq(iomux2
.out_port
.o
)
138 comb
+= pads
['N2']["pad"].oe
.eq(iomux2
.out_port
.oe
)
139 comb
+= iomux2
.out_port
.i
.eq(pads
['N2']["pad"].i
)
144 for pad
in list(self
.pads
.keys()):
145 for field
in self
.pads
[pad
]["pad"].fields
.values():
147 #for field in self.uart.fields.values():
149 #for field in self.i2c["sda"].fields.values():
151 #for field in self.i2c["scl"].fields.values():
158 def set_bank(dut
, bank
, delay
=1e-6):
159 yield dut
.bank
.eq(bank
)
164 Set the gpio output based on given data sequence, checked at pad.o
165 Then sends the same byte via pad.i to gpio input
167 def gpio(gpio
, pad
, data
, delay
=1e-6):
168 # Output test - Control GPIO output
171 n_bits
= len(bin(data
)[2:])
173 for i
in range(0, n_bits
):
174 bit
= (data
>> i
) & 0x1
179 assert data
== read
, f
"GPIO Sent: %x | Pad Read: %x" % (data
, read
)
180 # Input test - Control Pad input
184 for i
in range(0, n_bits
):
185 bit
= (read
>> i
) & 0x1
190 assert read2
== read
, f
"Pad Sent: %x | GPIO Read: %x" % (data
, read
)
197 Sends a byte via uart tx, checked at output pad
198 Then sends the same byte via input pad to uart rx
199 Input and output pads are different, so must specify both
201 def uart_send(tx
, rx
, pad_tx
, pad_rx
, byte
, delay
=1e-6):
202 # Drive uart tx - check the word seen at the Pad
206 yield tx
.o
.eq(0) # start bit
209 # send one byte, lsb first
210 for i
in range(0, 8):
211 bit
= (byte
>> i
) & 0x1
214 test_bit
= yield pad_tx
.o
215 read |
= (test_bit
<< i
)
216 yield tx
.o
.eq(1) # stop bit
218 assert byte
== read
, f
"UART Sent: %x | Pad Read: %x" % (byte
, read
)
219 # Drive Pad i - check word at uart rx
222 yield pad_rx
.i
.eq(0) # start bit
225 for i
in range(0, 8):
226 bit
= (read
>> i
) & 0x1
227 yield pad_rx
.i
.eq(bit
)
230 read2 |
= (test_bit
<< i
)
231 yield pad_rx
.i
.eq(1) # stop bit
233 assert read
== read2
, f
"Pad Sent: %x | UART Read: %x" % (read
, read2
)
237 Sends a byte via SDA.o (peripheral side), checked at output pad
238 Then sends the same byte via input pad to master SDA.i
239 This transaction doesn't make the distinction between read/write bit.
241 def i2c_send(sda
, scl
, sda_pad
, byte
, delay
=1e-6):
243 # No pull-up on line implemented, set high instead
248 yield sda_pad
.i
.eq(1)
251 yield sda
.o
.eq(0) # start bit
253 for i
in range(0, 8):
254 bit
= (byte
>> i
) & 0x1
259 temp
= yield sda_pad
.o
262 yield sda
.o
.eq(1) # Master releases SDA line
264 assert byte
== read
, f
"I2C Sent: %x | Pad Read: %x" % (byte
, read
)
266 yield sda_pad
.i
.eq(0)
271 # Send byte back to master
273 for i
in range(0, 8):
274 bit
= (read
>> i
) & 0x1
275 yield sda_pad
.i
.eq(bit
)
282 assert read
== read2
, f
"Pad Sent: %x | I2C Read: %x" % (read
, read2
)
290 # Stop condition - SDA line high after SCL high
295 yield sda
.o
.eq(1) # 'release' the SDA line
297 # Test the GPIO/UART/I2C connectivity
298 def test_man_pinmux(dut
, pad_names
):
301 yield from set_bank(dut
, GPIO_BANK
)
302 yield from gpio(dut
.pads
["N1"]["mux%d" % GPIO_BANK
],
303 dut
.pads
["N1"]["pad"], 0x5a5)
304 yield from gpio(dut
.pads
["N2"]["mux%d" % GPIO_BANK
],
305 dut
.pads
["N2"]["pad"], 0x5a5)
307 yield from set_bank(dut
, UART_BANK
)
308 yield from uart_send(dut
.pads
["N1"]["mux%d" % UART_BANK
],
309 dut
.pads
["N2"]["mux%d" % UART_BANK
],
310 dut
.pads
['N1']["pad"], dut
.pads
['N2']["pad"], 0x42)
311 #yield dut.pads['N2'].i.eq(0)
314 yield from set_bank(dut
, I2C_BANK
)
315 yield from i2c_send(dut
.pads
["N1"]["mux%d" % I2C_BANK
],
316 dut
.pads
["N2"]["mux%d" % I2C_BANK
],
317 dut
.pads
['N1']["pad"], 0x67)
319 def sim_man_pinmux():
320 filename
= "test_man_pinmux"
321 pad_names
= ["N1", "N2"]
322 dut
= ManPinmux(pad_names
)
323 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
324 with
open(filename
+".il", "w") as f
:
328 m
.submodules
.manpinmux
= dut
332 sim
.add_process(wrap(test_man_pinmux(dut
, pad_names
)))
333 sim_writer
= sim
.write_vcd(filename
+".vcd")
336 #gen_gtkw_doc("top.manpinmux", dut.n_banks, filename)
338 if __name__
== '__main__':