378d590331e270c9b2b9ed3c68660cda46c16bc6
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),
38 Really basic example, uart tx/rx and i2c sda/scl pinmux
40 class ManPinmux(Elaboratable
):
41 def __init__(self
, pad_names
):
42 print("Test Manual Pinmux!")
44 self
.iomux1
= IOMuxBlockSingle(self
.n_banks
)
45 self
.iomux2
= IOMuxBlockSingle(self
.n_banks
)
48 self
.pads
[pad
] = Record(name
=pad
, layout
=io_layout
)
49 self
.gpio
= {"0": Record(name
="gp0", layout
=io_layout
),
50 "1": Record(name
="gp1", layout
=io_layout
)
52 self
.uart
= Record(name
="uart", layout
=uart_layout
)
53 self
.i2c
= {"sda": Record(name
="sda", layout
=io_layout
),
54 "scl": Record(name
="scl", layout
=io_layout
)
56 self
.bank
= Signal(log2_int(self
.n_banks
))
58 def elaborate(self
, platform
):
60 comb
, sync
= m
.d
.comb
, m
.d
.sync
63 m
.submodules
.iomux1
= iomux1
64 m
.submodules
.iomux2
= iomux2
72 comb
+= iomux1
.bank
.eq(bank
)
73 comb
+= iomux2
.bank
.eq(bank
)
75 # ---------------------------
76 # This section is muxing only - doesn'care about pad names
77 # ---------------------------
78 # gpio - gpio0 on Pad1, gpio1 on Pad2
79 comb
+= iomux1
.bank_ports
[GPIO_BANK
].o
.eq(gpio
["0"].o
)
80 comb
+= iomux1
.bank_ports
[GPIO_BANK
].oe
.eq(gpio
["0"].oe
)
81 comb
+= gpio
["0"].i
.eq(iomux1
.bank_ports
[GPIO_BANK
].i
)
82 comb
+= iomux2
.bank_ports
[GPIO_BANK
].o
.eq(gpio
["1"].o
)
83 comb
+= iomux2
.bank_ports
[GPIO_BANK
].oe
.eq(gpio
["1"].oe
)
84 comb
+= gpio
["1"].i
.eq(iomux2
.bank_ports
[GPIO_BANK
].i
)
85 # uart Pad 1 tx, Pad 2 rx
86 comb
+= iomux1
.bank_ports
[UART_BANK
].o
.eq(uart
.tx
)
87 comb
+= iomux1
.bank_ports
[UART_BANK
].oe
.eq(uart
.oe
)
88 comb
+= uart
.rx
.eq(iomux2
.bank_ports
[UART_BANK
].i
)
89 # i2c Pad 1 sda, Pad 2 scl
90 comb
+= iomux1
.bank_ports
[I2C_BANK
].o
.eq(i2c
["sda"].o
)
91 comb
+= iomux1
.bank_ports
[I2C_BANK
].oe
.eq(i2c
["sda"].oe
)
92 comb
+= i2c
["sda"].i
.eq(iomux1
.bank_ports
[I2C_BANK
].i
)
93 comb
+= iomux2
.bank_ports
[I2C_BANK
].o
.eq(i2c
["scl"].o
)
94 comb
+= iomux2
.bank_ports
[I2C_BANK
].oe
.eq(i2c
["scl"].oe
)
95 comb
+= i2c
["scl"].i
.eq(iomux2
.bank_ports
[I2C_BANK
].i
)
97 # ---------------------------
98 # Here is where the muxes are assigned to the actual pads
99 # ---------------------------
100 # TODO: for-loop to autoconnect muxes to pads (n_pads var?)
101 comb
+= pads
['N1'].o
.eq(iomux1
.out_port
.o
)
102 comb
+= pads
['N1'].oe
.eq(iomux1
.out_port
.oe
)
103 comb
+= iomux1
.out_port
.i
.eq(pads
['N1'].i
)
104 comb
+= pads
['N2'].o
.eq(iomux2
.out_port
.o
)
105 comb
+= pads
['N2'].oe
.eq(iomux2
.out_port
.oe
)
106 comb
+= iomux2
.out_port
.i
.eq(pads
['N2'].i
)
108 #temp for testing - connect pad rx-tx
109 #comb += pad2.i.eq(pad1.o)
114 for pad
in list(self
.pads
.keys()):
115 for field
in self
.pads
[pad
].fields
.values():
117 for field
in self
.uart
.fields
.values():
119 for field
in self
.i2c
["sda"].fields
.values():
121 for field
in self
.i2c
["scl"].fields
.values():
128 def set_bank(dut
, bank
, delay
=1e-6):
129 yield dut
.bank
.eq(bank
)
134 Set the gpio output based on given data sequence, checked at pad.o
135 Then sends the same byte via pad.i to gpio input
137 def gpio(gpio
, pad
, data
, delay
=1e-6):
138 # Output test - Control GPIO output
141 n_bits
= len(bin(data
)[2:])
143 for i
in range(0, n_bits
):
144 bit
= (data
>> i
) & 0x1
149 assert data
== read
, f
"GPIO Sent: %x | Pad Read: %x" % (data
, read
)
150 # Input test - Control Pad input
154 for i
in range(0, n_bits
):
155 bit
= (read
>> i
) & 0x1
160 assert read2
== read
, f
"Pad Sent: %x | GPIO Read: %x" % (data
, read
)
167 Sends a byte via uart tx, checked at output pad
168 Then sends the same byte via input pad to uart rx
169 Input and output pads are different, so must specify both
171 def uart_send(uart
, pad_o
, pad_i
, byte
, delay
=1e-6):
172 # Drive uart tx - check the word seen at the Pad
176 yield uart
.tx
.eq(0) # start bit
179 # send one byte, lsb first
180 for i
in range(0, 8):
181 bit
= (byte
>> i
) & 0x1
182 yield uart
.tx
.eq(bit
)
184 test_bit
= yield pad_o
185 read |
= (test_bit
<< i
)
186 yield uart
.tx
.eq(1) # stop bit
188 assert byte
== read
, f
"UART Sent: %x | Pad Read: %x" % (byte
, read
)
189 # Drive Pad i - check word at uart rx
192 yield pad_i
.eq(0) # start bit
195 for i
in range(0, 8):
196 bit
= (read
>> i
) & 0x1
199 test_bit
= yield uart
.rx
200 read2 |
= (test_bit
<< i
)
201 yield pad_i
.eq(1) # stop bit
203 assert read
== read2
, f
"Pad Sent: %x | UART Read: %x" % (read
, read2
)
206 def i2c_send(sda
, scl
, sda_pad_i
, byte
, delay
=1e-6):
208 # No pull-up on line implemented, set high instead
213 yield sda_pad_i
.eq(1)
215 yield sda
.o
.eq(0) # start bit
217 for i
in range(0, 8):
218 bit
= (byte
>> i
) & 0x1
224 yield sda
.o
.eq(1) # Master releases SDA line
226 yield sda_pad_i
.eq(0) # ACK
228 yield sda_pad_i
.eq(1)
232 def test_man_pinmux(dut
, pad_names
):
235 yield from gpio(dut
.gpio
['0'], dut
.pads
['N1'], 0x5a5)
236 yield from gpio(dut
.gpio
['1'], dut
.pads
['N2'], 0x5a5)
238 yield from set_bank(dut
, UART_BANK
)
239 yield from uart_send(dut
.uart
, dut
.pads
['N1'].o
, dut
.pads
['N2'].i
, 0x42)
240 yield dut
.pads
['N2'].i
.eq(0)
243 yield from set_bank(dut
, I2C_BANK
)
244 yield from i2c_send(dut
.i2c
['sda'], dut
.i2c
['scl'], dut
.pads
['N1'].i
, 0x67)
246 yield dut
.gpio
['0'].oe
.eq(1)
248 yield dut
.gpio
['0'].oe
.eq(0)
251 def sim_man_pinmux():
252 filename
= "test_man_pinmux"
253 pad_names
= ["N1", "N2"]
254 dut
= ManPinmux(pad_names
)
255 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
256 with
open(filename
+".il", "w") as f
:
260 m
.submodules
.manpinmux
= dut
264 sim
.add_process(wrap(test_man_pinmux(dut
, pad_names
)))
265 sim_writer
= sim
.write_vcd(filename
+".vcd")
268 #gen_gtkw_doc("top.manpinmux", dut.n_banks, filename)
270 if __name__
== '__main__':