Added a few TODOs
[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 # Bit shift position for CSR word used in WB transactions
23 ADDROFFSET = 8 # offset where CSR/output/input addr are specified
24 CSRADDR = 0 # addr to access CSR
25 OADDR = 1 # addr needed to write/read output
26 IADDR = 2 # addr to read GPIO inputs
27 # Layout of 16-bit configuration word (? is unused):
28 # ? ? ? i | bank_select[3:0] |? pden puen opendrain |? ien oe o
29 ISHIFT = 12
30 BANKSHIFT = 8
31 # Pull-up/down, open-drain, ien have been skipped for now
32 OESHIFT = 1
33 OSHIFT = 0
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(4) # set maximum number of banks to 16
47 self.gpio_o = Signal(n_gpio)
48 self.gpio_oe = Signal(n_gpio)
49 self.gpio_i = Signal(n_gpio)
50
51 def elaborate(self, platform):
52 m = Module()
53 comb, sync = m.d.comb, m.d.sync
54
55 bus = self.bus
56 wb_rd_data = bus.dat_r
57 wb_wr_data = bus.dat_w
58 wb_ack = bus.ack
59
60 bank_sel = self.bank_sel
61 gpio_o = self.gpio_o
62 gpio_oe = self.gpio_oe
63 gpio_i = self.gpio_i
64
65 comb += wb_ack.eq(0)
66
67 gpio_addr = Signal(log2_int(self.n_gpio))
68 gpio_o_list = Array(list(gpio_o))
69 print(bank_sel)
70 print(gpio_o_list)
71 gpio_oe_list = Array(list(gpio_oe))
72 gpio_i_list = Array(list(gpio_i))
73
74 # Address first byte for GPIO (max would be 256 GPIOs)
75 # Address second byte, bit 0 indicates input read
76 with m.If(bus.cyc & bus.stb):
77 comb += wb_ack.eq(1) # always ack
78 comb += gpio_addr.eq(bus.adr[0:ADDROFFSET])
79 with m.If(bus.we): # write
80 # Write/set output
81 with m.If(bus.adr[ADDROFFSET:] == OADDR):
82 sync += gpio_o_list[gpio_addr].eq(wb_wr_data[OSHIFT])
83 # Write/set CSR
84 with m.Else():
85 sync += gpio_o_list[gpio_addr].eq(wb_wr_data[OSHIFT])
86 sync += gpio_oe_list[gpio_addr].eq(wb_wr_data[OESHIFT])
87 sync += bank_sel.eq(wb_wr_data[BANKSHIFT:BANKSHIFT+4])
88 with m.Else(): # read
89 # Read the value of the input
90 with m.If(bus.adr[ADDROFFSET:] == OADDR):
91 comb += wb_rd_data.eq(gpio_o_list[gpio_addr])
92 with m.If(bus.adr[ADDROFFSET:] == IADDR):
93 comb += wb_rd_data.eq(gpio_i_list[gpio_addr])
94 # Read the state of CSR bits
95 with m.Else():
96 comb += wb_rd_data.eq((gpio_o_list[gpio_addr] << OSHIFT)
97 + (gpio_oe_list[gpio_addr] << OESHIFT)
98 + (bank_sel << BANKSHIFT))
99 #comb += wb_rd_data.eq(gpio_a[gpio_addr])
100
101 return m
102
103 def __iter__(self):
104 for field in self.bus.fields.values():
105 yield field
106 yield self.gpio_o
107
108 def ports(self):
109 return list(self)
110
111
112
113 def gpio_configure(dut, gpio, oe, output=0, bank_sel=0):
114 csr_val = ( (bank_sel << BANKSHIFT)
115 | (oe << OESHIFT)
116 | (output << OSHIFT) )
117 # | (PUEN, PDUN, Open-drain etc...)
118 print("Configuring CSR to {0:x}".format(csr_val))
119 yield from wb_write(dut.bus, gpio, csr_val)
120
121 # TODO: Return the configuration states
122 def gpio_rd_csr(dut, gpio):
123 csr_val = yield from wb_read(dut.bus, gpio)
124 print("GPIO{0} | CSR: {1:x}".format(gpio, csr_val))
125 # gpio_parse_csr(csr_val)
126 return data
127
128 def gpio_rd_input(dut, gpio):
129 in_val = yield from wb_read(dut.bus, gpio | (IADDR<<ADDROFFSET))
130 print("GPIO{0} | Input: {1:b}".format(gpio, in_val))
131 return data
132
133 def gpio_set_out(dut, gpio, output):
134 yield from wb_write(dut.bus, gpio | (OADDR<<ADDROFFSET), (output<<OSHIFT))
135
136 # TODO: There's probably a cleaner way to clear the bit...
137 def gpio_set_in_pad(dut, gpio, in_val):
138 old_in_val = yield dut.gpio_i
139 if in_val:
140 new_in_val = old_in_val | (in_val << gpio)
141 else:
142 temp = (old_in_val >> gpio) & 1
143 if temp:
144 mask = ~(1 << gpio)
145 new_in_val = old_in_val & mask
146 else:
147 new_in_val = old_in_val
148 print("Previous GPIO i: {0:b} | New GPIO i: {1:b}"
149 .format(old_in_val, new_in_val))
150 yield dut.gpio_i.eq(new_in_val)
151
152 def sim_gpio(dut, use_random=True):
153
154 # GPIO0
155 #data = yield from read_gpio(gpio, 0) # read gpio addr 0
156 #yield from wb_write(gpio.bus, 0, 1) # write gpio addr 0
157 #data = yield from read_gpio(gpio, 0) # read gpio addr 0
158 print(dir(dut))
159 print(dut)
160 num_gpios = len(dut.gpio_o)
161 if use_random:
162 bank_sel = randint(0, num_gpios)
163 else:
164 bank_sel = 3 # not special, chose for testing
165 oe = 1
166 output = 0
167 # Configure GPIOs for
168 for gpio in range(0, num_gpios):
169 yield from gpio_configure(dut, gpio, oe, output, bank_sel)
170
171 for gpio in range(0, num_gpios):
172 yield from gpio_set_out(dut, gpio, 1)
173
174 for gpio in range(0, num_gpios):
175 yield from gpio_set_in_pad(dut, gpio, 1)
176 yield
177
178 for gpio in range(0, num_gpios):
179 yield from gpio_set_in_pad(dut, gpio, 0)
180 yield
181
182 print("Finished the simple GPIO block test!")
183
184 def test_gpio():
185
186 dut = SimpleGPIO()
187 vl = rtlil.convert(dut, ports=dut.ports())
188 with open("test_gpio.il", "w") as f:
189 f.write(vl)
190
191 m = Module()
192 m.submodules.xics_icp = dut
193
194 sim = Simulator(m)
195 sim.add_clock(1e-6)
196
197 sim.add_sync_process(wrap(sim_gpio(dut)))
198 sim_writer = sim.write_vcd('test_gpio.vcd')
199 with sim_writer:
200 sim.run()
201
202
203 if __name__ == '__main__':
204 test_gpio()
205