378d590331e270c9b2b9ed3c68660cda46c16bc6
[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
33 GPIO_BANK = 0
34 UART_BANK = 1
35 I2C_BANK = 2
36
37 """
38 Really basic example, uart tx/rx and i2c sda/scl pinmux
39 """
40 class ManPinmux(Elaboratable):
41 def __init__(self, pad_names):
42 print("Test Manual Pinmux!")
43 self.n_banks = 4
44 self.iomux1 = IOMuxBlockSingle(self.n_banks)
45 self.iomux2 = IOMuxBlockSingle(self.n_banks)
46 self.pads = {}
47 for pad in pad_names:
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)
51 }
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)
55 }
56 self.bank = Signal(log2_int(self.n_banks))
57
58 def elaborate(self, platform):
59 m = Module()
60 comb, sync = m.d.comb, m.d.sync
61 iomux1 = self.iomux1
62 iomux2 = self.iomux2
63 m.submodules.iomux1 = iomux1
64 m.submodules.iomux2 = iomux2
65
66 pads = self.pads
67 gpio = self.gpio
68 uart = self.uart
69 i2c = self.i2c
70 bank = self.bank
71
72 comb += iomux1.bank.eq(bank)
73 comb += iomux2.bank.eq(bank)
74
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)
96
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)
107
108 #temp for testing - connect pad rx-tx
109 #comb += pad2.i.eq(pad1.o)
110
111 return m
112
113 def __iter__(self):
114 for pad in list(self.pads.keys()):
115 for field in self.pads[pad].fields.values():
116 yield field
117 for field in self.uart.fields.values():
118 yield field
119 for field in self.i2c["sda"].fields.values():
120 yield field
121 for field in self.i2c["scl"].fields.values():
122 yield field
123 yield self.bank
124
125 def ports(self):
126 return list(self)
127
128 def set_bank(dut, bank, delay=1e-6):
129 yield dut.bank.eq(bank)
130 yield Delay(delay)
131
132 """
133 GPIO test function
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
136 """
137 def gpio(gpio, pad, data, delay=1e-6):
138 # Output test - Control GPIO output
139 yield gpio.oe.eq(1)
140 yield Delay(delay)
141 n_bits = len(bin(data)[2:])
142 read = 0
143 for i in range(0, n_bits):
144 bit = (data >> i) & 0x1
145 yield gpio.o.eq(bit)
146 yield Delay(delay)
147 temp = yield pad.o
148 read |= (temp << i)
149 assert data == read, f"GPIO Sent: %x | Pad Read: %x" % (data, read)
150 # Input test - Control Pad input
151 yield gpio.oe.eq(0)
152 yield Delay(delay)
153 read2 = 0
154 for i in range(0, n_bits):
155 bit = (read >> i) & 0x1
156 yield pad.i.eq(bit)
157 yield Delay(delay)
158 temp = yield gpio.i
159 read2 |= (temp << i)
160 assert read2 == read, f"Pad Sent: %x | GPIO Read: %x" % (data, read)
161 # reset input signal
162 yield pad.i.eq(0)
163 yield Delay(delay)
164
165 """
166 UART test function
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
170 """
171 def uart_send(uart, pad_o, pad_i, byte, delay=1e-6):
172 # Drive uart tx - check the word seen at the Pad
173 yield uart.oe.eq(1)
174 yield uart.tx.eq(1)
175 yield Delay(2*delay)
176 yield uart.tx.eq(0) # start bit
177 yield Delay(delay)
178 read = 0
179 # send one byte, lsb first
180 for i in range(0, 8):
181 bit = (byte >> i) & 0x1
182 yield uart.tx.eq(bit)
183 yield Delay(delay)
184 test_bit = yield pad_o
185 read |= (test_bit << i)
186 yield uart.tx.eq(1) # stop bit
187 yield Delay(delay)
188 assert byte == read, f"UART Sent: %x | Pad Read: %x" % (byte, read)
189 # Drive Pad i - check word at uart rx
190 yield pad_i.eq(1)
191 yield Delay(2*delay)
192 yield pad_i.eq(0) # start bit
193 yield Delay(delay)
194 read2 = 0
195 for i in range(0, 8):
196 bit = (read >> i) & 0x1
197 yield pad_i.eq(bit)
198 yield Delay(delay)
199 test_bit = yield uart.rx
200 read2 |= (test_bit << i)
201 yield pad_i.eq(1) # stop bit
202 yield Delay(delay)
203 assert read == read2, f"Pad Sent: %x | UART Read: %x" % (read, read2)
204
205
206 def i2c_send(sda, scl, sda_pad_i, byte, delay=1e-6):
207 # No checking yet
208 # No pull-up on line implemented, set high instead
209 yield sda.oe.eq(1)
210 yield sda.o.eq(1)
211 yield scl.oe.eq(1)
212 yield scl.o.eq(1)
213 yield sda_pad_i.eq(1)
214 yield Delay(delay)
215 yield sda.o.eq(0) # start bit
216 yield Delay(delay)
217 for i in range(0, 8):
218 bit = (byte >> i) & 0x1
219 yield sda.o.eq(bit)
220 yield scl.o.eq(0)
221 yield Delay(delay/2)
222 yield scl.o.eq(1)
223 yield Delay(delay/2)
224 yield sda.o.eq(1) # Master releases SDA line
225 yield sda.oe.eq(0)
226 yield sda_pad_i.eq(0) # ACK
227 yield Delay(delay)
228 yield sda_pad_i.eq(1)
229
230
231
232 def test_man_pinmux(dut, pad_names):
233 delay = 1e-6
234 # GPIO test
235 yield from gpio(dut.gpio['0'], dut.pads['N1'], 0x5a5)
236 yield from gpio(dut.gpio['1'], dut.pads['N2'], 0x5a5)
237 # UART test
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)
241 yield Delay(delay)
242 # I2C test
243 yield from set_bank(dut, I2C_BANK)
244 yield from i2c_send(dut.i2c['sda'], dut.i2c['scl'], dut.pads['N1'].i, 0x67)
245
246 yield dut.gpio['0'].oe.eq(1)
247 yield Delay(delay)
248 yield dut.gpio['0'].oe.eq(0)
249 yield Delay(delay)
250
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:
257 f.write(vl)
258
259 m = Module()
260 m.submodules.manpinmux = dut
261
262 sim = Simulator(m)
263
264 sim.add_process(wrap(test_man_pinmux(dut, pad_names)))
265 sim_writer = sim.write_vcd(filename+".vcd")
266 with sim_writer:
267 sim.run()
268 #gen_gtkw_doc("top.manpinmux", dut.n_banks, filename)
269
270 if __name__ == '__main__':
271 sim_man_pinmux()