Made changes discussed in IRC, will fix sim tomorrow
[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 NUM_BANKSEL_BITS = 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 # ONLY ONE BANK FOR ALL GPIOs atm...
46 self.bank_sel = [Signal(NUM_BANKSEL_BITS)] * n_gpio
47 self.gpio_o = Signal(n_gpio)
48 self.gpio_oe = Signal(n_gpio)
49 self.gpio_i = Signal(n_gpio)
50 self.gpio_ie = Signal(n_gpio)
51 self.pden = Signal(n_gpio)
52 self.puen = Signal(n_gpio)
53
54 def elaborate(self, platform):
55 m = Module()
56 comb, sync = m.d.comb, m.d.sync
57
58 bus = self.bus
59 wb_rd_data = bus.dat_r
60 wb_wr_data = bus.dat_w
61 wb_ack = bus.ack
62
63 bank_sel = self.bank_sel
64 gpio_o = self.gpio_o
65 gpio_oe = self.gpio_oe
66 gpio_i = self.gpio_i
67 gpio_ie = self.gpio_ie
68 pden = self.pden
69 puen = self.puen
70
71 comb += wb_ack.eq(0)
72
73 #for i in range(0, self.n_gpio):
74 # bank_sel[i]
75 gpio_addr = Signal(log2_int(self.n_gpio))
76 gpio_o_list = Array(list(gpio_o))
77 print(bank_sel)
78 print(gpio_o_list)
79 gpio_oe_list = Array(list(gpio_oe))
80 gpio_i_list = Array(list(gpio_i))
81 gpio_ie_list = Array(list(gpio_ie))
82 pden_list = Array(list(pden))
83 puen_list = Array(list(puen))
84
85 # One address used to configure CSR, set output, read input
86 with m.If(bus.cyc & bus.stb):
87 comb += wb_ack.eq(1) # always ack
88 comb += gpio_addr.eq(bus.adr)
89 with m.If(bus.we): # write
90 # Write/set output
91 sync += gpio_oe_list[gpio_addr].eq(wb_wr_data[OESHIFT])
92 sync += gpio_ie_list[gpio_addr].eq(wb_wr_data[IESHIFT])
93 # check GPIO is in output mode and NOT input (oe high, ie low)
94 with m.If(wb_wr_data[OESHIFT] & (~wb_wr_data[IESHIFT])):
95 sync += gpio_o_list[gpio_addr].eq(wb_wr_data[IOSHIFT])
96 sync += puen_list[gpio_addr].eq(wb_wr_data[PUSHIFT])
97 sync += pden_list[gpio_addr].eq(wb_wr_data[PDSHIFT])
98 # TODO: clean up name
99 sync += bank_sel[gpio_addr].eq(
100 wb_wr_data[BANKSHIFT:BANKSHIFT+NUM_BANKSEL_BITS])
101 with m.Else(): # read
102 # Read the state of CSR bits
103 with m.Else():
104 comb += wb_rd_data.eq((gpio_oe_list[gpio_addr] << OESHIFT)
105 + (gpio_ie_list[gpio_addr] << IESHIFT)
106 + (puen_list[gpio_addr] << PUSHIFT)
107 + (pden_list[gpio_addr] << PDSHIFT)
108 + (gpio_i_list[gpio_addr] << IOSHIFT)
109 + (bank_sel << BANKSHIFT))
110 return m
111
112 def __iter__(self):
113 for field in self.bus.fields.values():
114 yield field
115 yield self.gpio_o
116
117 def ports(self):
118 return list(self)
119
120 # TODO: probably make into class (or return state in a variable)
121 def gpio_configure(dut, gpio, oe, ie, pden, puen, bank_sel=0):
122 csr_val = ( (bank_sel << BANKSHIFT)
123 | (pden << PDSHIFT)
124 | (puen << PUSHIFT)
125 | (oe << OESHIFT)
126 | (ie << IESHIFT) )
127 print("Configuring CSR to {0:x}".format(csr_val))
128 yield from wb_write(dut.bus, gpio, csr_val)
129
130 # TODO: Return the configuration states
131 def gpio_rd_csr(dut, gpio):
132 csr_val = yield from wb_read(dut.bus, gpio)
133 print("GPIO{0} | CSR: {1:x}".format(gpio, csr_val))
134 # gpio_parse_csr(csr_val)
135 return data
136
137 # TODO
138 def gpio_rd_input(dut, gpio):
139 in_val = yield from wb_read(dut.bus, gpio | (IADDR<<ADDROFFSET))
140 print("GPIO{0} | Input: {1:b}".format(gpio, in_val))
141 return data
142
143 def gpio_set_out(dut, gpio, output):
144 yield from wb_write(dut.bus, gpio | (OADDR<<ADDROFFSET), (output<<OSHIFT))
145
146 # TODO: There's probably a cleaner way to clear the bit...
147 def gpio_set_in_pad(dut, gpio, in_val):
148 old_in_val = yield dut.gpio_i
149 if in_val:
150 new_in_val = old_in_val | (in_val << gpio)
151 else:
152 temp = (old_in_val >> gpio) & 1
153 if temp:
154 mask = ~(1 << gpio)
155 new_in_val = old_in_val & mask
156 else:
157 new_in_val = old_in_val
158 print("Previous GPIO i: {0:b} | New GPIO i: {1:b}"
159 .format(old_in_val, new_in_val))
160 yield dut.gpio_i.eq(new_in_val)
161
162 def sim_gpio(dut, use_random=True):
163
164 # GPIO0
165 #data = yield from read_gpio(gpio, 0) # read gpio addr 0
166 #yield from wb_write(gpio.bus, 0, 1) # write gpio addr 0
167 #data = yield from read_gpio(gpio, 0) # read gpio addr 0
168 print(dir(dut))
169 print(dut)
170 num_gpios = len(dut.gpio_o)
171 if use_random:
172 bank_sel = randint(0, num_gpios)
173 else:
174 bank_sel = 3 # not special, chose for testing
175 oe = 1
176 output = 0
177 # Configure GPIOs for
178 for gpio in range(0, num_gpios):
179 yield from gpio_configure(dut, gpio, oe, output, bank_sel)
180
181 for gpio in range(0, num_gpios):
182 yield from gpio_set_out(dut, gpio, 1)
183
184 for gpio in range(0, num_gpios):
185 yield from gpio_set_in_pad(dut, gpio, 1)
186 yield
187
188 for gpio in range(0, num_gpios):
189 yield from gpio_set_in_pad(dut, gpio, 0)
190 yield
191
192 print("Finished the simple GPIO block test!")
193
194 def test_gpio():
195
196 dut = SimpleGPIO()
197 vl = rtlil.convert(dut, ports=dut.ports())
198 with open("test_gpio.il", "w") as f:
199 f.write(vl)
200
201 m = Module()
202 m.submodules.xics_icp = dut
203
204 sim = Simulator(m)
205 sim.add_clock(1e-6)
206
207 sim.add_sync_process(wrap(sim_gpio(dut)))
208 sim_writer = sim.write_vcd('test_gpio.vcd')
209 with sim_writer:
210 sim.run()
211
212
213 if __name__ == '__main__':
214 test_gpio()
215