cores/cpu: add cv32e40p

This commit is contained in:
Piotr Binkowski 2020-05-19 17:05:25 +02:00
parent ca8cb83424
commit 2d6ee5aaf2
8 changed files with 639 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.vexriscv import VexRiscv
from litex.soc.cores.cpu.rocket import RocketRV64 from litex.soc.cores.cpu.rocket import RocketRV64
from litex.soc.cores.cpu.blackparrot import BlackParrotRV64 from litex.soc.cores.cpu.blackparrot import BlackParrotRV64
from litex.soc.cores.cpu.cv32e40p import CV32E40P
CPUS = { CPUS = {
# None # None
@ -76,6 +77,7 @@ CPUS = {
"picorv32" : PicoRV32, "picorv32" : PicoRV32,
"minerva" : Minerva, "minerva" : Minerva,
"vexriscv" : VexRiscv, "vexriscv" : VexRiscv,
"cv32e40p" : CV32E40P,
# RISC-V 64-bit # RISC-V 64-bit
"rocket" : RocketRV64, "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 */