8891e16dc55fa34880ff154d16c22aab6e28ad4b
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.
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 # Bit shift position for CSR word used in WB transactions
23 IADDRSHIFT
= 8 # offset needed to tell WB to return input ONLY
24 # Layout of 16-bit configuration word (? is unused):
25 # ? ? ? i | bank_select[3:0] |? pden puen opendrain |? ien oe o
28 # Pull-up/down, open-drain, ien have been skipped for now
32 class SimpleGPIO(Elaboratable
):
34 def __init__(self
, n_gpio
=16):
41 self
.bus
= Record(make_wb_layout(spec
), name
="gpio_wb")
42 # ONLY ONE BANK FOR ALL GPIOs atm...
43 self
.bank_sel
= Signal(4) # set maximum number of banks to 16
44 self
.gpio_o
= Signal(n_gpio
)
45 self
.gpio_oe
= Signal(n_gpio
)
46 self
.gpio_i
= Signal(n_gpio
)
48 def elaborate(self
, platform
):
50 comb
, sync
= m
.d
.comb
, m
.d
.sync
53 wb_rd_data
= bus
.dat_r
54 wb_wr_data
= bus
.dat_w
57 bank_sel
= self
.bank_sel
59 gpio_oe
= self
.gpio_oe
64 gpio_addr
= Signal(log2_int(self
.n_gpio
))
65 gpio_o_list
= Array(list(gpio_o
))
68 gpio_oe_list
= Array(list(gpio_oe
))
69 gpio_i_list
= Array(list(gpio_i
))
71 # Address first byte for GPIO (max would be 256 GPIOs)
72 # Address second byte, bit 0 indicates input read
73 with m
.If(bus
.cyc
& bus
.stb
):
74 comb
+= wb_ack
.eq(1) # always ack
75 comb
+= gpio_addr
.eq(bus
.adr
[0:8])
76 with m
.If(bus
.we
): # write
78 sync
+= gpio_o_list
[gpio_addr
].eq(wb_wr_data
[OSHIFT
])
79 sync
+= gpio_oe_list
[gpio_addr
].eq(wb_wr_data
[OESHIFT
])
80 sync
+= bank_sel
.eq(wb_wr_data
[BANKSHIFT
:BANKSHIFT
+4])
82 # Read the value of the input
83 with m
.If(bus
.adr
[8]):
84 comb
+= wb_rd_data
.eq(gpio_i_list
[gpio_addr
])
85 # Read the state of CSR bits
87 comb
+= wb_rd_data
.eq((gpio_o_list
[gpio_addr
] << OSHIFT
)
88 + (gpio_oe_list
[gpio_addr
] << OESHIFT
)
89 + (bank_sel
<< BANKSHIFT
))
90 #comb += wb_rd_data.eq(gpio_a[gpio_addr])
95 for field
in self
.bus
.fields
.values():
104 def gpio_configure(dut
, gpio
, oe
, output
=0, bank_sel
=0):
105 csr_val
= ( (bank_sel
<< BANKSHIFT
)
107 |
(output
<< OSHIFT
) )
108 # | (PUEN, PDUN, Open-drain etc...)
109 print("Configuring CSR to {0:x}".format(csr_val
))
110 yield from wb_write(dut
.bus
, gpio
, csr_val
)
112 def gpio_rd_csr(dut
, gpio
):
113 csr_val
= yield from wb_read(dut
.bus
, gpio
)
114 print("GPIO{0} | CSR: {1:x}".format(gpio
, csr_val
))
115 # gpio_parse_csr(csr_val)
118 def gpio_rd_input(dut
, gpio
):
119 in_val
= yield from wb_read(dut
.bus
, gpio |
(1<<IADDRSHIFT
))
120 print("GPIO{0} | Input: {1:b}".format(gpio
, in_val
))
123 def gpio_set_out(dut
, gpio
, output
):
124 yield from wb_write(dut
.bus
, gpio
, (output
<< OSHIFT
))
126 def gpio_set_in_pad(dut
, gpio
, in_val
):
127 yield dut
.gpio_i
.eq(in_val
)
133 #data = yield from read_gpio(gpio, 0) # read gpio addr 0
134 #yield from wb_write(gpio.bus, 0, 1) # write gpio addr 0
135 #data = yield from read_gpio(gpio, 0) # read gpio addr 0
138 num_gpios
= len(dut
.gpio_o
)
142 for gpio
in range(0, num_gpios
):
143 yield from gpio_configure(dut
, gpio
, oe
, output
, bank_sel
)
145 for gpio
in range(0, num_gpios
):
146 yield from gpio_set_out(dut
, gpio
, 1)
148 #for gpio in range(0, num_gpios):
149 # yield from gpio_set_in_pad(dut, gpio, 1)
150 yield from gpio_set_in_pad(dut
, 0, 1)
152 yield from gpio_set_in_pad(dut
, 1, 1)
154 yield from gpio_set_in_pad(dut
, 2, 1)
156 yield from gpio_set_in_pad(dut
, 3, 1)
158 yield from gpio_set_in_pad(dut
, 2, 0)
161 print("Finished the simple GPIO block test!")
166 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
167 with
open("test_gpio.il", "w") as f
:
171 m
.submodules
.xics_icp
= dut
176 sim
.add_sync_process(wrap(sim_gpio(dut
)))
177 sim_writer
= sim
.write_vcd('test_gpio.vcd')
182 if __name__
== '__main__':