add cv32e41p

This commit is contained in:
Pascal Cotret 2022-02-14 22:43:34 +01:00
parent d506b4418e
commit d4448827ac
7 changed files with 577 additions and 0 deletions

View file

@ -0,0 +1 @@
from litex.soc.cores.cpu.cv32e41p.core import CV32E41P

View file

@ -0,0 +1,4 @@
.section .text, "ax", @progbits
.global boot_helper
boot_helper:
jr x13

View file

@ -0,0 +1,343 @@
#
# This file is part of LiteX.
#
# Copyright (c) 2020 Antmicro <www.antmicro.com>
# SPDX-License-Identifier: BSD-2-Clause
import os
import re
from migen import *
from migen.fhdl.specials import Tristate
from litex import get_data_mod
from litex.soc.interconnect import wishbone, stream
from litex.soc.interconnect.csr import *
from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32
# Variants -----------------------------------------------------------------------------------------
CPU_VARIANTS = ["standard"]
# GCC Flags ----------------------------------------------------------------------------------------
GCC_FLAGS = {
# /-------- Base ISA
# |/------- Hardware Multiply + Divide
# ||/----- Atomics
# |||/---- Compressed ISA
# ||||/--- Single-Precision Floating-Point
# |||||/-- Double-Precision Floating-Point
# imacfd
"standard": "-march=rv32imc -mabi=ilp32 ",
}
# OBI / APB / Trace Layouts ------------------------------------------------------------------------
obi_layout = [
("req", 1),
("gnt", 1),
("addr", 32),
("we", 1),
("be", 4),
("wdata", 32),
("rvalid", 1),
("rdata", 32),
]
apb_layout = [
("paddr", 32),
("pwdata", 32),
("pwrite", 1),
("psel", 1),
("penable", 1),
("prdata", 32),
("pready", 1),
("pslverr", 1),
]
# Helpers ------------------------------------------------------------------------------------------
def add_manifest_sources(platform, manifest):
basedir = get_data_mod("cpu", "cv32e41p").data_location
with open(os.path.join(basedir, manifest), 'r') as f:
for l in f:
res = re.search('\$\{DESIGN_RTL_DIR\}/(.+)', l)
if res and not re.match('//', l):
if re.match('\+incdir\+', l):
platform.add_verilog_include_path(os.path.join(basedir, 'rtl', res.group(1)))
else:
platform.add_source(os.path.join(basedir, 'rtl', res.group(1)))
# OBI <> Wishbone ----------------------------------------------------------------------------------
class OBI2Wishbone(Module):
def __init__(self, obi, wb):
addr = Signal.like(obi.addr)
be = Signal.like(obi.be)
we = Signal.like(obi.we)
wdata = Signal.like(obi.wdata)
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
# On OBI request:
If(obi.req,
# Drive Wishbone bus from OBI bus.
wb.adr.eq(obi.addr[2:32]),
wb.stb.eq( 1),
wb.dat_w.eq( obi.wdata),
wb.cyc.eq( 1),
wb.sel.eq( obi.be),
wb.we.eq( obi.we),
# Store OBI bus values.
NextValue(addr, obi.addr),
NextValue(be, obi.be),
NextValue(we, obi.we),
NextValue(wdata, obi.wdata),
# Now we need to wait Wishbone Ack.
NextState("ACK")
),
obi.gnt.eq(1), # Always ack OBI request in Idle.
)
fsm.act("ACK",
# Drive Wishbone bus from stored OBI bus values.
wb.adr.eq(addr[2:32]),
wb.stb.eq( 1),
wb.dat_w.eq( wdata),
wb.cyc.eq( 1),
wb.sel.eq( be),
wb.we.eq( we),
# On Wishbone Ack:
If(wb.ack,
# Generate OBI response.
obi.rvalid.eq(1),
obi.rdata.eq(wb.dat_r),
# Return to Idle.
NextState("IDLE")
)
)
class Wishbone2OBI(Module):
def __init__(self, wb, obi):
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
If(wb.cyc & wb.stb,
obi.req.eq(1),
NextState("ACK"),
)
)
fsm.act("ACK",
wb.ack.eq(1),
NextState("IDLE"),
)
self.comb += [
obi.we.eq(wb.we),
obi.be.eq(wb.sel),
obi.addr.eq(Cat(Signal(2), wb.adr)),
obi.wdata.eq(wb.dat_w),
wb.dat_r.eq(obi.rdata),
]
# Wishbone <> APB ----------------------------------------------------------------------------------
class Wishbone2APB(Module):
def __init__(self, wb, apb):
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
If(wb.cyc & wb.stb,
NextState("ACK"),
)
)
fsm.act("ACK",
apb.penable.eq(1),
wb.ack.eq(1),
NextState("IDLE"),
)
self.comb += [
apb.paddr.eq(Cat(Signal(2), wb.adr)),
apb.pwrite.eq(wb.we),
apb.psel.eq(1),
apb.pwdata.eq(wb.dat_w),
wb.dat_r.eq(apb.prdata),
]
# Debug Module -------------------------------------------------------------------------------------
class DebugModule(Module):
jtag_layout = [
("tck", 1),
("tms", 1),
("trst", 1),
("tdi", 1),
("tdo", 1),
]
def __init__(self, pads=None):
if pads is None:
pads = Record(self.jtag_layout)
self.pads = pads
self.dmbus = wishbone.Interface()
self.sbbus = wishbone.Interface()
dmbus = Record(obi_layout)
sbbus = Record(obi_layout)
self.submodules.sbbus_conv = OBI2Wishbone(sbbus, self.sbbus)
self.submodules.dmbus_conv = Wishbone2OBI(self.dmbus, dmbus)
self.debug_req = Signal()
self.ndmreset = Signal()
tdo_i = Signal()
tdo_o = Signal()
tdo_oe = Signal()
self.specials += Tristate(pads.tdo, tdo_o, tdo_oe, tdo_i)
self.dm_params = dict(
# Clk / Rst.
i_clk = ClockSignal("sys"),
i_rst_n = ~ResetSignal("sys"),
o_ndmreset = self.ndmreset,
o_debug_req = self.debug_req,
# Slave Bus.
i_dm_req = dmbus.req,
i_dm_we = dmbus.we,
i_dm_addr = dmbus.addr,
i_dm_be = dmbus.be,
i_dm_wdata = dmbus.wdata,
o_dm_rdata = dmbus.rdata,
# Master Bus.
o_sb_req = sbbus.req,
o_sb_addr = sbbus.addr,
o_sb_we = sbbus.we,
o_sb_wdata = sbbus.wdata,
o_sb_be = sbbus.be,
i_sb_gnt = sbbus.gnt,
i_sb_rvalid = sbbus.rvalid,
i_sb_rdata = sbbus.rdata,
# JTAG.
i_tck = pads.tck,
i_tms = pads.tms,
i_trst_n = pads.trst,
i_tdi = pads.tdi,
o_tdo = tdo_o,
o_tdo_oe = tdo_oe,
)
self.comb += [
dmbus.gnt.eq(dmbus.req),
dmbus.rvalid.eq(dmbus.gnt),
]
self.specials += Instance("dm_wrap", **self.dm_params)
# CV32E41P -----------------------------------------------------------------------------------------
class CV32E41P(CPU):
family = "riscv"
name = "cv32e41p"
human_name = "CV32E41P"
variants = CPU_VARIANTS
data_width = 32
endianness = "little"
gcc_triple = CPU_GCC_TRIPLE_RISCV32
linker_output_format = "elf32-littleriscv"
nop = "nop"
io_regions = {0x80000000: 0x80000000} # Origin, Length.
# GCC Flags.
@property
def gcc_flags(self):
flags = GCC_FLAGS[self.variant]
flags += "-D__cv32e41p__ "
return flags
def __init__(self, platform, variant="standard"):
self.platform = platform
self.variant = variant
self.reset = Signal()
self.ibus = wishbone.Interface()
self.dbus = wishbone.Interface()
self.periph_buses = [self.ibus, self.dbus]
self.memory_buses = []
self.interrupt = Signal(16)
self.interrupt_padding = Signal(16)
ibus = Record(obi_layout)
dbus = Record(obi_layout)
# OBI <> Wishbone.
self.submodules.ibus_conv = OBI2Wishbone(ibus, self.ibus)
self.submodules.dbus_conv = OBI2Wishbone(dbus, self.dbus)
self.comb += [
ibus.we.eq(0),
ibus.be.eq(1111),
]
self.cpu_params = dict(
# Clk / Rst.
i_clk_i = ClockSignal("sys"),
i_rst_ni = ~ResetSignal("sys"),
# Controls.
i_pulp_clock_en_i = 1,
i_scan_cg_en_i = 0,
i_mtvec_addr_i = 0,
i_dm_halt_addr_i = 0,
i_hart_id_i = 0,
i_dm_exception_addr_i = 0,
# IBus.
o_instr_req_o = ibus.req,
i_instr_gnt_i = ibus.gnt,
i_instr_rvalid_i = ibus.rvalid,
o_instr_addr_o = ibus.addr,
i_instr_rdata_i = ibus.rdata,
# DBus.
o_data_req_o = dbus.req,
i_data_gnt_i = dbus.gnt,
i_data_rvalid_i = dbus.rvalid,
o_data_we_o = dbus.we,
o_data_be_o = dbus.be,
o_data_addr_o = dbus.addr,
o_data_wdata_o = dbus.wdata,
i_data_rdata_i = dbus.rdata,
# APU.
i_apu_gnt_i = 0,
i_apu_rvalid_i = 0,
# IRQ.
i_irq_i = Cat(self.interrupt_padding,self.interrupt),
# Debug.
i_debug_req_i = 0,
# CPU Control.
i_fetch_enable_i = 1,
)
# Add Verilog sources.
add_manifest_sources(platform, 'cv32e41p_manifest.flist')
def add_debug_module(self, dm):
self.cpu_params.update(i_debug_req_i=dm.debug_req)
self.cpu_params.update(i_rst_ni=~(ResetSignal() | dm.ndmreset))
def set_reset_address(self, reset_address):
self.reset_address = reset_address
self.cpu_params.update(i_boot_addr_i=Signal(32, reset=reset_address))
def do_finalize(self):
assert hasattr(self, "reset_address")
self.specials += Instance("cv32e41p_core", **self.cpu_params)

View file

@ -0,0 +1,125 @@
.global main
.global isr
.global _start
_start:
j crt_init
nop
nop
nop
nop
nop
nop
nop
.balign 256
vector_table:
j trap_entry # 0 unused
j trap_entry # 1 unused
j trap_entry # 2 unused
j trap_entry # 3 software
j trap_entry # 4 unused
j trap_entry # 5 unused
j trap_entry # 6 unused
j trap_entry # 7 timer
j trap_entry # 8 unused
j trap_entry # 9 unused
j trap_entry # 10 unused
j trap_entry # 11 external
j trap_entry # 12 unused
j trap_entry # 13 unused
j trap_entry # 14 unused
j trap_entry # 15 unused
j trap_entry # 16 firq0
j trap_entry # 17 firq1
j trap_entry # 18 firq2
j trap_entry # 19 firq3
j trap_entry # 20 firq4
j trap_entry # 21 firq5
j trap_entry # 22 firq6
j trap_entry # 23 firq7
j trap_entry # 24 firq8
j trap_entry # 25 firq9
j trap_entry # 26 firq10
j trap_entry # 27 firq11
j trap_entry # 28 firq12
j trap_entry # 29 firq13
j trap_entry # 30 firq14
j trap_entry # 31 firq15
.global trap_entry
trap_entry:
sw x1, - 1*4(sp)
sw x5, - 2*4(sp)
sw x6, - 3*4(sp)
sw x7, - 4*4(sp)
sw x10, - 5*4(sp)
sw x11, - 6*4(sp)
sw x12, - 7*4(sp)
sw x13, - 8*4(sp)
sw x14, - 9*4(sp)
sw x15, -10*4(sp)
sw x16, -11*4(sp)
sw x17, -12*4(sp)
sw x28, -13*4(sp)
sw x29, -14*4(sp)
sw x30, -15*4(sp)
sw x31, -16*4(sp)
addi sp,sp,-16*4
call isr
lw x1 , 15*4(sp)
lw x5, 14*4(sp)
lw x6, 13*4(sp)
lw x7, 12*4(sp)
lw x10, 11*4(sp)
lw x11, 10*4(sp)
lw x12, 9*4(sp)
lw x13, 8*4(sp)
lw x14, 7*4(sp)
lw x15, 6*4(sp)
lw x16, 5*4(sp)
lw x17, 4*4(sp)
lw x28, 3*4(sp)
lw x29, 2*4(sp)
lw x30, 1*4(sp)
lw x31, 0*4(sp)
addi sp,sp,16*4
mret
.text
crt_init:
la sp, _fstack
la a0, vector_table
csrw mtvec, a0
data_init:
la a0, _fdata
la a1, _edata
la a2, _fdata_rom
data_loop:
beq a0,a1,data_done
lw a3,0(a2)
sw a3,0(a0)
add a0,a0,4
add a2,a2,4
j data_loop
data_done:
bss_init:
la a0, _fbss
la a1, _ebss
bss_loop:
beq a0,a1,bss_done
sw zero,0(a0)
add a0,a0,4
j bss_loop
bss_done:
li a0, 0x7FFF0880 //7FFF0880 enable timer + external interrupt + fast interrupt sources (until mstatus.MIE is set, they will never trigger an interrupt)
csrw mie,a0
j main
infinit_loop:
j infinit_loop

View file

@ -0,0 +1,11 @@
#ifndef CSR_DEFS__H
#define CSR_DEFS__H
#define CSR_MSTATUS_MIE 0x8
#define CSR_IRQ_MASK 0xBC0
#define CSR_IRQ_PENDING 0xFC0
#define CSR_DCACHE_INFO 0xCC0
#endif /* CSR_DEFS__H */

View file

@ -0,0 +1,40 @@
#ifndef __IRQ_H
#define __IRQ_H
#ifdef __cplusplus
extern "C" {
#endif
#include <system.h>
#include <generated/csr.h>
static inline unsigned int irq_getie(void)
{
return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0;
}
static inline void irq_setie(unsigned int ie)
{
if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE);
}
static inline unsigned int irq_getmask(void)
{
return 0; // FIXME
}
static inline void irq_setmask(unsigned int mask)
{
// FIXME
}
static inline unsigned int irq_pending(void)
{
return 0;// FIXME
}
#ifdef __cplusplus
}
#endif
#endif /* __IRQ_H */

View file

@ -0,0 +1,53 @@
#ifndef __SYSTEM_H
#define __SYSTEM_H
#include <csr-defs.h>
#ifdef __cplusplus
extern "C" {
#endif
__attribute__((unused)) static void flush_cpu_icache(void)
{
// FIXME
asm volatile("nop");
}
__attribute__((unused)) static void flush_cpu_dcache(void)
{
// FIXME
asm volatile("nop");
}
void flush_l2_cache(void);
void busy_wait(unsigned int ms);
void busy_wait_us(unsigned int us);
#define csrr(reg) ({ unsigned long __tmp; \
asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
__tmp; })
#define csrw(reg, val) ({ \
if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \
asm volatile ("csrw " #reg ", %0" :: "i"(val)); \
else \
asm volatile ("csrw " #reg ", %0" :: "r"(val)); })
#define csrs(reg, bit) ({ \
if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \
asm volatile ("csrrs x0, " #reg ", %0" :: "i"(bit)); \
else \
asm volatile ("csrrs x0, " #reg ", %0" :: "r"(bit)); })
#define csrc(reg, bit) ({ \
if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \
asm volatile ("csrrc x0, " #reg ", %0" :: "i"(bit)); \
else \
asm volatile ("csrrc x0, " #reg ", %0" :: "r"(bit)); })
#ifdef __cplusplus
}
#endif
#endif /* __SYSTEM_H */