cores/cpu: add initial lowRISC's Ibex support (without interrupts).

Working in simulation and on hardware: litex_sim --cpu-type=ibex, ./target.py --cpu-type=ibex.

This is currently doing a git clone of ibex and opentitan repositories but we'll
create a pythondata-cpu-ibex package in the future.

litex_sim --cpu-type=ibex:

        __   _ __      _  __
       / /  (_) /____ | |/_/
      / /__/ / __/ -_)>  <
     /____/_/\__/\__/_/|_|
   Build your hardware, easily!

 (c) Copyright 2012-2020 Enjoy-Digital
 (c) Copyright 2007-2015 M-Labs

 BIOS built on Feb 15 2021 11:57:50
 BIOS CRC passed (e7517f7b)

 Migen git sha1: 7014bdc
 LiteX git sha1: ead12df2

--=============== SoC ==================--
CPU:		Ibex @ 1MHz
BUS:		WISHBONE 32-bit @ 4GiB
CSR:		32-bit data
ROM:		32KiB
SRAM:		8KiB
MAIN-RAM:	262144KiB

--============== Boot ==================--
Booting from serial...
Press Q or ESC to abort boot completely.
sL5DdSMmkekro
Timeout
No boot medium found

--============= Console ================--
This commit is contained in:
Florent Kermarrec 2021-02-15 12:01:46 +01:00
parent ead12df21b
commit 510bda4c99
7 changed files with 324 additions and 0 deletions

View File

@ -77,6 +77,7 @@ from litex.soc.cores.cpu.picorv32 import PicoRV32
from litex.soc.cores.cpu.minerva import Minerva
from litex.soc.cores.cpu.vexriscv import VexRiscv
from litex.soc.cores.cpu.vexriscv_smp import VexRiscvSMP
from litex.soc.cores.cpu.ibex import Ibex
from litex.soc.cores.cpu.cv32e40p import CV32E40P
# RISC-V (64-bit)
@ -109,6 +110,7 @@ CPUS = {
"minerva" : Minerva,
"vexriscv" : VexRiscv,
"vexriscv_smp": VexRiscvSMP,
"ibex" : Ibex,
"cv32e40p" : CV32E40P,
# RISC-V (64-bit)

View File

@ -0,0 +1 @@
from litex.soc.cores.cpu.ibex.core import Ibex

View File

@ -0,0 +1,4 @@
.section .text, "ax", @progbits
.global boot_helper
boot_helper:
jr x13

View File

@ -0,0 +1,219 @@
#
# This file is part of LiteX.
#
# Copyright (c) 2021 Florent Kermarrec <florent@enjoy-digital.fr>
# Copyright (c) 2020 Antmicro <www.antmicro.com>
# 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
CPU_VARIANTS = ["standard"]
GCC_FLAGS = {
# /-------- Base ISA
# |/------- Hardware Multiply + Divide
# ||/----- Atomics
# |||/---- Compressed ISA
# ||||/--- Single-Precision Floating-Point
# |||||/-- Double-Precision Floating-Point
# imacfd
"standard": "-march=rv32imc -mabi=ilp32 ",
}
obi_layout = [
("req", 1),
("gnt", 1),
("addr", 32),
("we", 1),
("be", 4),
("wdata", 32),
("rvalid", 1),
("rdata", 32),
]
class OBI2Wishbone(Module):
def __init__(self, obi, wb):
addr = Signal.like(obi.addr)
be = Signal.like(obi.be)
we = Signal.like(obi.we)
wdata = Signal.like(obi.wdata)
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
# On OBI request:
If(obi.req,
# Drive Wishbone bus from OBI bus.
wb.adr.eq(obi.addr[2:32]),
wb.stb.eq( 1),
wb.dat_w.eq( obi.wdata),
wb.cyc.eq( 1),
wb.sel.eq( obi.be),
wb.we.eq( obi.we),
# Store OBI bus values.
NextValue(addr, obi.addr),
NextValue(be, obi.be),
NextValue(we, obi.we),
NextValue(wdata, obi.wdata),
# Now we need to wait Wishbone Ack.
NextState("ACK")
),
obi.gnt.eq(1), # Always ack OBI request in Idle.
)
fsm.act("ACK",
# Drive Wishbone bus from stored OBI bus values.
wb.adr.eq(addr[2:32]),
wb.stb.eq( 1),
wb.dat_w.eq( wdata),
wb.cyc.eq( 1),
wb.sel.eq( be),
wb.we.eq( we),
# On Wishbone Ack:
If(wb.ack,
# Generate OBI response.
obi.rvalid.eq(1),
obi.rdata.eq(wb.dat_r),
# Return to Idle.
NextState("IDLE")
)
)
class Ibex(CPU):
name = "ibex"
human_name = "Ibex"
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
@property
def gcc_flags(self):
flags = GCC_FLAGS[self.variant]
flags += "-D__ibex__ "
return flags
def __init__(self, platform, variant="standard"):
self.platform = platform
self.variant = variant
self.reset = Signal()
self.ibus = wishbone.Interface()
self.dbus = wishbone.Interface()
self.periph_buses = [self.ibus, self.dbus]
self.memory_buses = []
ibus = Record(obi_layout)
dbus = Record(obi_layout)
self.submodules.ibus_conv = OBI2Wishbone(ibus, self.ibus)
self.submodules.dbus_conv = OBI2Wishbone(dbus, self.dbus)
self.comb += [
ibus.we.eq(0),
ibus.be.eq(1111),
]
class Open(Signal): pass
self.cpu_params = dict(
# Configuration
p_RegFile = 1, # RegFileFPGA
i_test_en_i = 0,
i_hart_id_i = 0,
# Clk/Rst
i_clk_i = ClockSignal(),
i_rst_ni = ~ResetSignal(),
# Instruction bus
o_instr_req_o = ibus.req,
i_instr_gnt_i = ibus.gnt,
i_instr_rvalid_i = ibus.rvalid,
o_instr_addr_o = ibus.addr,
i_instr_rdata_i = ibus.rdata,
i_instr_err_i = 0,
# Data bus
o_data_req_o = dbus.req,
i_data_gnt_i = dbus.gnt,
i_data_rvalid_i = dbus.rvalid,
o_data_we_o = dbus.we,
o_data_be_o = dbus.be,
o_data_addr_o = dbus.addr,
o_data_wdata_o = dbus.wdata,
i_data_rdata_i = dbus.rdata,
i_data_err_i = 0,
# Interrupts
i_irq_software_i = 0,
i_irq_timer_i = 0,
i_irq_external_i = 0,
i_irq_fast_i = 0,
i_irq_nm_i = 0,
# Debug
i_debug_req_i = 0,
# Control/Status
i_fetch_enable_i = 1,
o_alert_minor_o = Open(),
o_alert_major_o = Open(),
o_core_sleep_o = Open()
)
# Add verilog sources
self.add_sources(platform)
@staticmethod
def add_sources(platform):
# FIXME: Create pythondata-cpu-ibex.
os.system("git clone https://github.com/lowRISC/ibex")
os.system("git clone https://github.com/lowRISC/opentitan")
platform.add_sources(os.path.join("ibex", "rtl"),
"ibex_pkg.sv",
"ibex_alu.sv",
"ibex_compressed_decoder.sv",
"ibex_controller.sv",
"ibex_counter.sv",
"ibex_cs_registers.sv",
"ibex_csr.sv",
"ibex_decoder.sv",
"ibex_ex_block.sv",
"ibex_id_stage.sv",
"ibex_if_stage.sv",
"ibex_load_store_unit.sv",
"ibex_multdiv_slow.sv",
"ibex_multdiv_fast.sv",
"ibex_prefetch_buffer.sv",
"ibex_fetch_fifo.sv",
"ibex_register_file_fpga.sv",
"ibex_wb_stage.sv",
"ibex_core.sv",
)
platform.add_source(os.path.join("ibex", "syn", "rtl", "prim_clock_gating.v"))
platform.add_sources(os.path.join("opentitan", "hw", "ip", "prim", "rtl"),
"prim_alert_pkg.sv",
"prim_assert.sv"
)
platform.add_verilog_include_path(os.path.join("opentitan", "hw", "ip", "prim", "rtl"))
platform.add_verilog_include_path(os.path.join("ibex", "dv", "fcov"))
def set_reset_address(self, reset_address):
assert not hasattr(self, "reset_address")
self.reset_address = reset_address
self.cpu_params.update(i_boot_addr_i=Signal(32, reset=reset_address))
def do_finalize(self):
assert hasattr(self, "reset_address")
self.specials += Instance("ibex_core", **self.cpu_params)

View File

@ -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

View File

@ -0,0 +1,4 @@
#ifndef __IRQ_H
#define __IRQ_H
#endif /* __IRQ_H */

View File

@ -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 */