Merge pull request #2098 from enjoy-digital/urv
Add initial uRV CPU support.
This commit is contained in:
commit
c1225736a8
|
@ -6,7 +6,8 @@
|
||||||
[> Added
|
[> Added
|
||||||
--------
|
--------
|
||||||
- cpu/zynqmp : Added SGMII support via PL andoptional PTP (#2095).
|
- cpu/zynqmp : Added SGMII support via PL andoptional PTP (#2095).
|
||||||
- liteeth/phy : Improved 1000BaseX/2500BaseX PCS/PHYs (https://github.com/enjoy-digital/liteeth/pull/174).
|
- liteeth/phy : Improved 1000BaseX/2500BaseX PCS/PHYs (https://github.com/enjoy-digital/liteeth/pull/174).*
|
||||||
|
- cpu/urv : Added uRV CPU support (RISC-V CPU use in White Rabbit project).
|
||||||
|
|
||||||
[> Changed
|
[> Changed
|
||||||
----------
|
----------
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
from litex.soc.cores.cpu.urv.core import uRV
|
|
@ -0,0 +1,4 @@
|
||||||
|
.section .text, "ax", @progbits
|
||||||
|
.global boot_helper
|
||||||
|
boot_helper:
|
||||||
|
jr x13
|
|
@ -0,0 +1,238 @@
|
||||||
|
#
|
||||||
|
# This file is part of LiteX.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2024 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from migen import *
|
||||||
|
|
||||||
|
from litex.gen import *
|
||||||
|
|
||||||
|
from litex.soc.interconnect import stream
|
||||||
|
|
||||||
|
from litex.soc.interconnect import wishbone
|
||||||
|
from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32
|
||||||
|
|
||||||
|
# Variants -----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CPU_VARIANTS = {
|
||||||
|
"standard": "urv",
|
||||||
|
}
|
||||||
|
|
||||||
|
# GCC Flags ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
GCC_FLAGS = {
|
||||||
|
# /------------ Base ISA
|
||||||
|
# | /------- Hardware Multiply + Divide
|
||||||
|
# | |/----- Atomics
|
||||||
|
# | ||/---- Compressed ISA
|
||||||
|
# | |||/--- Single-Precision Floating-Point
|
||||||
|
# | ||||/-- Double-Precision Floating-Point
|
||||||
|
# i macfd
|
||||||
|
"standard": "-march=rv32i2p0_m -mabi=ilp32",
|
||||||
|
}
|
||||||
|
|
||||||
|
# uRV ------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class uRV(CPU):
|
||||||
|
category = "softcore"
|
||||||
|
family = "riscv"
|
||||||
|
name = "urv"
|
||||||
|
human_name = "urv"
|
||||||
|
variants = CPU_VARIANTS
|
||||||
|
data_width = 32
|
||||||
|
endianness = "little"
|
||||||
|
gcc_triple = CPU_GCC_TRIPLE_RISCV32
|
||||||
|
linker_output_format = "elf32-littleriscv"
|
||||||
|
nop = "nop"
|
||||||
|
io_regions = {0x8000_0000: 0x8000_0000} # Origin, Length.
|
||||||
|
|
||||||
|
# GCC Flags.
|
||||||
|
@property
|
||||||
|
def gcc_flags(self):
|
||||||
|
flags = GCC_FLAGS[self.variant]
|
||||||
|
flags += " -D__urv__ "
|
||||||
|
return flags
|
||||||
|
|
||||||
|
def __init__(self, platform, variant="standard"):
|
||||||
|
self.platform = platform
|
||||||
|
self.variant = variant
|
||||||
|
self.human_name = f"uRV-{variant.upper()}"
|
||||||
|
self.reset = Signal()
|
||||||
|
self.ibus = ibus = wishbone.Interface(data_width=32, address_width=32, addressing="byte")
|
||||||
|
self.dbus = dbus = wishbone.Interface(data_width=32, address_width=32, addressing="byte")
|
||||||
|
self.periph_buses = [ibus, dbus] # Peripheral buses (Connected to main SoC's bus).
|
||||||
|
self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM).
|
||||||
|
|
||||||
|
# uRV Signals.
|
||||||
|
# ------------
|
||||||
|
im_addr = Signal(32)
|
||||||
|
im_rd = Signal()
|
||||||
|
im_data = Signal(32)
|
||||||
|
im_valid = Signal()
|
||||||
|
|
||||||
|
dm_addr = Signal(32)
|
||||||
|
dm_data_s = Signal(32)
|
||||||
|
dm_data_l = Signal(32)
|
||||||
|
dm_data_select = Signal(4)
|
||||||
|
dm_store = Signal()
|
||||||
|
dm_load = Signal()
|
||||||
|
dm_load_done = Signal()
|
||||||
|
dm_store_done = Signal()
|
||||||
|
|
||||||
|
# uRV Instance.
|
||||||
|
# -------------
|
||||||
|
self.cpu_params = dict(
|
||||||
|
# Parameters.
|
||||||
|
p_g_timer_frequency = 1000, # FIXME.
|
||||||
|
p_g_clock_frequency = 100000000, # FIXME.
|
||||||
|
p_g_with_hw_div = 1,
|
||||||
|
p_g_with_hw_mulh = 1,
|
||||||
|
p_g_with_hw_mul = 1,
|
||||||
|
p_g_with_hw_debug = 0,
|
||||||
|
p_g_with_ecc = 0,
|
||||||
|
p_g_with_compressed_insns = 0,
|
||||||
|
|
||||||
|
# Clk / Rst.
|
||||||
|
i_clk_i = ClockSignal("sys"),
|
||||||
|
i_rst_i = ResetSignal("sys") | self.reset,
|
||||||
|
|
||||||
|
# Instruction Mem Bus.
|
||||||
|
o_im_addr_o = im_addr,
|
||||||
|
o_im_rd_o = im_rd,
|
||||||
|
i_im_data_i = im_data,
|
||||||
|
i_im_valid_i = im_valid,
|
||||||
|
|
||||||
|
# Data Mem Bus.
|
||||||
|
o_dm_addr_o = dm_addr,
|
||||||
|
o_dm_data_s_o = dm_data_s,
|
||||||
|
i_dm_data_l_i = dm_data_l,
|
||||||
|
o_dm_data_select_o = dm_data_select,
|
||||||
|
|
||||||
|
o_dm_store_o = dm_store,
|
||||||
|
o_dm_load_o = dm_load,
|
||||||
|
i_dm_load_done_i = dm_load_done,
|
||||||
|
i_dm_store_done_i = dm_store_done,
|
||||||
|
)
|
||||||
|
|
||||||
|
# uRV Instruction Bus.
|
||||||
|
# --------------------
|
||||||
|
if True:
|
||||||
|
from litex.soc.integration.common import get_mem_data
|
||||||
|
self.rom = Memory(32, depth=131072//4)
|
||||||
|
self.rom_port = self.rom.get_port()
|
||||||
|
|
||||||
|
self.sync += im_valid.eq(1),
|
||||||
|
self.comb += [
|
||||||
|
self.rom_port.adr.eq(im_addr[2:]),
|
||||||
|
im_data.eq(self.rom_port.dat_r),
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
# FIXME: Try to implement im_bus -> Wishbone correctly (if possible).
|
||||||
|
im_addr_d = Signal(32, reset=0xffffffff)
|
||||||
|
self.sync += im_addr_d.eq(im_addr)
|
||||||
|
self.i_fsm = i_fsm = FSM(reset_state="IDLE")
|
||||||
|
i_fsm.act("IDLE",
|
||||||
|
If(im_addr != im_addr_d,
|
||||||
|
NextValue(im_valid, 0),
|
||||||
|
NextState("READ")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
i_fsm.act("READ",
|
||||||
|
ibus.stb.eq(1),
|
||||||
|
ibus.cyc.eq(1),
|
||||||
|
ibus.we.eq(0),
|
||||||
|
ibus.adr.eq(im_addr),
|
||||||
|
ibus.sel.eq(0b1111),
|
||||||
|
If(ibus.ack,
|
||||||
|
NextValue(im_valid, 1),
|
||||||
|
NextValue(im_data, ibus.dat_r),
|
||||||
|
NextState("IDLE")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# uRV Data Bus.
|
||||||
|
# -------------
|
||||||
|
self.dm_fifo = dm_fifo = stream.SyncFIFO(
|
||||||
|
layout = [("addr", 32), ("we", 1), ("data", 32), ("sel", 4)],
|
||||||
|
depth = 16,
|
||||||
|
)
|
||||||
|
self.comb += [
|
||||||
|
dm_fifo.sink.valid.eq(dm_store | dm_load),
|
||||||
|
dm_fifo.sink.we.eq(dm_store),
|
||||||
|
dm_fifo.sink.addr.eq(dm_addr),
|
||||||
|
dm_fifo.sink.data.eq(dm_data_s),
|
||||||
|
dm_fifo.sink.sel.eq(dm_data_select),
|
||||||
|
]
|
||||||
|
self.dm_fsm = dm_fsm = FSM(reset_state="IDLE")
|
||||||
|
dm_fsm.act("IDLE",
|
||||||
|
If(dm_fifo.source.valid,
|
||||||
|
If(dm_fifo.source.we,
|
||||||
|
NextState("WRITE")
|
||||||
|
).Else(
|
||||||
|
NextState("READ")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
dm_fsm.act("WRITE",
|
||||||
|
dbus.stb.eq(1),
|
||||||
|
dbus.cyc.eq(1),
|
||||||
|
dbus.we.eq(1),
|
||||||
|
dbus.adr.eq(dm_fifo.source.addr),
|
||||||
|
dbus.sel.eq(dm_fifo.source.sel),
|
||||||
|
dbus.dat_w.eq(dm_fifo.source.data),
|
||||||
|
If(dbus.ack,
|
||||||
|
dm_fifo.source.ready.eq(1),
|
||||||
|
dm_store_done.eq(1),
|
||||||
|
NextState("IDLE")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
dm_fsm.act("READ",
|
||||||
|
dbus.stb.eq(1),
|
||||||
|
dbus.cyc.eq(1),
|
||||||
|
dbus.we.eq(0),
|
||||||
|
dbus.adr.eq(dm_fifo.source.addr),
|
||||||
|
dbus.sel.eq(dm_fifo.source.sel),
|
||||||
|
If(dbus.ack,
|
||||||
|
dm_fifo.source.ready.eq(1),
|
||||||
|
dm_load_done.eq(1),
|
||||||
|
dm_data_l.eq(dbus.dat_r),
|
||||||
|
NextState("IDLE")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add Verilog sources.
|
||||||
|
# --------------------
|
||||||
|
self.add_sources(platform, variant)
|
||||||
|
|
||||||
|
def set_reset_address(self, reset_address):
|
||||||
|
assert reset_address == 0
|
||||||
|
self.reset_address = reset_address
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def add_sources(platform, variant):
|
||||||
|
if not os.path.exists("urv-core"):
|
||||||
|
os.system(f"git clone https://ohwr.org/project/urv-core/")
|
||||||
|
vdir = "urv-core/rtl"
|
||||||
|
platform.add_verilog_include_path("urv-core/rtl")
|
||||||
|
platform.add_sources([
|
||||||
|
"urv-core/rtl/urv_cpu.v",
|
||||||
|
"urv-core/rtl/urv_exec.v",
|
||||||
|
"urv-core/rtl/urv_fetch.v",
|
||||||
|
"urv-core/rtl/urv_decode.v",
|
||||||
|
"urv-core/rtl/urv_regfile.v",
|
||||||
|
"urv-core/rtl/urv_writeback.v",
|
||||||
|
"urv-core/rtl/urv_shifter.v",
|
||||||
|
"urv-core/rtl/urv_multiply.v",
|
||||||
|
"urv-core/rtl/urv_divide.v",
|
||||||
|
"urv-core/rtl/urv_csr.v",
|
||||||
|
"urv-core/rtl/urv_timer.v",
|
||||||
|
"urv-core/rtl/urv_exceptions.v",
|
||||||
|
"urv-core/rtl/urv_iram.v",
|
||||||
|
"urv-core/rtl/urv_ecc.v",
|
||||||
|
])
|
||||||
|
|
||||||
|
def do_finalize(self):
|
||||||
|
self.specials += Instance("urv_cpu", **self.cpu_params)
|
|
@ -0,0 +1,75 @@
|
||||||
|
#define MIE_MEIE 0x800
|
||||||
|
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
j reset_vector
|
||||||
|
|
||||||
|
reset_vector:
|
||||||
|
la sp, _fstack
|
||||||
|
la t0, trap_vector
|
||||||
|
csrw mtvec, t0
|
||||||
|
|
||||||
|
// initialize .data
|
||||||
|
la t0, _fdata
|
||||||
|
la t1, _edata
|
||||||
|
la t2, _fdata_rom
|
||||||
|
1: beq t0, t1, 2f
|
||||||
|
lw t3, 0(t2)
|
||||||
|
sw t3, 0(t0)
|
||||||
|
addi t0, t0, 4
|
||||||
|
addi t2, t2, 4
|
||||||
|
j 1b
|
||||||
|
2:
|
||||||
|
|
||||||
|
// initialize .bss
|
||||||
|
la t0, _fbss
|
||||||
|
la t1, _ebss
|
||||||
|
1: beq t0, t1, 3f
|
||||||
|
sw zero, 0(t0)
|
||||||
|
addi t0, t0, 4
|
||||||
|
j 1b
|
||||||
|
3:
|
||||||
|
// enable external interrupts
|
||||||
|
li t0, MIE_MEIE
|
||||||
|
csrs mie, t0
|
||||||
|
|
||||||
|
call main
|
||||||
|
1: j 1b
|
||||||
|
|
||||||
|
trap_vector:
|
||||||
|
addi sp, sp, -16*4
|
||||||
|
sw ra, 0*4(sp)
|
||||||
|
sw t0, 1*4(sp)
|
||||||
|
sw t1, 2*4(sp)
|
||||||
|
sw t2, 3*4(sp)
|
||||||
|
sw a0, 4*4(sp)
|
||||||
|
sw a1, 5*4(sp)
|
||||||
|
sw a2, 6*4(sp)
|
||||||
|
sw a3, 7*4(sp)
|
||||||
|
sw a4, 8*4(sp)
|
||||||
|
sw a5, 9*4(sp)
|
||||||
|
sw a6, 10*4(sp)
|
||||||
|
sw a7, 11*4(sp)
|
||||||
|
sw t3, 12*4(sp)
|
||||||
|
sw t4, 13*4(sp)
|
||||||
|
sw t5, 14*4(sp)
|
||||||
|
sw t6, 15*4(sp)
|
||||||
|
call isr
|
||||||
|
lw ra, 0*4(sp)
|
||||||
|
lw t0, 1*4(sp)
|
||||||
|
lw t1, 2*4(sp)
|
||||||
|
lw t2, 3*4(sp)
|
||||||
|
lw a0, 4*4(sp)
|
||||||
|
lw a1, 5*4(sp)
|
||||||
|
lw a2, 6*4(sp)
|
||||||
|
lw a3, 7*4(sp)
|
||||||
|
lw a4, 8*4(sp)
|
||||||
|
lw a5, 9*4(sp)
|
||||||
|
lw a6, 10*4(sp)
|
||||||
|
lw a7, 11*4(sp)
|
||||||
|
lw t3, 12*4(sp)
|
||||||
|
lw t4, 13*4(sp)
|
||||||
|
lw t5, 14*4(sp)
|
||||||
|
lw t6, 15*4(sp)
|
||||||
|
addi sp, sp, 16*4
|
||||||
|
mret
|
|
@ -0,0 +1,4 @@
|
||||||
|
#ifndef __IRQ_H
|
||||||
|
#define __IRQ_H
|
||||||
|
|
||||||
|
#endif /* __IRQ_H */
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef __SYSTEM_H
|
||||||
|
#define __SYSTEM_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__attribute__((unused)) static void flush_cpu_icache(void){}; /* No instruction cache */
|
||||||
|
__attribute__((unused)) static void flush_cpu_dcache(void){}; /* No instruction cache */
|
||||||
|
void flush_l2_cache(void);
|
||||||
|
|
||||||
|
void busy_wait(unsigned int ms);
|
||||||
|
void busy_wait_us(unsigned int us);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __SYSTEM_H */
|
|
@ -339,6 +339,11 @@ class Builder:
|
||||||
# Initialize SoC with with BIOS data.
|
# Initialize SoC with with BIOS data.
|
||||||
self.soc.init_rom(name="rom", contents=bios_data)
|
self.soc.init_rom(name="rom", contents=bios_data)
|
||||||
|
|
||||||
|
# FIXME: Remove uRV ROM Init Workaround.
|
||||||
|
from litex.soc.cores.cpu.urv import uRV
|
||||||
|
if isinstance(self.soc.cpu, uRV):
|
||||||
|
self.soc.cpu.rom.init = bios_data
|
||||||
|
|
||||||
def build(self, **kwargs):
|
def build(self, **kwargs):
|
||||||
# Pass Output Directory to Platform.
|
# Pass Output Directory to Platform.
|
||||||
self.soc.platform.output_dir = self.output_dir
|
self.soc.platform.output_dir = self.output_dir
|
||||||
|
|
Loading…
Reference in New Issue