fcc8db43c60be0347923759d545d348161823afb
[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
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"]}
52 }
53 self.n_banks = 4
54 self.bank = Signal(log2_int(self.n_banks))
55 self.pads = {}
56 self.muxes = {}
57 for pad in self.requested.keys():
58 self.pads[pad] = {}
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]
66 else:
67 pin = "io"
68 if periph == "gpio":
69 self.pads[pad][mux] = Record(name="gp%d" % unit_num,
70 layout=io_layout)
71 elif periph == "uart":
72 if pin == "tx":
73 self.pads[pad][mux] = Record(name="tx%d" % unit_num,
74 layout=uart_tx_layout)
75 elif pin == "rx":
76 self.pads[pad][mux] = Signal(name="rx%d" % unit_num)
77 elif periph == "i2c":
78 if pin == "sda":
79 self.pads[pad][mux] = Record(name="sda%d" % unit_num,
80 layout=io_layout)
81 elif pin == "scl":
82 self.pads[pad][mux] = Record(name="scl%d" % unit_num,
83 layout=io_layout)
84
85 def elaborate(self, platform):
86 m = Module()
87 comb, sync = m.d.comb, m.d.sync
88 muxes = self.muxes
89 # TODO: replace with pin specific
90 iomux1 = muxes["N1"]
91 iomux2 = muxes["N2"]
92 for pad in self.pads.keys():
93 m.submodules[pad+"_mux"] = muxes[pad]
94
95 pads = self.pads
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]
103 bank = self.bank
104
105 comb += iomux1.bank.eq(bank)
106 comb += iomux2.bank.eq(bank)
107
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)
129
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)
140
141 return m
142
143 def __iter__(self):
144 for pad in list(self.pads.keys()):
145 for field in self.pads[pad]["pad"].fields.values():
146 yield field
147 #for field in self.uart.fields.values():
148 # yield field
149 #for field in self.i2c["sda"].fields.values():
150 # yield field
151 #for field in self.i2c["scl"].fields.values():
152 # yield field
153 yield self.bank
154
155 def ports(self):
156 return list(self)
157
158 def set_bank(dut, bank, delay=1e-6):
159 yield dut.bank.eq(bank)
160 yield Delay(delay)
161
162 """
163 GPIO test function
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
166 """
167 def gpio(gpio, pad, data, delay=1e-6):
168 # Output test - Control GPIO output
169 yield gpio.oe.eq(1)
170 yield Delay(delay)
171 n_bits = len(bin(data)[2:])
172 read = 0
173 for i in range(0, n_bits):
174 bit = (data >> i) & 0x1
175 yield gpio.o.eq(bit)
176 yield Delay(delay)
177 temp = yield pad.o
178 read |= (temp << i)
179 assert data == read, f"GPIO Sent: %x | Pad Read: %x" % (data, read)
180 # Input test - Control Pad input
181 yield gpio.oe.eq(0)
182 yield Delay(delay)
183 read2 = 0
184 for i in range(0, n_bits):
185 bit = (read >> i) & 0x1
186 yield pad.i.eq(bit)
187 yield Delay(delay)
188 temp = yield gpio.i
189 read2 |= (temp << i)
190 assert read2 == read, f"Pad Sent: %x | GPIO Read: %x" % (data, read)
191 # reset input signal
192 yield pad.i.eq(0)
193 yield Delay(delay)
194
195 """
196 UART test function
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
200 """
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
203 yield tx.oe.eq(1)
204 yield tx.o.eq(1)
205 yield Delay(2*delay)
206 yield tx.o.eq(0) # start bit
207 yield Delay(delay)
208 read = 0
209 # send one byte, lsb first
210 for i in range(0, 8):
211 bit = (byte >> i) & 0x1
212 yield tx.o.eq(bit)
213 yield Delay(delay)
214 test_bit = yield pad_tx.o
215 read |= (test_bit << i)
216 yield tx.o.eq(1) # stop bit
217 yield Delay(delay)
218 assert byte == read, f"UART Sent: %x | Pad Read: %x" % (byte, read)
219 # Drive Pad i - check word at uart rx
220 yield pad_rx.i.eq(1)
221 yield Delay(2*delay)
222 yield pad_rx.i.eq(0) # start bit
223 yield Delay(delay)
224 read2 = 0
225 for i in range(0, 8):
226 bit = (read >> i) & 0x1
227 yield pad_rx.i.eq(bit)
228 yield Delay(delay)
229 test_bit = yield rx
230 read2 |= (test_bit << i)
231 yield pad_rx.i.eq(1) # stop bit
232 yield Delay(delay)
233 assert read == read2, f"Pad Sent: %x | UART Read: %x" % (read, read2)
234
235 """
236 I2C test function
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.
240 """
241 def i2c_send(sda, scl, sda_pad, byte, delay=1e-6):
242 # No checking yet
243 # No pull-up on line implemented, set high instead
244 yield sda.oe.eq(1)
245 yield sda.o.eq(1)
246 yield scl.oe.eq(1)
247 yield scl.o.eq(1)
248 yield sda_pad.i.eq(1)
249 yield Delay(delay)
250 read = 0
251 yield sda.o.eq(0) # start bit
252 yield Delay(delay)
253 for i in range(0, 8):
254 bit = (byte >> i) & 0x1
255 yield sda.o.eq(bit)
256 yield scl.o.eq(0)
257 yield Delay(delay/2)
258 yield scl.o.eq(1)
259 temp = yield sda_pad.o
260 read |= (temp << i)
261 yield Delay(delay/2)
262 yield sda.o.eq(1) # Master releases SDA line
263 yield sda.oe.eq(0)
264 assert byte == read, f"I2C Sent: %x | Pad Read: %x" % (byte, read)
265 # Slave ACK
266 yield sda_pad.i.eq(0)
267 yield scl.o.eq(0)
268 yield Delay(delay/2)
269 yield scl.o.eq(1)
270 yield Delay(delay/2)
271 # Send byte back to master
272 read2 = 0
273 for i in range(0, 8):
274 bit = (read >> i) & 0x1
275 yield sda_pad.i.eq(bit)
276 yield scl.o.eq(0)
277 yield Delay(delay/2)
278 yield scl.o.eq(1)
279 temp = yield sda.i
280 read2 |= (temp << i)
281 yield Delay(delay/2)
282 assert read == read2, f"Pad Sent: %x | I2C Read: %x" % (read, read2)
283 # Master ACK
284 yield sda.oe.eq(1)
285 yield sda.o.eq(0)
286 yield scl.o.eq(0)
287 yield Delay(delay/2)
288 yield scl.o.eq(1)
289 yield Delay(delay/2)
290 # Stop condition - SDA line high after SCL high
291 yield scl.o.eq(0)
292 yield Delay(delay/2)
293 yield scl.o.eq(1)
294 yield Delay(delay/2)
295 yield sda.o.eq(1) # 'release' the SDA line
296
297 # Test the GPIO/UART/I2C connectivity
298 def test_man_pinmux(dut, pad_names):
299 delay = 1e-6
300 # GPIO test
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)
306 # UART test
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)
312 #yield Delay(delay)
313 # I2C test
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)
318
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:
325 f.write(vl)
326
327 m = Module()
328 m.submodules.manpinmux = dut
329
330 sim = Simulator(m)
331
332 sim.add_process(wrap(test_man_pinmux(dut, pad_names)))
333 sim_writer = sim.write_vcd(filename+".vcd")
334 with sim_writer:
335 sim.run()
336 #gen_gtkw_doc("top.manpinmux", dut.n_banks, filename)
337
338 if __name__ == '__main__':
339 sim_man_pinmux()