mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
add cv32e41p
This commit is contained in:
parent
d506b4418e
commit
d4448827ac
7 changed files with 577 additions and 0 deletions
1
litex/soc/cores/cpu/cv32e41p/__init__.py
Normal file
1
litex/soc/cores/cpu/cv32e41p/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
from litex.soc.cores.cpu.cv32e41p.core import CV32E41P
|
4
litex/soc/cores/cpu/cv32e41p/boot-helper.S
Normal file
4
litex/soc/cores/cpu/cv32e41p/boot-helper.S
Normal file
|
@ -0,0 +1,4 @@
|
|||
.section .text, "ax", @progbits
|
||||
.global boot_helper
|
||||
boot_helper:
|
||||
jr x13
|
343
litex/soc/cores/cpu/cv32e41p/core.py
Normal file
343
litex/soc/cores/cpu/cv32e41p/core.py
Normal 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)
|
125
litex/soc/cores/cpu/cv32e41p/crt0.S
Normal file
125
litex/soc/cores/cpu/cv32e41p/crt0.S
Normal 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
|
11
litex/soc/cores/cpu/cv32e41p/csr-defs.h
Normal file
11
litex/soc/cores/cpu/cv32e41p/csr-defs.h
Normal 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 */
|
40
litex/soc/cores/cpu/cv32e41p/irq.h
Normal file
40
litex/soc/cores/cpu/cv32e41p/irq.h
Normal 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 */
|
53
litex/soc/cores/cpu/cv32e41p/system.h
Normal file
53
litex/soc/cores/cpu/cv32e41p/system.h
Normal 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 */
|
Loading…
Reference in a new issue