Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial uRV CPU support. #2098

Merged
merged 4 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
[> Added
--------
- 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
----------
Expand Down
1 change: 1 addition & 0 deletions litex/soc/cores/cpu/urv/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from litex.soc.cores.cpu.urv.core import uRV
4 changes: 4 additions & 0 deletions litex/soc/cores/cpu/urv/boot-helper.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.section .text, "ax", @progbits
.global boot_helper
boot_helper:
jr x13
238 changes: 238 additions & 0 deletions litex/soc/cores/cpu/urv/core.py
Original file line number Diff line number Diff line change
@@ -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)
75 changes: 75 additions & 0 deletions litex/soc/cores/cpu/urv/crt0.S
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions litex/soc/cores/cpu/urv/irq.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#ifndef __IRQ_H
#define __IRQ_H

#endif /* __IRQ_H */
19 changes: 19 additions & 0 deletions litex/soc/cores/cpu/urv/system.h
Original file line number Diff line number Diff line change
@@ -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 */
5 changes: 5 additions & 0 deletions litex/soc/integration/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,11 @@ def _initialize_rom_software(self):
# Initialize SoC with with 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):
# Pass Output Directory to Platform.
self.soc.platform.output_dir = self.output_dir
Expand Down
Loading