8eb1f92037ce4b1f9cb848ad63c27f95f7cd9801
[pinmux.git] / src / spec / stage2.py
1 #!/usr/bin/env python3
2 """
3 pinmux documented here https://libre-soc.org/docs/pinmux/
4 """
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
12
13 from nmutil.gtkw import write_gtkw
14
15 cxxsim = False
16 if cxxsim:
17 from nmigen.sim.cxxsim import Simulator, Settle, Delay
18 else:
19 from nmigen.sim import Simulator, Settle, Delay
20
21 from iomux import IOMuxBlockSingle
22
23 io_layout = (("i", 1),
24 ("oe", 1),
25 ("o", 1)
26 )
27
28 uart_layout = (("rx", 1),
29 ("tx", 1),
30 ("oe", 1)
31 )
32 uart_tx_layout = (("o", 1),
33 ("oe", 1)
34 )
35 GPIO_BANK = 0
36 UART_BANK = 1
37 I2C_BANK = 2
38
39 """
40 Really basic example, uart tx/rx and i2c sda/scl pinmux
41 """
42 class ManPinmux(Elaboratable):
43 def __init__(self, pad_names):
44 print("Test Manual Pinmux!")
45 self.n_banks = 4
46 self.iomux1 = IOMuxBlockSingle(self.n_banks)
47 self.iomux2 = IOMuxBlockSingle(self.n_banks)
48 """
49 self.pads = {}
50 for pad in pad_names:
51 self.pads[pad] = Record(name=pad, layout=io_layout)
52 self.gpio = {"0": Record(name="gp0", layout=io_layout),
53 "1": Record(name="gp1", layout=io_layout)
54 }
55 self.uart = Record(name="uart", layout=uart_layout)
56 self.i2c = {"sda": Record(name="sda", layout=io_layout),
57 "scl": Record(name="scl", layout=io_layout)
58 }
59 """
60 self.bank = Signal(log2_int(self.n_banks))
61 self.pads = {pad_names[0]:{}, pad_names[1]:{}}
62 self.pads["N1"]["pad"] = Record(name=pad_names[0], layout=io_layout)
63 self.pads["N1"]["mux%d" % GPIO_BANK] = Record(name="gp0",
64 layout=io_layout)
65 self.pads["N1"]["mux%d" % UART_BANK] = Record(name="tx",
66 layout=uart_tx_layout)
67 self.pads["N1"]["mux%d" % I2C_BANK] = Record(name="sda",
68 layout=io_layout)
69 self.pads["N2"]["pad"] = Record(name=pad_names[1], layout=io_layout)
70 self.pads["N2"]["mux%d" % GPIO_BANK] = Record(name="gp1",
71 layout=io_layout)
72 self.pads["N2"]["mux%d" % UART_BANK] = Signal(name="rx") # One signal
73 self.pads["N2"]["mux%d" % I2C_BANK] = Record(name="scl",
74 layout=io_layout)
75
76 def elaborate(self, platform):
77 m = Module()
78 comb, sync = m.d.comb, m.d.sync
79 iomux1 = self.iomux1
80 iomux2 = self.iomux2
81 m.submodules.iomux1 = iomux1
82 m.submodules.iomux2 = iomux2
83
84 pads = self.pads
85 pad0 = self.pads["N1"]["pad"]
86 gp0 = self.pads["N1"]["mux%d" % GPIO_BANK]
87 gp1 = self.pads["N2"]["mux%d" % GPIO_BANK]
88 tx = self.pads["N1"]["mux%d" % UART_BANK]
89 rx = self.pads["N2"]["mux%d" % UART_BANK]
90 sda = self.pads["N1"]["mux%d" % I2C_BANK]
91 scl = self.pads["N2"]["mux%d" % I2C_BANK]
92 bank = self.bank
93
94 comb += iomux1.bank.eq(bank)
95 comb += iomux2.bank.eq(bank)
96
97 # ---------------------------
98 # This section is muxing only - doesn'care about pad names
99 # ---------------------------
100 # gpio - gpio0 on Pad1, gpio1 on Pad2
101 comb += iomux1.bank_ports[GPIO_BANK].o.eq(gp0.o)
102 comb += iomux1.bank_ports[GPIO_BANK].oe.eq(gp0.oe)
103 comb += gp0.i.eq(iomux1.bank_ports[GPIO_BANK].i)
104 comb += iomux2.bank_ports[GPIO_BANK].o.eq(gp1.o)
105 comb += iomux2.bank_ports[GPIO_BANK].oe.eq(gp1.oe)
106 comb += gp1.i.eq(iomux2.bank_ports[GPIO_BANK].i)
107 # uart Pad 1 tx, Pad 2 rx
108 comb += iomux1.bank_ports[UART_BANK].o.eq(tx.o)
109 comb += iomux1.bank_ports[UART_BANK].oe.eq(tx.oe)
110 comb += rx.eq(iomux2.bank_ports[UART_BANK].i)
111 # i2c Pad 1 sda, Pad 2 scl
112 comb += iomux1.bank_ports[I2C_BANK].o.eq(sda.o)
113 comb += iomux1.bank_ports[I2C_BANK].oe.eq(sda.oe)
114 comb += sda.i.eq(iomux1.bank_ports[I2C_BANK].i)
115 comb += iomux2.bank_ports[I2C_BANK].o.eq(scl.o)
116 comb += iomux2.bank_ports[I2C_BANK].oe.eq(scl.oe)
117 comb += scl.i.eq(iomux2.bank_ports[I2C_BANK].i)
118
119 # ---------------------------
120 # Here is where the muxes are assigned to the actual pads
121 # ---------------------------
122 # TODO: for-loop to autoconnect muxes to pads (n_pads var?)
123 comb += pads['N1']["pad"].o.eq(iomux1.out_port.o)
124 comb += pads['N1']["pad"].oe.eq(iomux1.out_port.oe)
125 comb += iomux1.out_port.i.eq(pads['N1']["pad"].i)
126 comb += pads['N2']["pad"].o.eq(iomux2.out_port.o)
127 comb += pads['N2']["pad"].oe.eq(iomux2.out_port.oe)
128 comb += iomux2.out_port.i.eq(pads['N2']["pad"].i)
129
130 return m
131
132 def __iter__(self):
133 for pad in list(self.pads.keys()):
134 for field in self.pads[pad]["pad"].fields.values():
135 yield field
136 #for field in self.uart.fields.values():
137 # yield field
138 #for field in self.i2c["sda"].fields.values():
139 # yield field
140 #for field in self.i2c["scl"].fields.values():
141 # yield field
142 yield self.bank
143
144 def ports(self):
145 return list(self)
146
147 def set_bank(dut, bank, delay=1e-6):
148 yield dut.bank.eq(bank)
149 yield Delay(delay)
150
151 """
152 GPIO test function
153 Set the gpio output based on given data sequence, checked at pad.o
154 Then sends the same byte via pad.i to gpio input
155 """
156 def gpio(gpio, pad, data, delay=1e-6):
157 # Output test - Control GPIO output
158 yield gpio.oe.eq(1)
159 yield Delay(delay)
160 n_bits = len(bin(data)[2:])
161 read = 0
162 for i in range(0, n_bits):
163 bit = (data >> i) & 0x1
164 yield gpio.o.eq(bit)
165 yield Delay(delay)
166 temp = yield pad.o
167 read |= (temp << i)
168 assert data == read, f"GPIO Sent: %x | Pad Read: %x" % (data, read)
169 # Input test - Control Pad input
170 yield gpio.oe.eq(0)
171 yield Delay(delay)
172 read2 = 0
173 for i in range(0, n_bits):
174 bit = (read >> i) & 0x1
175 yield pad.i.eq(bit)
176 yield Delay(delay)
177 temp = yield gpio.i
178 read2 |= (temp << i)
179 assert read2 == read, f"Pad Sent: %x | GPIO Read: %x" % (data, read)
180 # reset input signal
181 yield pad.i.eq(0)
182 yield Delay(delay)
183
184 """
185 UART test function
186 Sends a byte via uart tx, checked at output pad
187 Then sends the same byte via input pad to uart rx
188 Input and output pads are different, so must specify both
189 """
190 def uart_send(tx, rx, pad_tx, pad_rx, byte, delay=1e-6):
191 # Drive uart tx - check the word seen at the Pad
192 yield tx.oe.eq(1)
193 yield tx.o.eq(1)
194 yield Delay(2*delay)
195 yield tx.o.eq(0) # start bit
196 yield Delay(delay)
197 read = 0
198 # send one byte, lsb first
199 for i in range(0, 8):
200 bit = (byte >> i) & 0x1
201 yield tx.o.eq(bit)
202 yield Delay(delay)
203 test_bit = yield pad_tx.o
204 read |= (test_bit << i)
205 yield tx.o.eq(1) # stop bit
206 yield Delay(delay)
207 assert byte == read, f"UART Sent: %x | Pad Read: %x" % (byte, read)
208 # Drive Pad i - check word at uart rx
209 yield pad_rx.i.eq(1)
210 yield Delay(2*delay)
211 yield pad_rx.i.eq(0) # start bit
212 yield Delay(delay)
213 read2 = 0
214 for i in range(0, 8):
215 bit = (read >> i) & 0x1
216 yield pad_rx.i.eq(bit)
217 yield Delay(delay)
218 test_bit = yield rx
219 read2 |= (test_bit << i)
220 yield pad_rx.i.eq(1) # stop bit
221 yield Delay(delay)
222 assert read == read2, f"Pad Sent: %x | UART Read: %x" % (read, read2)
223
224 """
225 I2C test function
226 Sends a byte via SDA.o (peripheral side), checked at output pad
227 Then sends the same byte via input pad to master SDA.i
228 This transaction doesn't make the distinction between read/write bit.
229 """
230 def i2c_send(sda, scl, sda_pad, byte, delay=1e-6):
231 # No checking yet
232 # No pull-up on line implemented, set high instead
233 yield sda.oe.eq(1)
234 yield sda.o.eq(1)
235 yield scl.oe.eq(1)
236 yield scl.o.eq(1)
237 yield sda_pad.i.eq(1)
238 yield Delay(delay)
239 read = 0
240 yield sda.o.eq(0) # start bit
241 yield Delay(delay)
242 for i in range(0, 8):
243 bit = (byte >> i) & 0x1
244 yield sda.o.eq(bit)
245 yield scl.o.eq(0)
246 yield Delay(delay/2)
247 yield scl.o.eq(1)
248 temp = yield sda_pad.o
249 read |= (temp << i)
250 yield Delay(delay/2)
251 yield sda.o.eq(1) # Master releases SDA line
252 yield sda.oe.eq(0)
253 assert byte == read, f"I2C Sent: %x | Pad Read: %x" % (byte, read)
254 # Slave ACK
255 yield sda_pad.i.eq(0)
256 yield scl.o.eq(0)
257 yield Delay(delay/2)
258 yield scl.o.eq(1)
259 yield Delay(delay/2)
260 # Send byte back to master
261 read2 = 0
262 for i in range(0, 8):
263 bit = (read >> i) & 0x1
264 yield sda_pad.i.eq(bit)
265 yield scl.o.eq(0)
266 yield Delay(delay/2)
267 yield scl.o.eq(1)
268 temp = yield sda.i
269 read2 |= (temp << i)
270 yield Delay(delay/2)
271 assert read == read2, f"Pad Sent: %x | I2C Read: %x" % (read, read2)
272 # Master ACK
273 yield sda.oe.eq(1)
274 yield sda.o.eq(0)
275 yield scl.o.eq(0)
276 yield Delay(delay/2)
277 yield scl.o.eq(1)
278 yield Delay(delay/2)
279 # Stop condition - SDA line high after SCL high
280 yield scl.o.eq(0)
281 yield Delay(delay/2)
282 yield scl.o.eq(1)
283 yield Delay(delay/2)
284 yield sda.o.eq(1) # 'release' the SDA line
285
286 # Test the GPIO/UART/I2C connectivity
287 def test_man_pinmux(dut, pad_names):
288 delay = 1e-6
289 # GPIO test
290 yield from set_bank(dut, GPIO_BANK)
291 yield from gpio(dut.pads["N1"]["mux%d" % GPIO_BANK],
292 dut.pads["N1"]["pad"], 0x5a5)
293 yield from gpio(dut.pads["N2"]["mux%d" % GPIO_BANK],
294 dut.pads["N2"]["pad"], 0x5a5)
295 # UART test
296 yield from set_bank(dut, UART_BANK)
297 yield from uart_send(dut.pads["N1"]["mux%d" % UART_BANK],
298 dut.pads["N2"]["mux%d" % UART_BANK],
299 dut.pads['N1']["pad"], dut.pads['N2']["pad"], 0x42)
300 #yield dut.pads['N2'].i.eq(0)
301 #yield Delay(delay)
302 # I2C test
303 yield from set_bank(dut, I2C_BANK)
304 yield from i2c_send(dut.pads["N1"]["mux%d" % I2C_BANK],
305 dut.pads["N2"]["mux%d" % I2C_BANK],
306 dut.pads['N1']["pad"], 0x67)
307
308 def sim_man_pinmux():
309 filename = "test_man_pinmux"
310 pad_names = ["N1", "N2"]
311 dut = ManPinmux(pad_names)
312 vl = rtlil.convert(dut, ports=dut.ports())
313 with open(filename+".il", "w") as f:
314 f.write(vl)
315
316 m = Module()
317 m.submodules.manpinmux = dut
318
319 sim = Simulator(m)
320
321 sim.add_process(wrap(test_man_pinmux(dut, pad_names)))
322 sim_writer = sim.write_vcd(filename+".vcd")
323 with sim_writer:
324 sim.run()
325 #gen_gtkw_doc("top.manpinmux", dut.n_banks, filename)
326
327 if __name__ == '__main__':
328 sim_man_pinmux()