Implemented GPIO changes discussed yesterday (except fitting multiple GPIOs in one...
[pinmux.git] / src / spec / simple_gpio.py
1 """Simple GPIO peripheral on wishbone
2
3 This is an extremely simple GPIO peripheral intended for use in XICS
4 testing, however it could also be used as an actual GPIO peripheral
5
6 Modified for use with pinmux, will probably change the class name later.
7 """
8 from random import randint
9 from nmigen import Elaboratable, Module, Signal, Record, Array
10 from nmigen.utils import log2_int
11 from nmigen.cli import rtlil
12 from soc.minerva.wishbone import make_wb_layout
13 from nmutil.util import wrap
14 from soc.bus.test.wb_rw import wb_read, wb_write
15
16 cxxsim = False
17 if cxxsim:
18 from nmigen.sim.cxxsim import Simulator, Settle
19 else:
20 from nmigen.sim import Simulator, Settle
21
22 # Layout of 8-bit configuration word:
23 # bank_select[2:0] i/o | pden puen ien oe
24 OESHIFT = 0
25 IESHIFT = 1
26 PUSHIFT = 2
27 PDSHIFT = 3
28 IOSHIFT = 4
29 BANKSHIFT = 5
30 NUMBANKBITS = 3 # only supporting 8 banks (0-7)
31
32 # For future testing:
33 WORDSIZE = 8 # in bytes
34
35 class SimpleGPIO(Elaboratable):
36
37 def __init__(self, n_gpio=16):
38 self.n_gpio = n_gpio
39 class Spec: pass
40 spec = Spec()
41 spec.addr_wid = 30
42 spec.mask_wid = 4
43 spec.reg_wid = 32
44 self.bus = Record(make_wb_layout(spec), name="gpio_wb")
45 self.bank_sel = Array([Signal(NUMBANKBITS) for _ in range(n_gpio)])
46 self.gpio_o = Signal(n_gpio)
47 self.gpio_oe = Signal(n_gpio)
48 self.gpio_i = Signal(n_gpio)
49 self.gpio_ie = Signal(n_gpio)
50 self.pden = Signal(n_gpio)
51 self.puen = Signal(n_gpio)
52
53 def elaborate(self, platform):
54 m = Module()
55 comb, sync = m.d.comb, m.d.sync
56
57 bus = self.bus
58 wb_rd_data = bus.dat_r
59 wb_wr_data = bus.dat_w
60 wb_ack = bus.ack
61
62 bank_sel = self.bank_sel
63 gpio_o = self.gpio_o
64 gpio_oe = self.gpio_oe
65 gpio_i = self.gpio_i
66 gpio_ie = self.gpio_ie
67 pden = self.pden
68 puen = self.puen
69
70 comb += wb_ack.eq(0)
71
72 gpio_addr = Signal(log2_int(self.n_gpio))
73 gpio_o_list = Array(list(gpio_o))
74 print(bank_sel)
75 print(gpio_o_list)
76 gpio_oe_list = Array(list(gpio_oe))
77 gpio_i_list = Array(list(gpio_i))
78 gpio_ie_list = Array(list(gpio_ie))
79 pden_list = Array(list(pden))
80 puen_list = Array(list(puen))
81
82 #print("Types:")
83 #print("gpio_addr: ", type(gpio_addr))
84 #print("gpio_o_list: ", type(gpio_o_list))
85 #print("bank_sel: ", type(bank_sel))
86
87 # One address used to configure CSR, set output, read input
88 with m.If(bus.cyc & bus.stb):
89 comb += wb_ack.eq(1) # always ack
90 comb += gpio_addr.eq(bus.adr)
91 with m.If(bus.we): # write
92 # Write/set output
93 sync += gpio_oe_list[gpio_addr].eq(wb_wr_data[OESHIFT])
94 sync += gpio_ie_list[gpio_addr].eq(wb_wr_data[IESHIFT])
95 # check GPIO is in output mode and NOT input (oe high, ie low)
96 with m.If(wb_wr_data[OESHIFT] & (~wb_wr_data[IESHIFT])):
97 sync += gpio_o_list[gpio_addr].eq(wb_wr_data[IOSHIFT])
98 sync += puen_list[gpio_addr].eq(wb_wr_data[PUSHIFT])
99 sync += pden_list[gpio_addr].eq(wb_wr_data[PDSHIFT])
100 # TODO: clean up name
101 sync += bank_sel[gpio_addr].eq(
102 wb_wr_data[BANKSHIFT:BANKSHIFT+NUMBANKBITS])
103 with m.Else(): # read
104 # Read the state of CSR bits
105 # Return state of input if ie
106 with m.If(gpio_ie_list[gpio_addr] == 1):
107 comb += wb_rd_data.eq((gpio_oe_list[gpio_addr] << OESHIFT)
108 + (gpio_ie_list[gpio_addr] << IESHIFT)
109 + (puen_list[gpio_addr] << PUSHIFT)
110 + (pden_list[gpio_addr] << PDSHIFT)
111 + (gpio_i_list[gpio_addr] << IOSHIFT)
112 + (bank_sel[gpio_addr] << BANKSHIFT))
113 # Return state of out if oe
114 with m.Else():
115 comb += wb_rd_data.eq((gpio_oe_list[gpio_addr] << OESHIFT)
116 + (gpio_ie_list[gpio_addr] << IESHIFT)
117 + (puen_list[gpio_addr] << PUSHIFT)
118 + (pden_list[gpio_addr] << PDSHIFT)
119 + (gpio_o_list[gpio_addr] << IOSHIFT)
120 + (bank_sel[gpio_addr] << BANKSHIFT))
121
122 return m
123
124 def __iter__(self):
125 for field in self.bus.fields.values():
126 yield field
127 yield self.gpio_o
128
129 def ports(self):
130 return list(self)
131
132 # TODO: probably make into class (or return state in a variable)
133 def gpio_configure(dut, gpio, oe, ie, puen, pden, outval, bank_sel):
134 csr_val = ( (oe << OESHIFT)
135 | (ie << IESHIFT)
136 | (puen << PUSHIFT)
137 | (pden << PDSHIFT)
138 | (bank_sel << BANKSHIFT) )
139 print("Configuring CSR to {0:x}".format(csr_val))
140 yield from wb_write(dut.bus, gpio, csr_val)
141 return csr_val # return the config state
142
143 # TODO: Return the configuration states
144 def gpio_rd_csr(dut, gpio):
145 csr_val = yield from wb_read(dut.bus, gpio)
146 print("GPIO{0} | CSR: {1:x}".format(gpio, csr_val))
147 print("Output Enable: {0:b}".format((csr_val >> OESHIFT) & 1))
148 print("Input Enable: {0:b}".format((csr_val >> IESHIFT) & 1))
149 print("Pull-Up Enable: {0:b}".format((csr_val >> PUSHIFT) & 1))
150 print("Pull-Down Enable: {0:b}".format((csr_val >> PDSHIFT) & 1))
151 if ((csr_val >> IESHIFT) & 1):
152 print("Input: {0:b}".format((csr_val >> IOSHIFT) & 1))
153 else:
154 print("Output: {0:b}".format((csr_val >> IOSHIFT) & 1))
155 print("Bank Select: {0:b}".format((csr_val >> BANKSHIFT) & 1))
156 # gpio_parse_csr(csr_val)
157 return csr_val
158
159 # TODO
160 def gpio_rd_input(dut, gpio):
161 in_val = yield from wb_read(dut.bus, gpio)
162 in_val = (in_val >> IOSHIFT) & 1
163 print("GPIO{0} | Input: {1:b}".format(gpio, in_val))
164 return in_val
165
166 def gpio_set_out(dut, gpio, csr_val, output):
167 print("Setting GPIO{0} output to {1}".format(gpio, output))
168 yield from wb_write(dut.bus, gpio, csr_val | (output<<IOSHIFT))
169
170 # TODO: There's probably a cleaner way to clear the bit...
171 def gpio_set_in_pad(dut, gpio, in_val):
172 old_in_val = yield dut.gpio_i
173 if in_val:
174 new_in_val = old_in_val | (in_val << gpio)
175 else:
176 temp = (old_in_val >> gpio) & 1
177 if temp:
178 mask = ~(1 << gpio)
179 new_in_val = old_in_val & mask
180 else:
181 new_in_val = old_in_val
182 print("Previous GPIO i: {0:b} | New GPIO i: {1:b}"
183 .format(old_in_val, new_in_val))
184 yield dut.gpio_i.eq(new_in_val)
185
186 def gpio_test_in_pattern(dut, pattern):
187 num_gpios = len(dut.gpio_o)
188 print("Test pattern:")
189 print(pattern)
190 for pat in range(0, len(pattern)):
191 for gpio in range(0, num_gpios):
192 yield from gpio_set_in_pad(dut, gpio, pattern[pat])
193 yield
194 temp = yield from gpio_rd_input(dut, gpio)
195 print("Pattern: {0}, Reading {1}".format(pattern[pat], temp))
196 assert (temp == pattern[pat])
197 pat += 1
198 if pat == len(pattern):
199 break
200
201
202 def sim_gpio(dut, use_random=True):
203 print(dir(dut))
204 print(dut)
205 num_gpios = len(dut.gpio_o)
206 if use_random:
207 bank_sel = randint(0, num_gpios)
208 else:
209 bank_sel = 3 # not special, chose for testing
210 oe = 1
211 ie = 0
212 output = 0
213 puen = 1
214 pden = 0
215 gpio_csr = [0] * num_gpios
216 # Configure GPIOs for
217 for gpio in range(0, num_gpios):
218 gpio_csr[gpio] = yield from gpio_configure(dut, gpio, oe, ie, puen,
219 pden, output, bank_sel)
220 # Set outputs
221 for gpio in range(0, num_gpios):
222 yield from gpio_set_out(dut, gpio, gpio_csr[gpio], 1)
223
224 # Read CSR
225 for gpio in range(0, num_gpios):
226 yield from gpio_rd_csr(dut, gpio)
227
228 # TODO: not working yet
229 #test_pattern = []
230 #for i in range(0, (num_gpios * 2)):
231 # test_pattern.append(randint(0,1))
232 #yield from gpio_test_in_pattern(dut, test_pattern)
233
234 print("Finished the simple GPIO block test!")
235
236 def test_gpio():
237 dut = SimpleGPIO()
238 vl = rtlil.convert(dut, ports=dut.ports())
239 with open("test_gpio.il", "w") as f:
240 f.write(vl)
241
242 m = Module()
243 m.submodules.xics_icp = dut
244
245 sim = Simulator(m)
246 sim.add_clock(1e-6)
247
248 sim.add_sync_process(wrap(sim_gpio(dut)))
249 sim_writer = sim.write_vcd('test_gpio.vcd')
250 with sim_writer:
251 sim.run()
252
253
254 if __name__ == '__main__':
255 test_gpio()
256