Merge pull request #535 from antmicro/arty-cv32e40p

Add support for the CV32E40P RISC-V CPU
This commit is contained in:
enjoy-digital 2020-05-22 13:44:10 +02:00 committed by GitHub
commit 4c4cd335de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 675 additions and 0 deletions

View File

@ -57,6 +57,7 @@ from litex.soc.cores.cpu.minerva import Minerva
from litex.soc.cores.cpu.vexriscv import VexRiscv
from litex.soc.cores.cpu.rocket import RocketRV64
from litex.soc.cores.cpu.blackparrot import BlackParrotRV64
from litex.soc.cores.cpu.cv32e40p import CV32E40P
CPUS = {
# None
@ -76,6 +77,7 @@ CPUS = {
"picorv32" : PicoRV32,
"minerva" : Minerva,
"vexriscv" : VexRiscv,
"cv32e40p" : CV32E40P,
# RISC-V 64-bit
"rocket" : RocketRV64,

View File

@ -0,0 +1 @@
from litex.soc.cores.cpu.cv32e40p.core import CV32E40P

View File

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

View File

@ -0,0 +1,417 @@
#!/usr/bin/env python3
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
CPU_VARIANTS = ["standard", "full"]
GCC_FLAGS = {
# /-------- Base ISA
# |/------- Hardware Multiply + Divide
# ||/----- Atomics
# |||/---- Compressed ISA
# ||||/--- Single-Precision Floating-Point
# |||||/-- Double-Precision Floating-Point
# imacfd
"standard": "-march=rv32imc -mabi=ilp32 ",
"full": "-march=rv32imfc -mabi=ilp32 ",
}
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),
]
trace_layout = [
("ivalid", 1),
("iexception", 1),
("interrupt", 1),
("cause", 5),
("tval", 32),
("priv", 3),
("iaddr", 32),
("instr", 32),
("compressed", 1),
]
def add_manifest_sources(platform, manifest):
basedir = get_data_mod("cpu", "cv32e40p").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)))
class OBI2Wishbone(Module):
def __init__(self, obi, wb):
dat_r_d = Signal().like(wb.dat_r)
addr_d = Signal().like(obi.addr)
ack_d = Signal()
self.sync += [
dat_r_d.eq(wb.dat_r),
ack_d.eq(wb.ack),
addr_d.eq(obi.addr),
]
self.comb += [
wb.adr.eq(obi.addr[2:32]),
wb.stb.eq(obi.req & (~ack_d)),
wb.dat_w.eq(obi.wdata),
wb.cyc.eq(obi.req),
wb.sel.eq(obi.be),
wb.we.eq(obi.we),
obi.gnt.eq(wb.ack & (addr_d == obi.addr)),
obi.rvalid.eq(ack_d),
obi.rdata.eq(dat_r_d),
]
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(0, 0, wb.adr)),
obi.wdata.eq(wb.dat_w),
wb.dat_r.eq(obi.rdata),
]
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(0, 0, wb.adr)),
apb.pwrite.eq(wb.we),
apb.psel.eq(1),
apb.pwdata.eq(wb.dat_w),
wb.dat_r.eq(apb.prdata),
]
class TraceCollector(Module, AutoCSR):
def __init__(self, trace_depth=16384):
self.bus = bus = wishbone.Interface()
self.sink = sink = stream.Endpoint([("data", 32)])
clear = Signal()
enable = Signal()
pointer = Signal(32)
self._enable = CSRStorage()
self._clear = CSRStorage()
self._pointer = CSRStatus(32)
mem = Memory(32, trace_depth)
rd_port = mem.get_port()
wr_port = mem.get_port(write_capable=True)
self.specials += rd_port, wr_port, mem
self.sync += [
# wishbone
bus.ack.eq(0),
If(bus.cyc & bus.stb & ~bus.ack, bus.ack.eq(1)),
# trace core
If(clear, pointer.eq(0)).Else(
If(sink.ready & sink.valid, pointer.eq(pointer+1)),
),
]
self.comb += [
# wishbone
rd_port.adr.eq(bus.adr),
bus.dat_r.eq(rd_port.dat_r),
# trace core
wr_port.adr.eq(pointer),
wr_port.dat_w.eq(sink.data),
wr_port.we.eq(sink.ready & sink.valid),
sink.ready.eq(enable & (pointer < trace_depth)),
# csrs
enable.eq(self._enable.storage),
clear.eq(self._clear.storage),
self._pointer.status.eq(pointer),
]
class TraceDebugger(Module):
def __init__(self):
self.bus = wishbone.Interface()
self.source = source = stream.Endpoint([("data", 32)])
self.trace_if = trace_if = Record(trace_layout)
apb = Record(apb_layout)
self.submodules.bus_conv = Wishbone2APB(self.bus, apb)
self.trace_params = dict(
i_clk_i=ClockSignal(),
i_rst_ni=~ResetSignal(),
i_test_mode_i=0,
# cpu interface
i_ivalid_i=trace_if.ivalid,
i_iexception_i=trace_if.iexception,
i_interrupt_i=trace_if.interrupt,
i_cause_i=trace_if.cause,
i_tval_i=trace_if.tval,
i_priv_i=trace_if.priv,
i_iaddr_i=trace_if.iaddr,
i_instr_i=trace_if.instr,
i_compressed_i=trace_if.compressed,
# apb interface
i_paddr_i=apb.paddr,
i_pwdata_i=apb.pwdata,
i_pwrite_i=apb.pwrite,
i_psel_i=apb.psel,
i_penable_i=apb.penable,
o_prdata_o=apb.prdata,
o_pready_o=apb.pready,
o_pslverr_o=apb.pslverr,
# data output
o_packet_word_o=source.data,
o_packet_word_valid_o=source.valid,
i_grant_i=source.ready,
)
self.specials += Instance("trace_debugger", **self.trace_params)
@staticmethod
def add_sources(platform):
add_manifest_sources(platform, "cv32e40p_trace_manifest.flist")
class DebugModule(Module):
jtag_layout = [
("tck", 1),
("tms", 1),
("trst", 1),
("tdi", 1),
("tdo", 1),
]
def __init__(self, pads=None):
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()
if pads is None:
pads = Record(self.jtag_layout)
self.pads = pads
self.specials += Tristate(pads.tdo, tdo_o, tdo_oe, tdo_i)
self.dm_params = dict(
i_clk=ClockSignal(),
i_rst_n=~ResetSignal(),
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)
@staticmethod
def add_sources(platform):
add_manifest_sources(platform, "cv32e40p_dm_manifest.flist")
class CV32E40P(CPU):
name = "cv32e40p"
human_name = "CV32E40P"
data_width = 32
endianness = "little"
gcc_triple = CPU_GCC_TRIPLE_RISCV32
linker_output_format = "elf32-littleriscv"
nop = "nop"
io_regions = {0x80000000: 0x80000000} # origin, length
has_fpu = ["full"]
@property
def gcc_flags(self):
flags = GCC_FLAGS[self.variant]
flags += "-D__cv32e40p__ "
return flags
def __init__(self, platform, variant="standard"):
assert variant in CPU_VARIANTS, "Unsupported variant %s" % variant
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(15)
ibus = Record(obi_layout)
dbus = Record(obi_layout)
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(
i_clk_i=ClockSignal(),
i_rst_ni=~ResetSignal(),
i_clock_en_i=1,
i_test_en_i=0,
i_fregfile_disable_i=0,
i_core_id_i=0,
i_cluster_id_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_master_gnt_i=0,
i_apu_master_valid_i=0,
# irq
i_irq_sec_i=0,
i_irq_software_i=0,
i_irq_external_i=0,
i_irq_fast_i=self.interrupt,
i_irq_nmi_i=0,
i_irq_fastx_i=0,
# debug
i_debug_req_i=0,
# cpu control
i_fetch_enable_i=1,
)
# add verilog sources
add_manifest_sources(platform, 'cv32e40p_manifest.flist')
if variant in self.has_fpu:
self.cpu_params.update(p_FPU=1)
add_manifest_sources(platform, 'cv32e40p_fpu_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 add_trace_core(self, trace):
trace_if = trace.trace_if
self.cpu_params.update(
o_ivalid_o=trace_if.ivalid,
o_iexception_o=trace_if.iexception,
o_interrupt_o=trace_if.interrupt,
o_cause_o=trace_if.cause,
o_tval_o=trace_if.tval,
o_priv_o=trace_if.priv,
o_iaddr_o=trace_if.iaddr,
o_instr_o=trace_if.instr,
o_compressed_o=trace_if.compressed,
)
def set_reset_address(self, reset_address):
assert not hasattr(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("riscv_core", **self.cpu_params)

View File

@ -0,0 +1,112 @@
.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 unused
.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 + 4
la a0, vector_table
csrw mtvec, a0
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,52 @@
#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);
#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 */

View File

@ -62,6 +62,41 @@ void isr(void)
*((unsigned int *)PLIC_CLAIM) = claim;
}
}
#elif defined(__cv32e40p__)
#define FIRQ_OFFSET 16
#define IRQ_MASK 0x7FFFFFFF
#define INVINST 2
#define ECALL 11
#define RISCV_TEST
void isr(void)
{
unsigned int cause = csrr(mcause) & IRQ_MASK;
if (csrr(mcause) & 0x80000000) {
#ifndef UART_POLLING
if (cause == (UART_INTERRUPT+FIRQ_OFFSET)){
uart_isr();
}
#endif
} else {
#ifdef RISCV_TEST
int gp;
asm volatile ("mv %0, gp" : "=r"(gp));
printf("E %d\n", cause);
if (cause == INVINST) {
printf("Inv Instr\n");
for(;;);
}
if (cause == ECALL) {
printf("Ecall (gp: %d)\n", gp);
csrw(mepc, csrr(mepc)+4);
}
#endif
}
}
#else
void isr(void)
{

View File

@ -50,6 +50,7 @@ repos = [
("pythondata-cpu-minerva", ("https://github.com/litex-hub/", False, True, None)),
("pythondata-cpu-microwatt", ("https://github.com/litex-hub/", False, True, 0xa7859fb)),
("pythondata-cpu-blackparrot", ("https://github.com/litex-hub/", False, True, None)),
("pythondata-cpu-cv32e40p", ("https://github.com/litex-hub/", False, True, None)),
]
repos = OrderedDict(repos)