CVA6: Adding RV32 support

Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
gatecat 2023-03-07 15:24:25 +01:00
parent fb1cd22ac2
commit 6a73e4c5fb
4 changed files with 206 additions and 190 deletions

View file

@ -4,6 +4,23 @@
.global smp_ap_target
.global smp_ap_ready
#if __riscv_xlen == 32
boot_helper:
// boot core saves args and jump target for ap cores:
sw a0, smp_ap_args, t1
sw a1, smp_ap_args+4, t1
sw a2, smp_ap_args+8, t1
sw a3, smp_ap_target, t1
fence w, w
// notify application cores to proceed with boot:
li t0, 1
sw t0, smp_ap_ready, t1
// boot core now also ready to boot:
jr a3
#else
boot_helper:
// boot core saves args and jump target for ap cores:
sd a0, smp_ap_args, t1
@ -16,3 +33,5 @@ boot_helper:
sd t0, smp_ap_ready, t1
// boot core now also ready to boot:
jr a3
#endif

View file

@ -19,7 +19,7 @@ from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV64
# Variants -----------------------------------------------------------------------------------------
CPU_VARIANTS = ["standard", "full"]
CPU_VARIANTS = ["standard", "standard32", "full"]
# GCC Flags ----------------------------------------------------------------------------------------
@ -31,8 +31,9 @@ GCC_FLAGS = {
# ||||/--- Single-Precision Floating-Point
# |||||/-- Double-Precision Floating-Point
# imacfd
"standard": "-march=rv64imac -mabi=lp64 ",
"full": "-march=rv64gc -mabi=lp64 ",
"standard": "-march=rv64imac -mabi=lp64 ",
"standard32": "-march=rv32imac -mabi=ilp32 ",
"full": "-march=rv64gc -mabi=lp64 ",
}
# Helpers ------------------------------------------------------------------------------------------
@ -61,13 +62,23 @@ class CVA6(CPU):
name = "cva6"
human_name = "CVA6"
variants = CPU_VARIANTS
data_width = 64
endianness = "little"
gcc_triple = CPU_GCC_TRIPLE_RISCV64
linker_output_format = "elf64-littleriscv"
nop = "nop"
io_regions = {0x8000_0000: 0x8000_0000} # Origin, Length.
@property
def linker_output_format(self):
return f"elf{self.data_width}-littleriscv"
@property
def data_width(self):
if self.variant == "standard32":
return 32
else:
return 64
# GCC Flags.
@property
def gcc_flags(self):
@ -163,8 +174,12 @@ class CVA6(CPU):
wrapper_root = os.path.join(os.path.abspath(os.path.dirname(__file__)), "cva6_wrapper")
platform.add_source(os.path.join(wrapper_root, "cva6_defines.sv"))
# TODO: use Flist.cv64a6_imafdc_sv39 and Flist.cv32a6_imac_sv0 instead
if self.variant == "standard32":
manifest = "Flist.cv32a6_imac_sv32"
else:
manifest = "Flist.cv64a6_imafdc_sv39"
add_manifest_sources(platform, os.path.join(get_data_mod("cpu", "cva6").data_location,
"core", "Flist.cv64a6_imafdc_sv39"))
"core", manifest))
# Add wrapper sources
add_manifest_sources(platform, os.path.join(wrapper_root, "Flist.cva6_wrapper"))

View file

@ -6,6 +6,128 @@
.global smp_ap_target
.global smp_ap_ready
#if __riscv_xlen == 32
_start:
j crt_init
nop
nop
nop
nop
nop
nop
nop
trap_entry:
sw x1, - 1*8(sp)
sw x5, - 2*8(sp)
sw x6, - 3*8(sp)
sw x7, - 4*8(sp)
sw x10, - 5*8(sp)
sw x11, - 6*8(sp)
sw x12, - 7*8(sp)
sw x13, - 8*8(sp)
sw x14, - 9*8(sp)
sw x15, -10*8(sp)
sw x16, -11*8(sp)
sw x17, -12*8(sp)
sw x28, -13*8(sp)
sw x29, -14*8(sp)
sw x30, -15*8(sp)
sw x31, -16*8(sp)
addi sp,sp,-16*8
call isr
lw x1 , 15*8(sp)
lw x5, 14*8(sp)
lw x6, 13*8(sp)
lw x7, 12*8(sp)
lw x10, 11*8(sp)
lw x11, 10*8(sp)
lw x12, 9*8(sp)
lw x13, 8*8(sp)
lw x14, 7*8(sp)
lw x15, 6*8(sp)
lw x16, 5*8(sp)
lw x17, 4*8(sp)
lw x28, 3*8(sp)
lw x29, 2*8(sp)
lw x30, 1*8(sp)
lw x31, 0*8(sp)
addi sp,sp,16*8
mret
.text
crt_init:
la sp, _fstack
sw zero, smp_ap_ready, t0
la t0, trap_entry
csrw mtvec, t0
smp_select_bp:
csrr a0, mhartid
beqz a0, data_init // hart 0 is bp, everyone else is ap
smp_ap_loop:
lw t0, smp_ap_ready
beqz t0, smp_ap_loop
smp_ap_boot:
fence r, r
fence.i // i$ flush
lw a0, smp_ap_args // hart ID (but next-stage loads its own)
lw a1, smp_ap_args+4 // DTB pointer (if provded by litex bios)
lw a2, smp_ap_args+8
lw a3, smp_ap_target
jr a3
smp_ap_done:
data_init:
la t0, _fdata
la t1, _edata
la t2, _fdata_rom
data_loop:
beq t0,t1,data_done
lw t3,0(t2)
sw t3,0(t0)
add t0,t0,4
add t2,t2,4
j data_loop
data_done:
bss_init:
la t0, _fbss
la t1, _ebss
bss_loop:
beq t0,t1,bss_done
sw zero,0(t0)
add t0,t0,4
j bss_loop
bss_done:
call plic_init // initialize external interrupt controller
li t0, 0x800 // external interrupt sources only (using LiteX timer);
// NOTE: must still enable mstatus.MIE!
csrw mie,t0
call main
inf_loop:
j inf_loop
.bss
.align 4
smp_ap_args:
.dword 0
.dword 0
.dword 0
.align 4
smp_ap_target:
.dword 0
.align 4
smp_ap_ready:
.dword 0
#else
_start:
j crt_init
nop
@ -123,3 +245,4 @@ smp_ap_target:
.align 8
smp_ap_ready:
.dword 0
#endif

View file

@ -87,6 +87,13 @@ module cva6_wrapper (
logic [(AxiDataWidth/8)-1:0],
logic [ AxiUserWidth-1:0])
`AXI_TYPEDEF_ALL(axi_dm_slave,
logic [ AxiAddrWidth-1:0],
logic [AxiIdWidthSlaves-1:0],
logic [ riscv::XLEN-1:0],
logic [(riscv::XLEN/8)-1:0],
logic [ AxiUserWidth-1:0])
AXI_BUS #(
.AXI_ADDR_WIDTH ( AxiAddrWidth ),
.AXI_DATA_WIDTH ( AxiDataWidth ),
@ -274,93 +281,45 @@ axi2mem #(
if (riscv::XLEN==32 ) begin
assign master_to_dm[0].aw_user = '0;
assign master_to_dm[0].w_user = '0;
assign master_to_dm[0].ar_user = '0;
axi_slave_req_t axi_dmi_slv_req;
axi_slave_resp_t axi_dmi_slv_resp;
assign master_to_dm[0].aw_id = dm_axi_m_req.aw.id;
assign master_to_dm[0].ar_id = dm_axi_m_req.ar.id;
axi_dm_slave_req_t axi_dmi_mst_req;
axi_dm_slave_resp_t axi_dmi_mst_resp;
`AXI_ASSIGN_TO_REQ(axi_dmi_slv_req, master[cva6_wrapper_pkg::Debug])
`AXI_ASSIGN_FROM_RESP(master[cva6_wrapper_pkg::Debug], axi_dmi_slv_resp)
`AXI_ASSIGN_FROM_REQ(master_to_dm[0], axi_dmi_mst_req)
`AXI_ASSIGN_TO_RESP(axi_dmi_mst_resp, master_to_dm[0])
assign master[cva6_wrapper_pkg::Debug].r_user ='0;
assign master[cva6_wrapper_pkg::Debug].b_user ='0;
xlnx_axi_dwidth_converter_dm_slave i_axi_dwidth_converter_dm_slave(
.s_axi_aclk(clk_i),
.s_axi_aresetn(ndmreset_n),
.s_axi_awid(master[cva6_wrapper_pkg::Debug].aw_id),
.s_axi_awaddr(master[cva6_wrapper_pkg::Debug].aw_addr[31:0]),
.s_axi_awlen(master[cva6_wrapper_pkg::Debug].aw_len),
.s_axi_awsize(master[cva6_wrapper_pkg::Debug].aw_size),
.s_axi_awburst(master[cva6_wrapper_pkg::Debug].aw_burst),
.s_axi_awlock(master[cva6_wrapper_pkg::Debug].aw_lock),
.s_axi_awcache(master[cva6_wrapper_pkg::Debug].aw_cache),
.s_axi_awprot(master[cva6_wrapper_pkg::Debug].aw_prot),
.s_axi_awregion(master[cva6_wrapper_pkg::Debug].aw_region),
.s_axi_awqos(master[cva6_wrapper_pkg::Debug].aw_qos),
.s_axi_awvalid(master[cva6_wrapper_pkg::Debug].aw_valid),
.s_axi_awready(master[cva6_wrapper_pkg::Debug].aw_ready),
.s_axi_wdata(master[cva6_wrapper_pkg::Debug].w_data),
.s_axi_wstrb(master[cva6_wrapper_pkg::Debug].w_strb),
.s_axi_wlast(master[cva6_wrapper_pkg::Debug].w_last),
.s_axi_wvalid(master[cva6_wrapper_pkg::Debug].w_valid),
.s_axi_wready(master[cva6_wrapper_pkg::Debug].w_ready),
.s_axi_bid(master[cva6_wrapper_pkg::Debug].b_id),
.s_axi_bresp(master[cva6_wrapper_pkg::Debug].b_resp),
.s_axi_bvalid(master[cva6_wrapper_pkg::Debug].b_valid),
.s_axi_bready(master[cva6_wrapper_pkg::Debug].b_ready),
.s_axi_arid(master[cva6_wrapper_pkg::Debug].ar_id),
.s_axi_araddr(master[cva6_wrapper_pkg::Debug].ar_addr[31:0]),
.s_axi_arlen(master[cva6_wrapper_pkg::Debug].ar_len),
.s_axi_arsize(master[cva6_wrapper_pkg::Debug].ar_size),
.s_axi_arburst(master[cva6_wrapper_pkg::Debug].ar_burst),
.s_axi_arlock(master[cva6_wrapper_pkg::Debug].ar_lock),
.s_axi_arcache(master[cva6_wrapper_pkg::Debug].ar_cache),
.s_axi_arprot(master[cva6_wrapper_pkg::Debug].ar_prot),
.s_axi_arregion(master[cva6_wrapper_pkg::Debug].ar_region),
.s_axi_arqos(master[cva6_wrapper_pkg::Debug].ar_qos),
.s_axi_arvalid(master[cva6_wrapper_pkg::Debug].ar_valid),
.s_axi_arready(master[cva6_wrapper_pkg::Debug].ar_ready),
.s_axi_rid(master[cva6_wrapper_pkg::Debug].r_id),
.s_axi_rdata(master[cva6_wrapper_pkg::Debug].r_data),
.s_axi_rresp(master[cva6_wrapper_pkg::Debug].r_resp),
.s_axi_rlast(master[cva6_wrapper_pkg::Debug].r_last),
.s_axi_rvalid(master[cva6_wrapper_pkg::Debug].r_valid),
.s_axi_rready(master[cva6_wrapper_pkg::Debug].r_ready),
.m_axi_awaddr(master_to_dm[0].aw_addr),
.m_axi_awlen(master_to_dm[0].aw_len),
.m_axi_awsize(master_to_dm[0].aw_size),
.m_axi_awburst(master_to_dm[0].aw_burst),
.m_axi_awlock(master_to_dm[0].aw_lock),
.m_axi_awcache(master_to_dm[0].aw_cache),
.m_axi_awprot(master_to_dm[0].aw_prot),
.m_axi_awregion(master_to_dm[0].aw_region),
.m_axi_awqos(master_to_dm[0].aw_qos),
.m_axi_awvalid(master_to_dm[0].aw_valid),
.m_axi_awready(master_to_dm[0].aw_ready),
.m_axi_wdata(master_to_dm[0].w_data ),
.m_axi_wstrb(master_to_dm[0].w_strb),
.m_axi_wlast(master_to_dm[0].w_last),
.m_axi_wvalid(master_to_dm[0].w_valid),
.m_axi_wready(master_to_dm[0].w_ready),
.m_axi_bresp(master_to_dm[0].b_resp),
.m_axi_bvalid(master_to_dm[0].b_valid),
.m_axi_bready(master_to_dm[0].b_ready),
.m_axi_araddr(master_to_dm[0].ar_addr),
.m_axi_arlen(master_to_dm[0].ar_len),
.m_axi_arsize(master_to_dm[0].ar_size),
.m_axi_arburst(master_to_dm[0].ar_burst),
.m_axi_arlock(master_to_dm[0].ar_lock),
.m_axi_arcache(master_to_dm[0].ar_cache),
.m_axi_arprot(master_to_dm[0].ar_prot),
.m_axi_arregion(master_to_dm[0].ar_region),
.m_axi_arqos(master_to_dm[0].ar_qos),
.m_axi_arvalid(master_to_dm[0].ar_valid),
.m_axi_arready(master_to_dm[0].ar_ready),
.m_axi_rdata(master_to_dm[0].r_data),
.m_axi_rresp(master_to_dm[0].r_resp),
.m_axi_rlast(master_to_dm[0].r_last),
.m_axi_rvalid(master_to_dm[0].r_valid),
.m_axi_rready(master_to_dm[0].r_ready)
axi_dw_converter #(
.AxiMaxReads(1),
.AxiSlvPortDataWidth(64),
.AxiMstPortDataWidth(32),
.AxiAddrWidth(AxiAddrWidth),
.AxiIdWidth(5),
.aw_chan_t(ariane_axi::aw_chan_t),
.slv_w_chan_t(axi_slave_w_chan_t),
.mst_w_chan_t(axi_dm_slave_w_chan_t),
.b_chan_t(axi_slave_b_chan_t),
.ar_chan_t(axi_slave_ar_chan_t),
.mst_r_chan_t(axi_dm_slave_r_chan_t),
.slv_r_chan_t(axi_slave_r_chan_t),
.axi_slv_req_t(axi_slave_req_t),
.axi_slv_resp_t(axi_slave_resp_t),
.axi_mst_req_t(axi_dm_slave_req_t),
.axi_mst_resp_t(axi_dm_slave_resp_t)
) i_downsizer_dm_slave (
.clk_i(clk_i),
.rst_ni(ndmreset_n),
.slv_req_i(axi_dmi_slv_req),
.slv_resp_o(axi_dmi_slv_resp),
.mst_req_o(axi_dmi_mst_req),
.mst_resp_i(axi_dmi_mst_resp)
);
end else begin
@ -455,108 +414,8 @@ axi_adapter #(
.axi_resp_i ( dm_axi_m_resp )
);
if (riscv::XLEN==32 ) begin
logic [31 : 0] dm_master_m_awaddr;
logic [31 : 0] dm_master_m_araddr;
assign slave[1].aw_addr = {32'h0000_0000, dm_master_m_awaddr};
assign slave[1].ar_addr = {32'h0000_0000, dm_master_m_araddr};
logic [31 : 0] dm_master_s_rdata;
assign dm_axi_m_resp.r.data = {32'h0000_0000, dm_master_s_rdata};
assign slave[1].aw_user = '0;
assign slave[1].w_user = '0;
assign slave[1].ar_user = '0;
assign slave[1].aw_id = dm_axi_m_req.aw.id;
assign slave[1].ar_id = dm_axi_m_req.ar.id;
assign slave[1].aw_atop = dm_axi_m_req.aw.atop;
xlnx_axi_dwidth_converter_dm_master i_axi_dwidth_converter_dm_master(
.s_axi_aclk(clk_i),
.s_axi_aresetn(ndmreset_n),
.s_axi_awid(dm_axi_m_req.aw.id),
.s_axi_awaddr(dm_axi_m_req.aw.addr[31:0]),
.s_axi_awlen(dm_axi_m_req.aw.len),
.s_axi_awsize(dm_axi_m_req.aw.size),
.s_axi_awburst(dm_axi_m_req.aw.burst),
.s_axi_awlock(dm_axi_m_req.aw.lock),
.s_axi_awcache(dm_axi_m_req.aw.cache),
.s_axi_awprot(dm_axi_m_req.aw.prot),
.s_axi_awregion(dm_axi_m_req.aw.region),
.s_axi_awqos(dm_axi_m_req.aw.qos),
.s_axi_awvalid(dm_axi_m_req.aw_valid),
.s_axi_awready(dm_axi_m_resp.aw_ready),
.s_axi_wdata(dm_axi_m_req.w.data[31:0]),
.s_axi_wstrb(dm_axi_m_req.w.strb[3:0]),
.s_axi_wlast(dm_axi_m_req.w.last),
.s_axi_wvalid(dm_axi_m_req.w_valid),
.s_axi_wready(dm_axi_m_resp.w_ready),
.s_axi_bid(dm_axi_m_resp.b.id),
.s_axi_bresp(dm_axi_m_resp.b.resp),
.s_axi_bvalid(dm_axi_m_resp.b_valid),
.s_axi_bready(dm_axi_m_req.b_ready),
.s_axi_arid(dm_axi_m_req.ar.id),
.s_axi_araddr(dm_axi_m_req.ar.addr[31:0]),
.s_axi_arlen(dm_axi_m_req.ar.len),
.s_axi_arsize(dm_axi_m_req.ar.size),
.s_axi_arburst(dm_axi_m_req.ar.burst),
.s_axi_arlock(dm_axi_m_req.ar.lock),
.s_axi_arcache(dm_axi_m_req.ar.cache),
.s_axi_arprot(dm_axi_m_req.ar.prot),
.s_axi_arregion(dm_axi_m_req.ar.region),
.s_axi_arqos(dm_axi_m_req.ar.qos),
.s_axi_arvalid(dm_axi_m_req.ar_valid),
.s_axi_arready(dm_axi_m_resp.ar_ready),
.s_axi_rid(dm_axi_m_resp.r.id),
.s_axi_rdata(dm_master_s_rdata),
.s_axi_rresp(dm_axi_m_resp.r.resp),
.s_axi_rlast(dm_axi_m_resp.r.last),
.s_axi_rvalid(dm_axi_m_resp.r_valid),
.s_axi_rready(dm_axi_m_req.r_ready),
.m_axi_awaddr(dm_master_m_awaddr),
.m_axi_awlen(slave[1].aw_len),
.m_axi_awsize(slave[1].aw_size),
.m_axi_awburst(slave[1].aw_burst),
.m_axi_awlock(slave[1].aw_lock),
.m_axi_awcache(slave[1].aw_cache),
.m_axi_awprot(slave[1].aw_prot),
.m_axi_awregion(slave[1].aw_region),
.m_axi_awqos(slave[1].aw_qos),
.m_axi_awvalid(slave[1].aw_valid),
.m_axi_awready(slave[1].aw_ready),
.m_axi_wdata(slave[1].w_data ),
.m_axi_wstrb(slave[1].w_strb),
.m_axi_wlast(slave[1].w_last),
.m_axi_wvalid(slave[1].w_valid),
.m_axi_wready(slave[1].w_ready),
.m_axi_bresp(slave[1].b_resp),
.m_axi_bvalid(slave[1].b_valid),
.m_axi_bready(slave[1].b_ready),
.m_axi_araddr(dm_master_m_araddr),
.m_axi_arlen(slave[1].ar_len),
.m_axi_arsize(slave[1].ar_size),
.m_axi_arburst(slave[1].ar_burst),
.m_axi_arlock(slave[1].ar_lock),
.m_axi_arcache(slave[1].ar_cache),
.m_axi_arprot(slave[1].ar_prot),
.m_axi_arregion(slave[1].ar_region),
.m_axi_arqos(slave[1].ar_qos),
.m_axi_arvalid(slave[1].ar_valid),
.m_axi_arready(slave[1].ar_ready),
.m_axi_rdata(slave[1].r_data),
.m_axi_rresp(slave[1].r_resp),
.m_axi_rlast(slave[1].r_last),
.m_axi_rvalid(slave[1].r_valid),
.m_axi_rready(slave[1].r_ready)
);
end else begin
`AXI_ASSIGN_FROM_REQ(slave[1], dm_axi_m_req)
`AXI_ASSIGN_TO_RESP(dm_axi_m_resp, slave[1])
end
`AXI_ASSIGN_FROM_REQ(slave[1], dm_axi_m_req)
`AXI_ASSIGN_TO_RESP(dm_axi_m_resp, slave[1])
// ---------------
// Core