diff --git a/litex/soc/cores/cpu/__init__.py b/litex/soc/cores/cpu/__init__.py index f2080f18c..9ae5b0ae0 100644 --- a/litex/soc/cores/cpu/__init__.py +++ b/litex/soc/cores/cpu/__init__.py @@ -74,6 +74,7 @@ from litex.soc.cores.cpu.microwatt import Microwatt # RISC-V (32-bit) from litex.soc.cores.cpu.serv import SERV +from litex.soc.cores.cpu.femtorv import FemtoRV from litex.soc.cores.cpu.picorv32 import PicoRV32 from litex.soc.cores.cpu.minerva import Minerva from litex.soc.cores.cpu.vexriscv import VexRiscv @@ -107,6 +108,7 @@ CPUS = { # RISC-V (32-bit) "serv" : SERV, + "femtorv" : FemtoRV, "picorv32" : PicoRV32, "minerva" : Minerva, "vexriscv" : VexRiscv, diff --git a/litex/soc/cores/cpu/femtorv/__init__.py b/litex/soc/cores/cpu/femtorv/__init__.py new file mode 100644 index 000000000..1544ec75d --- /dev/null +++ b/litex/soc/cores/cpu/femtorv/__init__.py @@ -0,0 +1 @@ +from litex.soc.cores.cpu.femtorv.core import FemtoRV diff --git a/litex/soc/cores/cpu/femtorv/boot-helper.S b/litex/soc/cores/cpu/femtorv/boot-helper.S new file mode 100644 index 000000000..e8bd5c760 --- /dev/null +++ b/litex/soc/cores/cpu/femtorv/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/femtorv/core.py b/litex/soc/cores/cpu/femtorv/core.py new file mode 100644 index 000000000..82a7d7026 --- /dev/null +++ b/litex/soc/cores/cpu/femtorv/core.py @@ -0,0 +1,152 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2021 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +import os + +from migen import * + +from litex.soc.interconnect import wishbone +from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32 + +# Variants ----------------------------------------------------------------------------------------- + +CPU_VARIANTS = ["standard"] + +# FemtoRV ------------------------------------------------------------------------------------------ + +class FemtoRV(CPU): + name = "femtorv" + human_name = "FemtoRV" + 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 = "-march=rv32i " + flags += "-mabi=ilp32 " + flags += "-D__femtorv__ " + return flags + + def __init__(self, platform, variant="standard"): + self.platform = platform + self.variant = variant + self.reset = Signal() + self.idbus = idbus = wishbone.Interface() + self.periph_buses = [idbus] # Peripheral buses (Connected to main SoC's bus). + self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). + + # # # + + # FemtoRV Mem Bus. + # ---------------- + mbus = Record([ + ("addr", 32), + ("wdata", 32), + ("wmask", 4), + ("rdata", 32), + ("rstrb", 1), + ("rbusy", 1), + ("wbusy", 1), + ]) + + # FemtoRV Instance. + # ----------------- + self.cpu_params = dict( + # Parameters. + p_ADDR_WIDTH = 32, + p_RESET_ADDR = Constant(0, 32), + + # Clk / Rst. + i_clk = ClockSignal("sys"), + i_reset = ~ResetSignal("sys"), # Active Low. + + # I/D Bus. + o_mem_addr = mbus.addr, + o_mem_wdata = mbus.wdata, + o_mem_wmask = mbus.wmask, + i_mem_rdata = mbus.rdata, + o_mem_rstrb = mbus.rstrb, + i_mem_rbusy = mbus.rbusy, + i_mem_wbusy = mbus.wbusy, + ) + + # Adapt FemtoRV Mem Bus to Wishbone. + # ---------------------------------- + + # Bytes to Words addressing conversion. + self.comb += idbus.adr.eq(mbus.addr[2:]) + + # Wdata/WMask direct connection. + self.comb += idbus.dat_w.eq(mbus.wdata) + self.comb += idbus.sel.eq(mbus.wmask) + + # Control adaptation. + latch = Signal() + write = mbus.wmask != 0 + read = mbus.rstrb + + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + fsm.act("IDLE", + idbus.stb.eq(read | write), + idbus.cyc.eq(read | write), + idbus.we.eq(write), + If(read, + mbus.rbusy.eq(1), + NextState("READ") + ).Elif(write, + mbus.wbusy.eq(1), + NextState("WRITE") + ) + ) + fsm.act("READ", + idbus.stb.eq(1), + idbus.cyc.eq(1), + mbus.rbusy.eq(1), + If(idbus.ack, + latch.eq(1), + NextState("IDLE") + ) + ) + fsm.act("WRITE", + idbus.stb.eq(1), + idbus.cyc.eq(1), + idbus.we.eq(1), + mbus.wbusy.eq(1), + If(idbus.ack, + NextState("IDLE") + ) + ) + + # Latch RData on Wishbone ack. + self.sync += If(latch, mbus.rdata.eq(idbus.dat_r)) + + # Add Verilog sources. + # -------------------- + self.add_sources(platform) + + def set_reset_address(self, reset_address): + assert not hasattr(self, "reset_address") + self.reset_address = reset_address + self.cpu_params.update(p_RESET_ADDR=Constant(reset_address, 32)) + + @staticmethod + def add_sources(platform): + if not os.path.exists("femtorv32_quark.v"): + # Get FemtoRV32 source. + os.system("wget https://raw.githubusercontent.com/BrunoLevy/learn-fpga/master/FemtoRV/RTL/PROCESSOR/femtorv32_quark.v") + # FIXME: Patch it to fix compilation issue with Verilator, report issue. + os.system(f"patch -p0 < {os.path.dirname(os.path.realpath(__file__))}/femtorv32_quark.patch") + platform.add_source("femtorv32_quark.v") + + def do_finalize(self): + assert hasattr(self, "reset_address") + self.specials += Instance("FemtoRV32", **self.cpu_params) diff --git a/litex/soc/cores/cpu/femtorv/crt0.S b/litex/soc/cores/cpu/femtorv/crt0.S new file mode 100644 index 000000000..13bfc48e9 --- /dev/null +++ b/litex/soc/cores/cpu/femtorv/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/femtorv/femtorv32_quark.patch b/litex/soc/cores/cpu/femtorv/femtorv32_quark.patch new file mode 100644 index 000000000..043eb361c --- /dev/null +++ b/litex/soc/cores/cpu/femtorv/femtorv32_quark.patch @@ -0,0 +1,33 @@ +diff --git a/femtorv32_quark_fix.v femtorv32_quark.v +index 220b8d4..31f6c08 100644 +--- a/femtorv32_quark_fix.v ++++ femtorv32_quark.v +@@ -44,8 +44,6 @@ module FemtoRV32( + parameter RESET_ADDR = 32'h00000000; + parameter ADDR_WIDTH = 24; + +- localparam ADDR_PAD = {(32-ADDR_WIDTH){1'b0}}; // 32-bits padding for addrs +- + /***************************************************************************/ + // Instruction decoding. + /***************************************************************************/ +@@ -205,7 +203,7 @@ module FemtoRV32( + wire [ADDR_WIDTH-1:0] loadstore_addr = rs1[ADDR_WIDTH-1:0] + + (instr[5] ? Simm[ADDR_WIDTH-1:0] : Iimm[ADDR_WIDTH-1:0]); + +- assign mem_addr = {ADDR_PAD, ++ assign mem_addr = { + state[WAIT_INSTR_bit] | state[FETCH_INSTR_bit] ? + PC : loadstore_addr + }; +@@ -220,8 +218,8 @@ module FemtoRV32( + /* verilator lint_on WIDTH */ + (isLUI ? Uimm : 32'b0) | // LUI + (isALU ? aluOut : 32'b0) | // ALUreg, ALUimm +- (isAUIPC ? {ADDR_PAD,PCplusImm} : 32'b0) | // AUIPC +- (isJALR | isJAL ? {ADDR_PAD,PCplus4 } : 32'b0) | // JAL, JALR ++ (isAUIPC ? {PCplusImm} : 32'b0) | // AUIPC ++ (isJALR | isJAL ? {PCplus4 } : 32'b0) | // JAL, JALR + (isLoad ? LOAD_data : 32'b0); // Load + + /***************************************************************************/ diff --git a/litex/soc/cores/cpu/femtorv/irq.h b/litex/soc/cores/cpu/femtorv/irq.h new file mode 100644 index 000000000..7374cf506 --- /dev/null +++ b/litex/soc/cores/cpu/femtorv/irq.h @@ -0,0 +1,4 @@ +#ifndef __IRQ_H +#define __IRQ_H + +#endif /* __IRQ_H */ diff --git a/litex/soc/cores/cpu/femtorv/system.h b/litex/soc/cores/cpu/femtorv/system.h new file mode 100644 index 000000000..262446a62 --- /dev/null +++ b/litex/soc/cores/cpu/femtorv/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 */