247de1136e15b2df8c53f7450e7ad268d1bfe80c
[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 # Automatically create the necessary periph/pad Records/Signals
58 # depending on the given dict specification
59 for pad in self.requested.keys():
60 self.pads[pad] = {}
61 self.pads[pad]["pad"] = Record(name=pad, layout=io_layout)
62 self.muxes[pad] = IOMuxBlockSingle(self.n_banks)
63 for mux in self.requested[pad].keys():
64 periph = self.requested[pad][mux][0]
65 unit_num = self.requested[pad][mux][1]
66 if len(self.requested[pad][mux]) == 3:
67 pin = self.requested[pad][mux][2]
68 else:
69 pin = "io"
70 if periph == "gpio":
71 self.pads[pad][mux] = Record(name="gp%d" % unit_num,
72 layout=io_layout)
73 elif periph == "uart":
74 if pin == "tx":
75 self.pads[pad][mux] = Record(name="tx%d" % unit_num,
76 layout=uart_tx_layout)
77 elif pin == "rx":
78 self.pads[pad][mux] = Signal(name="rx%d" % unit_num)
79 elif periph == "i2c":
80 if pin == "sda":
81 self.pads[pad][mux] = Record(name="sda%d" % unit_num,
82 layout=io_layout)
83 elif pin == "scl":
84 self.pads[pad][mux] = Record(name="scl%d" % unit_num,
85 layout=io_layout)
86
87 def elaborate(self, platform):
88 m = Module()
89 comb, sync = m.d.comb, m.d.sync
90 muxes = self.muxes
91 bank = self.bank
92 pads = self.pads
93 for pad in pads.keys():
94 m.submodules[pad+"_mux"] = muxes[pad]
95 # all muxes controlled by the same multi-bit signal
96 comb += muxes[pad].bank.eq(bank)
97
98 # print(self.requested)
99 # print(self.pads)
100
101 # ---------------------------
102 # This section connects the periphs to the assigned banks
103 # ---------------------------
104 for pad in pads.keys():
105 for mux in self.requested[pad].keys():
106 periph = self.requested[pad][mux][0]
107 num = int(mux[3])
108 if len(self.requested[pad][mux]) == 3:
109 pin = self.requested[pad][mux][2]
110 else:
111 pin = "io"
112 if periph == "gpio" or periph == "i2c":
113 comb += muxes[pad].bank_ports[num].o.eq(pads[pad][mux].o)
114 comb += muxes[pad].bank_ports[num].oe.eq(pads[pad][mux].oe)
115 comb += pads[pad][mux].i.eq(muxes[pad].bank_ports[num].i)
116 elif periph == "uart":
117 if pin == "tx":
118 comb += muxes[pad].bank_ports[num].o.eq(
119 pads[pad][mux].o)
120 comb += muxes[pad].bank_ports[num].oe.eq(
121 pads[pad][mux].oe)
122 elif pin == "rx":
123 comb += pads[pad][mux].eq(muxes[pad].bank_ports[num].i)
124
125 # ---------------------------
126 # Here is where the muxes are assigned to the actual pads
127 # ---------------------------
128 for pad in pads.keys():
129 comb += pads[pad]["pad"].o.eq(muxes[pad].out_port.o)
130 comb += pads[pad]["pad"].oe.eq(muxes[pad].out_port.oe)
131 comb += muxes[pad].out_port.i.eq(pads[pad]["pad"].i)
132
133 return m
134
135 def __iter__(self):
136 for pad in list(self.pads.keys()):
137 for field in self.pads[pad]["pad"].fields.values():
138 yield field
139 for mux in self.pads[pad].keys():
140 if type(self.pads[pad][mux]) == Signal:
141 yield self.pads[pad][mux]
142 else:
143 for field in self.pads[pad][mux].fields.values():
144 yield field
145 yield self.bank
146
147 def ports(self):
148 return list(self)
149
150 def set_bank(dut, bank, delay=1e-6):
151 yield dut.bank.eq(bank)
152 yield Delay(delay)
153
154 """
155 GPIO test function
156 Set the gpio output based on given data sequence, checked at pad.o
157 Then sends the same byte via pad.i to gpio input
158 """
159 def gpio(gpio, pad, data, delay=1e-6):
160 # Output test - Control GPIO output
161 yield gpio.oe.eq(1)
162 yield Delay(delay)
163 n_bits = len(bin(data)[2:])
164 read = 0
165 for i in range(0, n_bits):
166 bit = (data >> i) & 0x1
167 yield gpio.o.eq(bit)
168 yield Delay(delay)
169 temp = yield pad.o
170 read |= (temp << i)
171 assert data == read, f"GPIO Sent: %x | Pad Read: %x" % (data, read)
172 # Input test - Control Pad input
173 yield gpio.oe.eq(0)
174 yield Delay(delay)
175 read2 = 0
176 for i in range(0, n_bits):
177 bit = (read >> i) & 0x1
178 yield pad.i.eq(bit)
179 yield Delay(delay)
180 temp = yield gpio.i
181 read2 |= (temp << i)
182 assert read2 == read, f"Pad Sent: %x | GPIO Read: %x" % (data, read)
183 # reset input signal
184 yield pad.i.eq(0)
185 yield Delay(delay)
186
187 """
188 UART test function
189 Sends a byte via uart tx, checked at output pad
190 Then sends the same byte via input pad to uart rx
191 Input and output pads are different, so must specify both
192 """
193 def uart_send(tx, rx, pad_tx, pad_rx, byte, delay=1e-6):
194 # Drive uart tx - check the word seen at the Pad
195 yield tx.oe.eq(1)
196 yield tx.o.eq(1)
197 yield Delay(2*delay)
198 yield tx.o.eq(0) # start bit
199 yield Delay(delay)
200 read = 0
201 # send one byte, lsb first
202 for i in range(0, 8):
203 bit = (byte >> i) & 0x1
204 yield tx.o.eq(bit)
205 yield Delay(delay)
206 test_bit = yield pad_tx.o
207 read |= (test_bit << i)
208 yield tx.o.eq(1) # stop bit
209 yield Delay(delay)
210 assert byte == read, f"UART Sent: %x | Pad Read: %x" % (byte, read)
211 # Drive Pad i - check word at uart rx
212 yield pad_rx.i.eq(1)
213 yield Delay(2*delay)
214 yield pad_rx.i.eq(0) # start bit
215 yield Delay(delay)
216 read2 = 0
217 for i in range(0, 8):
218 bit = (read >> i) & 0x1
219 yield pad_rx.i.eq(bit)
220 yield Delay(delay)
221 test_bit = yield rx
222 read2 |= (test_bit << i)
223 yield pad_rx.i.eq(1) # stop bit
224 yield Delay(delay)
225 assert read == read2, f"Pad Sent: %x | UART Read: %x" % (read, read2)
226
227 """
228 I2C test function
229 Sends a byte via SDA.o (peripheral side), checked at output pad
230 Then sends the same byte via input pad to master SDA.i
231 This transaction doesn't make the distinction between read/write bit.
232 """
233 def i2c_send(sda, scl, sda_pad, byte, delay=1e-6):
234 # No checking yet
235 # No pull-up on line implemented, set high instead
236 yield sda.oe.eq(1)
237 yield sda.o.eq(1)
238 yield scl.oe.eq(1)
239 yield scl.o.eq(1)
240 yield sda_pad.i.eq(1)
241 yield Delay(delay)
242 read = 0
243 yield sda.o.eq(0) # start bit
244 yield Delay(delay)
245 for i in range(0, 8):
246 bit = (byte >> i) & 0x1
247 yield sda.o.eq(bit)
248 yield scl.o.eq(0)
249 yield Delay(delay/2)
250 yield scl.o.eq(1)
251 temp = yield sda_pad.o
252 read |= (temp << i)
253 yield Delay(delay/2)
254 yield sda.o.eq(1) # Master releases SDA line
255 yield sda.oe.eq(0)
256 assert byte == read, f"I2C Sent: %x | Pad Read: %x" % (byte, read)
257 # Slave ACK
258 yield sda_pad.i.eq(0)
259 yield scl.o.eq(0)
260 yield Delay(delay/2)
261 yield scl.o.eq(1)
262 yield Delay(delay/2)
263 # Send byte back to master
264 read2 = 0
265 for i in range(0, 8):
266 bit = (read >> i) & 0x1
267 yield sda_pad.i.eq(bit)
268 yield scl.o.eq(0)
269 yield Delay(delay/2)
270 yield scl.o.eq(1)
271 temp = yield sda.i
272 read2 |= (temp << i)
273 yield Delay(delay/2)
274 assert read == read2, f"Pad Sent: %x | I2C Read: %x" % (read, read2)
275 # Master ACK
276 yield sda.oe.eq(1)
277 yield sda.o.eq(0)
278 yield scl.o.eq(0)
279 yield Delay(delay/2)
280 yield scl.o.eq(1)
281 yield Delay(delay/2)
282 # Stop condition - SDA line high after SCL high
283 yield scl.o.eq(0)
284 yield Delay(delay/2)
285 yield scl.o.eq(1)
286 yield Delay(delay/2)
287 yield sda.o.eq(1) # 'release' the SDA line
288
289 # Test the GPIO/UART/I2C connectivity
290 def test_man_pinmux(dut, pad_names):
291 delay = 1e-6
292 # GPIO test
293 yield from set_bank(dut, GPIO_BANK)
294 yield from gpio(dut.pads["N1"]["mux%d" % GPIO_BANK],
295 dut.pads["N1"]["pad"], 0x5a5)
296 yield from gpio(dut.pads["N2"]["mux%d" % GPIO_BANK],
297 dut.pads["N2"]["pad"], 0x5a5)
298 # UART test
299 yield from set_bank(dut, UART_BANK)
300 yield from uart_send(dut.pads["N1"]["mux%d" % UART_BANK],
301 dut.pads["N2"]["mux%d" % UART_BANK],
302 dut.pads['N1']["pad"], dut.pads['N2']["pad"], 0x42)
303 #yield dut.pads['N2'].i.eq(0)
304 #yield Delay(delay)
305 # I2C test
306 yield from set_bank(dut, I2C_BANK)
307 yield from i2c_send(dut.pads["N1"]["mux%d" % I2C_BANK],
308 dut.pads["N2"]["mux%d" % I2C_BANK],
309 dut.pads['N1']["pad"], 0x67)
310
311 def gen_gtkw_doc(module_name, requested, filename):
312 # GTKWave doc generation
313 style = {
314 '': {'base': 'hex'},
315 'in': {'color': 'orange'},
316 'out': {'color': 'yellow'},
317 'debug': {'module': 'top', 'color': 'red'}
318 }
319 # Create a trace list, each block expected to be a tuple()
320 traces = []
321 temp = 0
322 n_banks = 0
323 for pad in requested.keys():
324 temp = len(requested[pad].keys())
325 if n_banks < temp:
326 n_banks = temp
327 temp_traces = ("Pad %s" % pad, [])
328 # Pad signals
329 temp_traces[1].append(('%s__i' % pad, 'in'))
330 temp_traces[1].append(('%s__o' % pad, 'out'))
331 temp_traces[1].append(('%s__oe' % pad, 'out'))
332 for mux in requested[pad].keys():
333 periph = requested[pad][mux][0]
334 unit_num = requested[pad][mux][1]
335 if len(requested[pad][mux]) == 3:
336 pin = requested[pad][mux][2]
337 else:
338 pin = "io"
339
340 if periph == "gpio":
341 temp_traces[1].append(('gp%d__i' % unit_num, 'in'))
342 temp_traces[1].append(('gp%d__o' % unit_num, 'out'))
343 temp_traces[1].append(('gp%d__oe' % unit_num, 'out'))
344 elif periph == "uart":
345 if pin == "tx":
346 temp_traces[1].append(('tx%d__o' % unit_num, 'out'))
347 temp_traces[1].append(('tx%d__oe' % unit_num, 'out'))
348 pass
349 elif pin == "rx":
350 temp_traces[1].append(('rx%d' % unit_num, 'in'))
351 pass
352 elif periph == "i2c":
353 temp_traces[1].append(('%s%d__i' % (pin, unit_num), 'in'))
354 temp_traces[1].append(('%s%d__o' % (pin, unit_num), 'out'))
355 temp_traces[1].append(('%s%d__oe' % (pin, unit_num), 'out'))
356 traces.append(temp_traces)
357
358 # master bank signal
359 temp_traces = ('Misc', [
360 ('bank[%d:0]' % ((n_banks-1).bit_length()-1), 'in')
361 ])
362 traces.append(temp_traces)
363
364 #print(traces)
365
366 write_gtkw(filename+".gtkw", filename+".vcd", traces, style,
367 module=module_name)
368
369
370 def sim_man_pinmux():
371 filename = "test_man_pinmux"
372 pad_names = ["N1", "N2"]
373 dut = ManPinmux(pad_names)
374 vl = rtlil.convert(dut, ports=dut.ports())
375 with open(filename+".il", "w") as f:
376 f.write(vl)
377
378 m = Module()
379 m.submodules.manpinmux = dut
380
381 sim = Simulator(m)
382
383 sim.add_process(wrap(test_man_pinmux(dut, pad_names)))
384 sim_writer = sim.write_vcd(filename+".vcd")
385 with sim_writer:
386 sim.run()
387 gen_gtkw_doc("top.manpinmux", dut.requested, filename)
388
389 if __name__ == '__main__':
390 sim_man_pinmux()