From edb56e73aa3c5645acc74adcdcd4d1a55b67a99f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 16 Oct 2024 22:24:07 +0200 Subject: [PATCH 1/4] soc/cores/cpu: Add initial uRV CPU support (not yet working). --- litex/soc/cores/cpu/urv/__init__.py | 1 + litex/soc/cores/cpu/urv/boot-helper.S | 4 + litex/soc/cores/cpu/urv/core.py | 210 ++++++++++++++++++++++++++ litex/soc/cores/cpu/urv/crt0.S | 75 +++++++++ litex/soc/cores/cpu/urv/irq.h | 4 + litex/soc/cores/cpu/urv/system.h | 19 +++ 6 files changed, 313 insertions(+) create mode 100644 litex/soc/cores/cpu/urv/__init__.py create mode 100644 litex/soc/cores/cpu/urv/boot-helper.S create mode 100644 litex/soc/cores/cpu/urv/core.py create mode 100644 litex/soc/cores/cpu/urv/crt0.S create mode 100644 litex/soc/cores/cpu/urv/irq.h create mode 100644 litex/soc/cores/cpu/urv/system.h diff --git a/litex/soc/cores/cpu/urv/__init__.py b/litex/soc/cores/cpu/urv/__init__.py new file mode 100644 index 0000000000..e4ef785b61 --- /dev/null +++ b/litex/soc/cores/cpu/urv/__init__.py @@ -0,0 +1 @@ +from litex.soc.cores.cpu.urv.core import uRV diff --git a/litex/soc/cores/cpu/urv/boot-helper.S b/litex/soc/cores/cpu/urv/boot-helper.S new file mode 100644 index 0000000000..336a4d4f39 --- /dev/null +++ b/litex/soc/cores/cpu/urv/boot-helper.S @@ -0,0 +1,4 @@ + .section .text, "ax", @progbits + .global boot_helper +boot_helper: + jr x13 diff --git a/litex/soc/cores/cpu/urv/core.py b/litex/soc/cores/cpu/urv/core.py new file mode 100644 index 0000000000..6ac7896eb4 --- /dev/null +++ b/litex/soc/cores/cpu/urv/core.py @@ -0,0 +1,210 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2024 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +import os + +from migen import * + +from litex.gen import * + +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(1) + im_data = Signal(32) + im_valid = Signal(1) + + 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() + + rst_count = Signal(8, reset=16) + self.sync += If(rst_count != 0, rst_count.eq(rst_count - 1)) + + # uRV Instance. + # ------------- + self.cpu_params = dict( + # Parameters. + p_g_timer_frequency = 1000, + p_g_clock_frequency = 100000000, + 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 | (rst_count != 0)), + + # 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. + # -------------------- + self.i_fsm = i_fsm = FSM(reset_state="IDLE") + i_fsm.act("IDLE", + If(im_rd, + 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.d_fsm = d_fsm = FSM(reset_state="IDLE") + d_fsm.act("IDLE", + If(dm_store, + NextState("WRITE") + ), + If(dm_load, + NextState("READ") + ) + ) + d_fsm.act("WRITE", + dbus.stb.eq(1), + dbus.cyc.eq(1), + dbus.we.eq(1), + dbus.adr.eq(dm_addr), + dbus.sel.eq(dm_data_select), + dbus.dat_w.eq(dm_data_s), + If(dbus.ack, + NextState("IDLE") + ) + ) + d_fsm.act("READ", + dbus.stb.eq(1), + dbus.cyc.eq(1), + dbus.we.eq(0), + dbus.adr.eq(dm_addr), + dbus.sel.eq(dm_data_select), + If(dbus.ack, + 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) diff --git a/litex/soc/cores/cpu/urv/crt0.S b/litex/soc/cores/cpu/urv/crt0.S new file mode 100644 index 0000000000..683f6ad784 --- /dev/null +++ b/litex/soc/cores/cpu/urv/crt0.S @@ -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 diff --git a/litex/soc/cores/cpu/urv/irq.h b/litex/soc/cores/cpu/urv/irq.h new file mode 100644 index 0000000000..1aa55bc8e4 --- /dev/null +++ b/litex/soc/cores/cpu/urv/irq.h @@ -0,0 +1,4 @@ +#ifndef __IRQ_H +#define __IRQ_H + +#endif /* __IRQ_H */ diff --git a/litex/soc/cores/cpu/urv/system.h b/litex/soc/cores/cpu/urv/system.h new file mode 100644 index 0000000000..828c87bc1d --- /dev/null +++ b/litex/soc/cores/cpu/urv/system.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 */ From 9449d25911b855bd5c99353ebf34436283181084 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 17 Oct 2024 16:54:20 +0200 Subject: [PATCH 2/4] soc/cores/cpu/urv: Able to boot LiteX BIOS with im bus connected to synchronous memory. - Replace im bus wishbone adaptation with synchronous memory (for now and initial tests). - Correctly handle dm bus wishbone adaptation (Added FIFO). --- litex/soc/cores/cpu/urv/core.py | 116 +++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 40 deletions(-) diff --git a/litex/soc/cores/cpu/urv/core.py b/litex/soc/cores/cpu/urv/core.py index 6ac7896eb4..abf4b82e60 100644 --- a/litex/soc/cores/cpu/urv/core.py +++ b/litex/soc/cores/cpu/urv/core.py @@ -10,6 +10,8 @@ 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 @@ -62,14 +64,14 @@ def __init__(self, platform, variant="standard"): 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). + self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). # uRV Signals. # ------------ im_addr = Signal(32) - im_rd = Signal(1) + im_rd = Signal() im_data = Signal(32) - im_valid = Signal(1) + im_valid = Signal() dm_addr = Signal(32) dm_data_s = Signal(32) @@ -80,9 +82,6 @@ def __init__(self, platform, variant="standard"): dm_load_done = Signal() dm_store_done = Signal() - rst_count = Signal(8, reset=16) - self.sync += If(rst_count != 0, rst_count.eq(rst_count - 1)) - # uRV Instance. # ------------- self.cpu_params = dict( @@ -97,8 +96,8 @@ def __init__(self, platform, variant="standard"): p_g_with_compressed_insns = 0, # Clk / Rst. - i_clk_i = ClockSignal("sys"), - i_rst_i = ~(ResetSignal("sys") | self.reset | (rst_count != 0)), + i_clk_i = ClockSignal("sys"), + i_rst_i = ResetSignal("sys") | self.reset, # Instruction Mem Bus. o_im_addr_o = im_addr, @@ -120,55 +119,92 @@ def __init__(self, platform, variant="standard"): # uRV Instruction Bus. # -------------------- - self.i_fsm = i_fsm = FSM(reset_state="IDLE") - i_fsm.act("IDLE", - If(im_rd, - 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") + from litex.soc.integration.common import get_mem_data + + try: + # FIXME. + rom_init = get_mem_data("build/sim/software/bios/bios.bin", + data_width = 32, + endianness = "little" ) - ) + except: + rom_init = [] + rom = Memory(32, depth=131072//4, init=rom_init) + rom_port = rom.get_port() + self.specials += rom, rom_port + + self.sync += im_valid.eq(1), + self.comb += [ + rom_port.adr.eq(im_addr[2:]), + im_data.eq(rom_port.dat_r), + ] + +# 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.d_fsm = d_fsm = FSM(reset_state="IDLE") - d_fsm.act("IDLE", - If(dm_store, - NextState("WRITE") - ), - If(dm_load, - NextState("READ") + 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") + ) ) ) - d_fsm.act("WRITE", + dm_fsm.act("WRITE", dbus.stb.eq(1), dbus.cyc.eq(1), dbus.we.eq(1), - dbus.adr.eq(dm_addr), - dbus.sel.eq(dm_data_select), - dbus.dat_w.eq(dm_data_s), + 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") ) ) - d_fsm.act("READ", + dm_fsm.act("READ", dbus.stb.eq(1), dbus.cyc.eq(1), dbus.we.eq(0), - dbus.adr.eq(dm_addr), - dbus.sel.eq(dm_data_select), + 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") From aab8912f5a51298c74f911fb5ddd9a9b3c157319 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 17 Oct 2024 17:44:40 +0200 Subject: [PATCH 3/4] soc/cores/cpu/urv: Move ROM init to builder and allow switching between classical ROM or ROM integrated in CPU. --- litex/soc/cores/cpu/urv/core.py | 76 ++++++++++++++------------------ litex/soc/integration/builder.py | 5 +++ 2 files changed, 39 insertions(+), 42 deletions(-) diff --git a/litex/soc/cores/cpu/urv/core.py b/litex/soc/cores/cpu/urv/core.py index abf4b82e60..1270b678b1 100644 --- a/litex/soc/cores/cpu/urv/core.py +++ b/litex/soc/cores/cpu/urv/core.py @@ -86,8 +86,8 @@ def __init__(self, platform, variant="standard"): # ------------- self.cpu_params = dict( # Parameters. - p_g_timer_frequency = 1000, - p_g_clock_frequency = 100000000, + 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, @@ -119,47 +119,39 @@ def __init__(self, platform, variant="standard"): # uRV Instruction Bus. # -------------------- - from litex.soc.integration.common import get_mem_data - - try: - # FIXME. - rom_init = get_mem_data("build/sim/software/bios/bios.bin", - data_width = 32, - endianness = "little" + 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") + ) ) - except: - rom_init = [] - rom = Memory(32, depth=131072//4, init=rom_init) - rom_port = rom.get_port() - self.specials += rom, rom_port - - self.sync += im_valid.eq(1), - self.comb += [ - rom_port.adr.eq(im_addr[2:]), - im_data.eq(rom_port.dat_r), - ] - -# 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. # ------------- diff --git a/litex/soc/integration/builder.py b/litex/soc/integration/builder.py index 027862e8f6..a436ba52d6 100644 --- a/litex/soc/integration/builder.py +++ b/litex/soc/integration/builder.py @@ -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 From 5f463dba87d0a43ff7a3ce0758ffdf0a0e8c25c2 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 17 Oct 2024 17:45:50 +0200 Subject: [PATCH 4/4] CHANGES.md: Update. --- CHANGES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index c5b688bef4..659b82ff17 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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 ----------