Skip to content

Commit 2006ab8

Browse files
committed
riscv-demo: add reference implementation.
1 parent b1386c1 commit 2006ab8

File tree

2 files changed

+162
-2
lines changed

2 files changed

+162
-2
lines changed

riscv-demo/riscv_demo/ips/uart.py

+96-1
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,99 @@
1111
__all__ = ["UARTPeripheral"]
1212

1313

14-
# TODO
14+
class UARTPeripheral(wiring.Component):
15+
class TxData(csr.Register, access="w"):
16+
"""valid to write to when tx_ready is 1, will trigger a transmit"""
17+
def __init__(self):
18+
super().__init__(csr.Field(csr.action.W, 8))
19+
20+
class RxData(csr.Register, access="r"):
21+
"""valid to read from when rx_avail is 1, last received byte"""
22+
def __init__(self):
23+
super().__init__(csr.Field(csr.action.R, 8))
24+
25+
class TxReady(csr.Register, access="r"):
26+
"""is '1' when 1-byte transmit buffer is empty"""
27+
def __init__(self):
28+
super().__init__(csr.Field(csr.action.R, 1))
29+
30+
class RxAvail(csr.Register, access="r"):
31+
"""is '1' when 1-byte receive buffer is full; reset by a read from rx_data"""
32+
def __init__(self):
33+
super().__init__(csr.Field(csr.action.R, 1))
34+
35+
class Divisor(csr.Register, access="rw"):
36+
"""baud divider, defaults to init_divisor"""
37+
def __init__(self, init_divisor):
38+
super().__init__(csr.Field(csr.action.RW, 24, init=init_divisor))
39+
40+
"""
41+
A custom, minimal UART.
42+
"""
43+
def __init__(self, *, ports, init_divisor):
44+
assert len(ports.rx) == 1 and ports.rx.direction in (io.Direction.Input, io.Direction.Bidir)
45+
assert len(ports.tx) == 1 and ports.tx.direction in (io.Direction.Output, io.Direction.Bidir)
46+
47+
self.ports = PortGroup(rx=ports.rx, tx=ports.tx)
48+
self.init_divisor = init_divisor
49+
50+
regs = csr.Builder(addr_width=5, data_width=8)
51+
52+
self._tx_data = regs.add("tx_data", self.TxData(), offset=0x00)
53+
self._rx_data = regs.add("rx_data", self.RxData(), offset=0x04)
54+
self._tx_ready = regs.add("tx_ready", self.TxReady(), offset=0x08)
55+
self._rx_avail = regs.add("rx_avail", self.RxAvail(), offset=0x0c)
56+
self._divisor = regs.add("divisor", self.Divisor(init_divisor), offset=0x10)
57+
58+
self._bridge = csr.Bridge(regs.as_memory_map())
59+
60+
super().__init__({
61+
"csr_bus": In(csr.Signature(addr_width=regs.addr_width, data_width=regs.data_width)),
62+
})
63+
self.csr_bus.memory_map = self._bridge.bus.memory_map
64+
65+
def elaborate(self, platform):
66+
m = Module()
67+
m.submodules.bridge = self._bridge
68+
69+
connect(m, flipped(self.csr_bus), self._bridge.bus)
70+
71+
m.submodules.rx_buffer = rx_buffer = io.Buffer("i", self.ports.rx)
72+
m.submodules.tx_buffer = tx_buffer = io.Buffer("o", self.ports.tx)
73+
74+
m.submodules.tx = tx = AsyncSerialTX(divisor=self.init_divisor, divisor_bits=24)
75+
m.d.comb += [
76+
tx_buffer.o.eq(tx.o),
77+
78+
tx.data.eq(self._tx_data.f.w_data),
79+
tx.ack.eq(self._tx_data.f.w_stb),
80+
self._tx_ready.f.r_data.eq(tx.rdy),
81+
82+
tx.divisor.eq(self._divisor.f.data)
83+
]
84+
85+
rx_data_ff = Signal(8)
86+
rx_avail = Signal()
87+
88+
m.submodules.rx = rx = AsyncSerialRX(divisor=self.init_divisor, divisor_bits=24)
89+
90+
with m.If(self._rx_data.f.r_stb):
91+
m.d.sync += rx_avail.eq(0)
92+
93+
with m.If(rx.rdy):
94+
m.d.sync += [
95+
rx_data_ff.eq(rx.data),
96+
rx_avail.eq(1)
97+
]
98+
99+
m.d.comb += [
100+
rx.i.eq(rx_buffer.i),
101+
102+
self._rx_data.f.r_data.eq(rx_data_ff),
103+
self._rx_avail.f.r_data.eq(rx_avail),
104+
rx.ack.eq(~rx_avail),
105+
106+
rx.divisor.eq(self._divisor.f.data)
107+
]
108+
109+
return m

riscv-demo/riscv_demo/soc.py

+66-1
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,69 @@
1515
__all__ = ["DemoSoC"]
1616

1717

18-
# TODO
18+
class DemoSoC(wiring.Component):
19+
def __init__(self, ports):
20+
super().__init__({})
21+
22+
self.ports = ports
23+
24+
# Memory regions:
25+
self.mem_spiflash_base = 0x00000000
26+
self.mem_sram_base = 0x10000000
27+
28+
# CSR regions:
29+
self.csr_base = 0xb0000000
30+
self.csr_spiflash_base = 0xb0000000
31+
self.csr_uart_base = 0xb2000000
32+
33+
self.sram_size = 0x400 # 1KiB
34+
self.bios_start = 0x100000 # 1MiB into spiflash
35+
36+
def elaborate(self, platform):
37+
m = Module()
38+
39+
wb_arbiter = wishbone.Arbiter(addr_width=30, data_width=32, granularity=8)
40+
wb_decoder = wishbone.Decoder(addr_width=30, data_width=32, granularity=8)
41+
csr_decoder = csr.Decoder(addr_width=28, data_width=8)
42+
43+
m.submodules.wb_arbiter = wb_arbiter
44+
m.submodules.wb_decoder = wb_decoder
45+
m.submodules.csr_decoder = csr_decoder
46+
47+
connect(m, wb_arbiter.bus, wb_decoder.bus)
48+
49+
# CPU
50+
51+
m.submodules.cpu = cpu = Minerva(reset_address=self.bios_start)
52+
53+
wb_arbiter.add(cpu.ibus)
54+
wb_arbiter.add(cpu.dbus)
55+
56+
# SPI flash
57+
58+
qspi = QSPIController(self.ports.qspi)
59+
spiflash = WishboneQSPIFlashController(addr_width=24, data_width=32)
60+
m.submodules.qspi = qspi
61+
m.submodules.spiflash = spiflash
62+
63+
wb_decoder.add(spiflash.wb_bus, name="spiflash", addr=self.mem_spiflash_base)
64+
65+
connect(m, spiflash.spi_bus, qspi)
66+
67+
# SRAM
68+
69+
m.submodules.sram = sram = WishboneSRAM(size=self.sram_size, data_width=32, granularity=8)
70+
wb_decoder.add(sram.wb_bus, name="sram", addr=self.mem_sram_base)
71+
72+
# UART
73+
74+
uart_divisor = int(48e6 // 115200)
75+
m.submodules.uart = uart = UARTPeripheral(ports=self.ports.uart, init_divisor=uart_divisor)
76+
csr_decoder.add(uart.csr_bus, name="uart", addr=self.csr_uart_base - self.csr_base)
77+
78+
# Wishbone-CSR bridge
79+
80+
m.submodules.wb_to_csr = wb_to_csr = WishboneCSRBridge(csr_decoder.bus, data_width=32)
81+
wb_decoder.add(wb_to_csr.wb_bus, name="csr", addr=self.csr_base, sparse=False)
82+
83+
return m

0 commit comments

Comments
 (0)