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