Skip to content

Commit 191c5d8

Browse files
Merge pull request enjoy-digital#2211 from mohammadshahidzade/master
Add Linux support for CVA5, including PLIC and CLINT and major bug fixes
2 parents fbf218f + b27e7d3 commit 191c5d8

File tree

6 files changed

+402
-74
lines changed

6 files changed

+402
-74
lines changed
Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
.section .text, "ax", @progbits
2-
.global boot_helper
2+
.global boot_helper
3+
.global smp_lottery_target
4+
.global smp_lottery_lock
5+
.global smp_lottery_args
6+
37
boot_helper:
4-
jr x13
8+
sw x10, smp_lottery_args , x14
9+
sw x11, smp_lottery_args+4, x14
10+
sw x12, smp_lottery_args+8, x14
11+
sw x13, smp_lottery_target, x14
12+
fence w, w
13+
li x15, 1
14+
sw x15, smp_lottery_lock, x14
15+
jr x13

litex/soc/cores/cpu/cva5/core.py

Lines changed: 238 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
from litex.gen import *
1414

1515
from litex.soc.interconnect import wishbone
16+
from litex.soc.interconnect import axi
1617
from litex.soc.interconnect.csr import *
1718
from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32
19+
from litex.soc.integration.soc import SoCRegion
1820

1921
# Variants -----------------------------------------------------------------------------------------
2022

21-
CPU_VARIANTS = ["minimal", "standard"]
23+
CPU_VARIANTS = ["minimal", "standard","standard+atomic","standard+atomic+float+double"]
2224

2325
# GCC Flags ----------------------------------------------------------------------------------------
2426

@@ -32,6 +34,8 @@
3234
# i macfd
3335
"minimal" : "-march=rv32i2p0 -mabi=ilp32 ",
3436
"standard" : "-march=rv32i2p0_m -mabi=ilp32 ",
37+
"standard+atomic" : "-march=rv32i2p0_ma -mabi=ilp32 ",
38+
"standard+atomic+float+double" : "-march=rv32i2p0_mafd -mabi=ilp32 ",
3539
}
3640

3741
# CVA5 ----------------------------------------------------------------------------------------------
@@ -47,12 +51,51 @@ class CVA5(CPU):
4751
linker_output_format = "elf32-littleriscv"
4852
nop = "nop"
4953
io_regions = {0x80000000: 0x80000000} # origin, length
54+
plic_base = 0xf800_0000
55+
clint_base = 0xf001_0000
56+
cpu_count = 1
57+
bus_type = "wishbone" #either wishbone or axi
58+
cpu_variant = "Linux" #either linux or default
5059

60+
61+
62+
@staticmethod
63+
def args_fill(parser):
64+
cpu_group = parser.add_argument_group(title="CPU options")
65+
cpu_group.add_argument("--cpu-count", default=1, help="Number of CPU(s) in the cluster.", type=int)
66+
cpu_group.add_argument("--clint-base", default="0xf0010000", help="CLINT base address.")
67+
cpu_group.add_argument("--plic-base", default="0xf800_0000", help="PLIC base address.")
68+
cpu_group.add_argument("--bus-type", default="wishbone", help="Bus type can be either wishbone or axi")
69+
cpu_group.add_argument("--variant", default="Linux", help="The CPU type for now it has the linux type")#TODO add other configs
70+
71+
@staticmethod
72+
def args_read(args):
73+
CVA5.cpu_count = args.cpu_count
74+
CVA5.bus_type = args.bus_type
75+
CVA5.cpu_variant = args.variant
76+
if(args.clint_base): CVA5.clint_base = int(args.clint_base, 16)
77+
if(args.plic_base): CVA5.plic_base = int(args.plic_base, 16)
78+
79+
80+
81+
# Memory Mapping.
82+
@property
83+
def mem_map(self):
84+
return {
85+
"rom": 0x0000_0000,
86+
"sram": 0x0100_0000,
87+
"main_ram": 0x4000_0000,
88+
"csr": 0xf000_0000,
89+
}
90+
5191
# GCC Flags.
5292
@property
5393
def gcc_flags(self):
5494
flags = GCC_FLAGS[self.variant]
55-
flags += "-D__cva5__"
95+
if(CVA5.cpu_variant=="Linux"):
96+
flags += "-D__riscv_plic__"
97+
else:
98+
flags += "-D__cva5__"
5699
return flags
57100

58101
def __init__(self, platform, variant="standard"):
@@ -63,60 +106,23 @@ def __init__(self, platform, variant="standard"):
63106
self.interrupt = Signal(2)
64107
self.periph_buses = [] # Peripheral buses (Connected to main SoC's bus).
65108
self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM).
66-
67-
# # #
109+
self.reset = Signal()
68110

69111
# CPU Instance.
70112
self.cpu_params = dict(
71-
# Configuration.
72-
p_LITEX_VARIANT = CPU_VARIANTS.index(variant),
113+
# Configuration.
73114
p_RESET_VEC = 0,
74115
p_NON_CACHABLE_L = 0x80000000, # FIXME: Use io_regions.
75116
p_NON_CACHABLE_H = 0xFFFFFFFF, # FIXME: Use io_regions.
117+
p_NUM_CORES = CVA5.cpu_count,
118+
p_AXI = 0 if CVA5.bus_type == "wishbone" else 1,
76119

77120
# Clk/Rst.
78121
i_clk = ClockSignal("sys"),
79-
i_rst = ResetSignal("sys"),
80-
81-
# Interrupts.
82-
i_litex_interrupt = self.interrupt
122+
i_rst = ResetSignal("sys") | self.reset,
83123
)
84-
# CPU Wishbone Buses.
85-
if variant == "minimal":
86-
# Minimal variant has no caches, no multiply or divide support, and no branch predictor.
87-
# It also uses separate fetch and load-store wishbone interfaces.
88-
self.ibus = ibus = wishbone.Interface(data_width=32, address_width=32, addressing="word")
89-
self.dbus = dbus = wishbone.Interface(data_width=32, address_width=32, addressing="word")
90-
self.periph_buses.append(ibus)
91-
self.periph_buses.append(dbus)
92-
self.cpu_params.update(
93-
o_ibus_adr = ibus.adr,
94-
o_ibus_dat_w = ibus.dat_w,
95-
o_ibus_sel = ibus.sel,
96-
o_ibus_cyc = ibus.cyc,
97-
o_ibus_stb = ibus.stb,
98-
o_ibus_we = ibus.we,
99-
o_ibus_cti = ibus.cti,
100-
o_ibus_bte = ibus.bte,
101-
i_ibus_dat_r = ibus.dat_r,
102-
i_ibus_ack = ibus.ack,
103-
i_ibus_err = ibus.err,
104-
105-
o_dbus_adr = dbus.adr,
106-
o_dbus_dat_w = dbus.dat_w,
107-
o_dbus_sel = dbus.sel,
108-
o_dbus_cyc = dbus.cyc,
109-
o_dbus_stb = dbus.stb,
110-
o_dbus_we = dbus.we,
111-
o_dbus_cti = dbus.cti,
112-
o_dbus_bte = dbus.bte,
113-
i_dbus_dat_r = dbus.dat_r,
114-
i_dbus_ack = dbus.ack,
115-
i_dbus_err = dbus.err
116-
)
117-
if variant == "standard":
118-
# Standard variant includes instruction and data caches, multiply and divide support
119-
# along with the branch predictor. It uses a shared wishbone interface.
124+
125+
if(CVA5.bus_type == "wishbone"):
120126
self.idbus = idbus = wishbone.Interface(data_width=32, address_width=32, addressing="word")
121127
self.periph_buses.append(idbus)
122128
self.cpu_params.update(
@@ -132,6 +138,52 @@ def __init__(self, platform, variant="standard"):
132138
i_idbus_ack = idbus.ack,
133139
i_idbus_err = idbus.err,
134140
)
141+
else:
142+
self.axi_if = axi_if = axi.AXIInterface(data_width=32, address_width=32, id_width=4)
143+
self.periph_buses.append(axi_if)
144+
145+
self.cpu_params.update(
146+
# AXI read address channel
147+
i_m_axi_arready = axi_if.ar.ready,
148+
o_m_axi_arvalid = axi_if.ar.valid,
149+
o_m_axi_araddr = axi_if.ar.addr,
150+
o_m_axi_arlen = axi_if.ar.len,
151+
o_m_axi_arsize = axi_if.ar.size,
152+
o_m_axi_arburst = axi_if.ar.burst,
153+
o_m_axi_arcache = axi_if.ar.cache,
154+
o_m_axi_arid = axi_if.ar.id,
155+
156+
# AXI read data channel
157+
o_m_axi_rready = axi_if.r.ready,
158+
i_m_axi_rvalid = axi_if.r.valid,
159+
i_m_axi_rdata = axi_if.r.data,
160+
i_m_axi_rresp = axi_if.r.resp,
161+
i_m_axi_rlast = axi_if.r.last,
162+
i_m_axi_rid = axi_if.r.id,
163+
164+
# AXI write address channel
165+
i_m_axi_awready = axi_if.aw.ready,
166+
o_m_axi_awvalid = axi_if.aw.valid,
167+
o_m_axi_awaddr = axi_if.aw.addr,
168+
o_m_axi_awlen = axi_if.aw.len,
169+
o_m_axi_awsize = axi_if.aw.size,
170+
o_m_axi_awburst = axi_if.aw.burst,
171+
o_m_axi_awcache = axi_if.aw.cache,
172+
o_m_axi_awid = axi_if.aw.id,
173+
174+
# AXI write data channel
175+
i_m_axi_wready = axi_if.w.ready,
176+
o_m_axi_wvalid = axi_if.w.valid,
177+
o_m_axi_wdata = axi_if.w.data,
178+
o_m_axi_wstrb = axi_if.w.strb,
179+
o_m_axi_wlast = axi_if.w.last,
180+
181+
# AXI write response channel
182+
o_m_axi_bready = axi_if.b.ready,
183+
i_m_axi_bvalid = axi_if.b.valid,
184+
i_m_axi_bresp = axi_if.b.resp,
185+
i_m_axi_bid = axi_if.b.id,
186+
)
135187
self.add_sources(platform)
136188

137189
def set_reset_address(self, reset_address):
@@ -146,9 +198,148 @@ def add_sources(platform):
146198
for line in f:
147199
if line.strip() != '':
148200
platform.add_source(os.path.join(cva5_path, line.strip()))
149-
platform.add_source(os.path.join(cva5_path, "examples/litex/l1_to_wishbone.sv"))
150201
platform.add_source(os.path.join(cva5_path, "examples/litex/litex_wrapper.sv"))
151202

152203
def do_finalize(self):
153204
assert hasattr(self, "reset_address")
154205
self.specials += Instance("litex_wrapper", **self.cpu_params)
206+
207+
def add_soc_components(self, soc):
208+
soc.csr.add("sdram", n=1)
209+
soc.csr.add("uart", n=2)
210+
soc.csr.add("timer0", n=3)
211+
soc.csr.add("supervisor", n=4)
212+
213+
# PLIC
214+
seip = Signal(int(self.cpu_params["p_NUM_CORES"]))
215+
meip = Signal(int(self.cpu_params["p_NUM_CORES"]))
216+
eip = Signal(2*int(self.cpu_params["p_NUM_CORES"]))
217+
es = Signal(2, reset=0)
218+
219+
if(CVA5.cpu_variant == "Linux"):
220+
if(CVA5.bus_type == "wishbone"):
221+
self.plicbus = plicbus = wishbone.Interface(data_width=32, address_width=32, addressing="word")
222+
self.specials += Instance("plic_wrapper",
223+
p_NUM_SOURCES = 1,
224+
p_NUM_TARGETS = 2*int(self.cpu_params["p_NUM_CORES"]),
225+
p_PRIORITY_W = 8,
226+
p_REG_STAGE = 1,
227+
p_AXI = 0,
228+
i_clk = ClockSignal("sys"),
229+
i_rst = ResetSignal("sys"),
230+
i_irq_srcs = self.interrupt,
231+
i_edge_sensitive = es,
232+
o_eip = eip,
233+
i_wb_cyc = plicbus.cyc,
234+
i_wb_stb = plicbus.stb,
235+
i_wb_we = plicbus.we,
236+
i_wb_adr = plicbus.adr,
237+
i_wb_dat_i = plicbus.dat_w,
238+
o_wb_dat_o = plicbus.dat_r,
239+
o_wb_ack = plicbus.ack,
240+
)
241+
else:
242+
self.plicbus = plicbus = axi.AXIInterface(data_width=32, address_width=32, id_width=4)
243+
self.specials += Instance("plic_wrapper",
244+
p_NUM_SOURCES = 1,
245+
p_NUM_TARGETS = 2*int(self.cpu_params["p_NUM_CORES"]),
246+
p_PRIORITY_W = 8,
247+
p_REG_STAGE = 1,
248+
p_AXI = 1,
249+
i_clk = ClockSignal("sys"),
250+
i_rst = ResetSignal("sys"),
251+
i_irq_srcs = self.interrupt,
252+
i_edge_sensitive = es,
253+
o_eip = eip,
254+
i_s_axi_awvalid = plicbus.aw.valid,
255+
i_s_axi_awaddr = plicbus.aw.addr,
256+
i_s_axi_wvalid = plicbus.w.valid,
257+
i_s_axi_wdata = plicbus.w.data,
258+
i_s_axi_bready = plicbus.b.ready,
259+
i_s_axi_arvalid = plicbus.ar.valid,
260+
i_s_axi_araddr = plicbus.ar.addr,
261+
i_s_axi_rready = plicbus.r.ready,
262+
o_s_axi_awready = plicbus.aw.ready,
263+
o_s_axi_wready = plicbus.w.ready,
264+
o_s_axi_bvalid = plicbus.b.valid,
265+
o_s_axi_arready = plicbus.ar.ready,
266+
o_s_axi_rvalid = plicbus.r.valid,
267+
o_s_axi_rdata = plicbus.r.data
268+
)
269+
270+
self.comb += [
271+
meip.eq(Cat(*[eip[i*2] for i in range(int(self.cpu_params["p_NUM_CORES"]))])),
272+
seip.eq(Cat(*[eip[i*2 + 1] for i in range(int(self.cpu_params["p_NUM_CORES"]))]))
273+
]
274+
275+
self.cpu_params.update(
276+
i_seip = seip,
277+
i_meip = meip
278+
)
279+
soc.bus.add_slave("plic", self.plicbus, region=SoCRegion(origin=self.plic_base, size=0x40_0000, cached=False))
280+
else:
281+
self.cpu_params.update(
282+
i_meip = self.interrupt[0]
283+
)
284+
285+
286+
287+
# CLINT
288+
if(CVA5.cpu_variant == "Linux"):
289+
mtime = Signal(64)
290+
msip = Signal(int(self.cpu_params["p_NUM_CORES"]))
291+
mtip = Signal(int(self.cpu_params["p_NUM_CORES"]))
292+
if(CVA5.bus_type == "wishbone"):
293+
self.clintbus = clintbus = wishbone.Interface(data_width=32, address_width=32, addressing="word")
294+
self.specials += Instance("clint_wrapper",
295+
p_NUM_CORES = int(self.cpu_params["p_NUM_CORES"]),
296+
p_AXI = 0,
297+
i_clk = ClockSignal("sys"),
298+
i_rst = ResetSignal("sys"),
299+
o_mtip = mtip,
300+
o_msip = msip,
301+
o_mtime = mtime,
302+
i_wb_cyc = clintbus.cyc,
303+
i_wb_stb = clintbus.stb,
304+
i_wb_we = clintbus.we,
305+
i_wb_adr = clintbus.adr,
306+
i_wb_dat_i = clintbus.dat_w,
307+
o_wb_dat_o = clintbus.dat_r,
308+
o_wb_ack = clintbus.ack,
309+
)
310+
else:
311+
self.clintbus = clintbus = axi.AXIInterface(data_width=32, address_width=32, id_width=4)
312+
self.specials += Instance("clint_wrapper",
313+
p_NUM_CORES = int(self.cpu_params["p_NUM_CORES"]),
314+
p_AXI = 1,
315+
i_clk = ClockSignal("sys"),
316+
i_rst = ResetSignal("sys"),
317+
o_mtip = mtip,
318+
o_msip = msip,
319+
o_mtime = mtime,
320+
i_s_axi_awvalid = clintbus.aw.valid,
321+
i_s_axi_awaddr = clintbus.aw.addr,
322+
i_s_axi_wvalid = clintbus.w.valid,
323+
i_s_axi_wdata = clintbus.w.data,
324+
i_s_axi_bready = clintbus.b.ready,
325+
i_s_axi_arvalid = clintbus.ar.valid,
326+
i_s_axi_araddr = clintbus.ar.addr,
327+
i_s_axi_rready = clintbus.r.ready,
328+
o_s_axi_awready = clintbus.aw.ready,
329+
o_s_axi_wready = clintbus.w.ready,
330+
o_s_axi_bvalid = clintbus.b.valid,
331+
o_s_axi_arready = clintbus.ar.ready,
332+
o_s_axi_rvalid = clintbus.r.valid,
333+
o_s_axi_rdata = clintbus.r.data
334+
)
335+
self.cpu_params.update(
336+
i_mtime = mtime,
337+
i_msip = msip,
338+
i_mtip = mtip
339+
)
340+
soc.bus.add_slave("clint", clintbus, region=SoCRegion(origin=self.clint_base, size=0x1_0000, cached=False))
341+
else:
342+
self.cpu_params.update(
343+
i_mtip = self.interrupt[1]
344+
)
345+

0 commit comments

Comments
 (0)