1 """Simple GPIO peripheral on wishbone
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
6 Modified for use with pinmux, will probably change the class name later.
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
18 from nmigen
.sim
.cxxsim
import Simulator
, Settle
20 from nmigen
.sim
import Simulator
, Settle
22 # Layout of 8-bit configuration word:
23 # bank_select[2:0] i/o | pden puen ien oe
30 NUM_BANKSEL_BITS
= 3 # only supporting 8 banks (0-7)
33 WORDSIZE
= 8 # in bytes
35 class SimpleGPIO(Elaboratable
):
37 def __init__(self
, n_gpio
=16):
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
)
54 def elaborate(self
, platform
):
56 comb
, sync
= m
.d
.comb
, m
.d
.sync
59 wb_rd_data
= bus
.dat_r
60 wb_wr_data
= bus
.dat_w
63 bank_sel
= self
.bank_sel
65 gpio_oe
= self
.gpio_oe
67 gpio_ie
= self
.gpio_ie
73 #for i in range(0, self.n_gpio):
75 gpio_addr
= Signal(log2_int(self
.n_gpio
))
76 gpio_o_list
= Array(list(gpio_o
))
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
))
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
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
])
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
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
))
113 for field
in self
.bus
.fields
.values():
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
)
127 print("Configuring CSR to {0:x}".format(csr_val
))
128 yield from wb_write(dut
.bus
, gpio
, csr_val
)
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)
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
))
143 def gpio_set_out(dut
, gpio
, output
):
144 yield from wb_write(dut
.bus
, gpio |
(OADDR
<<ADDROFFSET
), (output
<<OSHIFT
))
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
150 new_in_val
= old_in_val |
(in_val
<< gpio
)
152 temp
= (old_in_val
>> gpio
) & 1
155 new_in_val
= old_in_val
& mask
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
)
162 def sim_gpio(dut
, use_random
=True):
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
170 num_gpios
= len(dut
.gpio_o
)
172 bank_sel
= randint(0, num_gpios
)
174 bank_sel
= 3 # not special, chose for testing
177 # Configure GPIOs for
178 for gpio
in range(0, num_gpios
):
179 yield from gpio_configure(dut
, gpio
, oe
, output
, bank_sel
)
181 for gpio
in range(0, num_gpios
):
182 yield from gpio_set_out(dut
, gpio
, 1)
184 for gpio
in range(0, num_gpios
):
185 yield from gpio_set_in_pad(dut
, gpio
, 1)
188 for gpio
in range(0, num_gpios
):
189 yield from gpio_set_in_pad(dut
, gpio
, 0)
192 print("Finished the simple GPIO block test!")
197 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
198 with
open("test_gpio.il", "w") as f
:
202 m
.submodules
.xics_icp
= dut
207 sim
.add_sync_process(wrap(sim_gpio(dut
)))
208 sim_writer
= sim
.write_vcd('test_gpio.vcd')
213 if __name__
== '__main__':