Skip to content

Commit

Permalink
Add RISC-V exception handler for MARS kernel (#1247)
Browse files Browse the repository at this point in the history
Fixes #1140
  • Loading branch information
exucutional authored and pavelkryukov committed Mar 5, 2020
1 parent 686f672 commit 5398b07
Show file tree
Hide file tree
Showing 31 changed files with 358 additions and 69 deletions.
18 changes: 15 additions & 3 deletions kernels/Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
# Building MIPS ElF binaries
# Building MIPS and RISC-V ElF binaries
# @author Alexander Titov <[email protected]>
# Copyright 2012-2019 uArchSim iLab Project

MIPS_AS?=mips-linux-gnu-as
MIPS_LD?=mips-linux-gnu-ld

RISCV_AS?=riscv64-unknown-elf-as
AS_FLAGS?=-march=rv32i -mabi=ilp32
RISCV_LD?=riscv64-unknown-elf-ld
LD_FLAGS?=-melf32lriscv --no-relax

# assemble all the object files
build_all: mars32_le.bin
build_all: mars32_le.bin riscv32.bin

mars32_le.bin: mars32_le.o
@$(MIPS_LD) $< -o $@ -EL -pie
Expand All @@ -16,6 +21,13 @@ mars32_le.bin: mars32_le.o
mars32_le.o: exceptions.s Makefile
@$(MIPS_AS) $< -o $@ -O0 -mips64 -no-break -EL -g -KPIC

riscv32.bin: riscv32.o
@$(RISCV_LD) $(LD_FLAGS) $< -o $@
@echo $@ is built

riscv32.o: riscv_exceptions.s
@$(RISCV_AS) $(AS_FLAGS) $< -o $@

# it is needed to preven make from
# deleting .o files automatically
.PRECIOUS: %.o
Expand All @@ -26,6 +38,6 @@ clean:

.PHONY: help
help:
@echo " This makefile build all MIPS assembly files in the directory."
@echo " This makefile build all MIPS and RISC-V assembly files in the directory."
@echo " To do that just type 'make' or 'make build_all'."
@echo " Note that assembly files should have '.s' extension."
Binary file modified kernels/mars32_le.bin
Binary file not shown.
Binary file added kernels/riscv32.bin
Binary file not shown.
112 changes: 112 additions & 0 deletions kernels/riscv_exceptions.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# RISC-V exception handler
# Author Eric Konks
# Copyright 2020 MIPT-V

.data
__m1_: .string " Exception "
__m2_: .string " Interrupt "
__m3_: .string " occurred\n"

__i0_: .string " [User software interrupt] "
__i1_: .string " [Supervisor software interrupt]"
__i2_: .string " [Reserved for future standard use]"
__i3_: .string " [Machine software interrupt]"
__i4_: .string " [User timer interrupt]"
__i5_: .string " [Supervisor timer interrupt]"
__i6_: .string " [Reserved for future standard use]"
__i7_: .string " [Machine timer interrupt]"
__i8_: .string " [User external interrupt]"
__i9_: .string " [Supervisor external interrupt]"
__i10_: .string " [Reserved for future standard use] "
__i11_: .string " [Machine external interrupt]"

__e0_: .string " [Instruction address misaligned]"
__e1_: .string " [Instruction access fault]"
__e2_: .string " [Illegal instruction]"
__e3_: .string " [Breakpoint]"
__e4_: .string " [Load address misaligned]"
__e5_: .string " [Load access fault]"
__e6_: .string " [Store/AMO address misaligned]"
__e7_: .string " [Store/AMO access fault]"
__e8_: .string " [Environment call from U-mode]"
__e9_: .string " [Environment call from S-mode]"
__e10_: .string " [Reserved]"
__e11_: .string " [Environment call from M-mode]"
__e12_: .string " [Instruction page fault]"
__e13_: .string " [Load page fault]"
__e14_: .string " [Reserved for future standard use]"
__e15_: .string " [Store/AMO page fault]"

__excp: .word __e0_, __e1_, __e2_, __e3_, __e4_, __e5_, __e6_, __e7_, __e8_, __e9_
.word __e10_, __e11_, __e12_, __e13_, __e14_

__intr: .word __i0_, __i1_, __i2_, __i3_, __i4_, __i5_, __i6_, __i7_, __i8_, __i9_
.word __i10_, __i10_, __i11_

.section .text
.globl _start
_start:
csrr t0, scause # Save cause register
not t1, x0
srli t1, t1, 0x1
and t0, t0, t1 # Extract exception code
not t1, t1 # Extract interrupt bit
beqz t1, _not_intr # Branch if not interrupt

# Interrupt-specific code

# Print information about interrupt
li x2, 4 # Syscall 4 (print string)
la x4, __m2_
ecall
li x2, 1 # Syscall 1 (print int)
mv x4, t0
ecall
li x2, 4 # Syscall 4 (print string)
lw x4, %lo(__intr)(t0)
ecall
li x2, 4 # Syscall 4 (print string)
la x4, __m3_
ecall

_not_intr:

# Exception-specific code

# Print information about exception
li x2, 4 # Syscall 4 (print str)
la x4, __m1_
ecall
li x2, 1 # Syscall 1 (print int)
mv x4, t0
ecall
li x2, 4 # Syscall 4 (print string)
lw x4, %lo(__excp)(t0)
ecall
li x2, 4 # Syscall 4 (print string)
la x4, __m3_
ecall

# 0x2 Illegal insruction
li t1, 2
beq t0, t1, _terminate

# 0x0 Instruction Address misaligned
bnez t0, _ok_pc # Branch if exception code != 0
csrr t0, sepc
andi t0, t0, 3 # Word-aligning check
beqz t0, _ok_pc # Branch if EPC word-aligned
j _terminate

_terminate:
li x2, 0xA # Syscall 10 (exit)
ecall

_ok_pc:

_return:
csrwi scause, 0 # Clear cause register
csrr t0, sepc
addi t0, t0, 4 # Skip instruction to avoid infinite loop
csrw sepc, t0
sret # Return from exception
2 changes: 2 additions & 0 deletions simulator/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ set(TESTS_CPPS
risc_v/riscv_register/t/unit_test.cpp
risc_v/t/unit_test.cpp
risc_v/t/riscv64_test.cpp
risc_v/t/riscv32_driver_test.cpp
func_sim/rf/t/unit_test.cpp
func_sim/traps/t/unit_test.cpp
func_sim/driver/t/unit_test.cpp
Expand Down Expand Up @@ -171,6 +172,7 @@ add_library(mipt-mips-src OBJECT
mips/mips_driver.cpp
risc_v/riscv_register/riscv_register.cpp
risc_v/riscv_instr.cpp
risc_v/riscv_driver.cpp
export/gdb/gdb_wrapper.cpp
export/cen64/cen64_wrapper.cpp
export/cache/runner.cpp
Expand Down
2 changes: 1 addition & 1 deletion simulator/export/cen64/cen64_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ struct vr4300 : private PerfSim<MIPS64>
void write_cause_register( uint64 value) { return write_cpu_register( cause_index, value); }

public:
vr4300() : PerfSim<MIPS64>( Endian::big) { sout.enable(); }
vr4300() : PerfSim<MIPS64>( Endian::big, "mips64be") { sout.enable(); }

int init( std::shared_ptr<FuncMemory> mem);
void apply_mask_to_cause( uint64 mask);
Expand Down
1 change: 1 addition & 0 deletions simulator/export/gdb/gdb_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ GDBSim::GDBSim( const std::string& isa)
cpu->set_kernel( kernel);
kernel->set_simulator( cpu);
kernel->connect_memory( memory);
kernel->connect_exception_handler();
}

bool GDBSim::load( const std::string& filename) const try
Expand Down
3 changes: 2 additions & 1 deletion simulator/export/standalone/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ int Main::impl( int argc, const char* argv[]) const {
sim->write_csr_register( "mscratch", 0x400'0000);

auto kernel = Kernel::create_configured_kernel();
kernel->connect_memory( memory);
kernel->set_simulator( sim);
kernel->connect_memory( memory);
kernel->connect_exception_handler();
kernel->load_file( config::binary_filename);
sim->set_kernel( kernel);

Expand Down
4 changes: 2 additions & 2 deletions simulator/func_sim/func_sim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
#include <stdexcept>

template <typename ISA>
FuncSim<ISA>::FuncSim( Endian endian, bool log)
: BasicFuncSim()
FuncSim<ISA>::FuncSim( Endian endian, bool log, std::string_view isa)
: BasicFuncSim( isa)
, imem( endian)
, driver( ISA::create_driver( this))
{
Expand Down
7 changes: 5 additions & 2 deletions simulator/func_sim/func_sim.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ class Driver;
class Operation;

// NOLINTNEXTLINE(fuchsia-multiple-inheritance) Cannot inherit Simulator from Log, since PerfSim inherits Module as well
class BasicFuncSim : public Simulator, public Log { };
class BasicFuncSim : public Simulator, public Log {
protected:
explicit BasicFuncSim( std::string_view isa) : Simulator( isa) { }
};

template <typename ISA>
class FuncSim : public BasicFuncSim
Expand Down Expand Up @@ -50,7 +53,7 @@ class FuncSim : public BasicFuncSim
void write_register( Register index, uint64 value) { rf.write( index, narrow_cast<RegisterUInt>( value)); }

public:
FuncSim( Endian endian, bool log);
FuncSim( Endian endian, bool log, std::string_view isa);

void set_memory( std::shared_ptr<FuncMemory> memory) final;
void set_kernel( std::shared_ptr<Kernel> k) final { kernel = std::move( k); }
Expand Down
27 changes: 18 additions & 9 deletions simulator/func_sim/t/unit_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ static auto run_over_empty_memory( const std::string& isa)
auto kernel = Kernel::create_dummy_kernel();
kernel->set_simulator( sim);
kernel->connect_memory( m);
kernel->connect_exception_handler();
kernel->load_file( TEST_PATH "/mips-tt-no-delayed-branches.bin");
sim->set_kernel( kernel);
return sim->run( 30);
Expand All @@ -48,6 +49,7 @@ TEST_CASE( "FuncSim: get lost without pc")
auto kernel = Kernel::create_dummy_kernel();
kernel->set_simulator( sim);
kernel->connect_memory( m);
kernel->connect_exception_handler();
kernel->load_file( TEST_PATH "/mips-tt-no-delayed-branches.bin");
sim->set_kernel( kernel);
CHECK_THROWS_AS( sim->run_no_limit(), BearingLost);
Expand All @@ -63,6 +65,7 @@ TEST_CASE( "Process_Wrong_Args_Of_Constr: Func_Sim_init_and_load")
auto kernel = Kernel::create_dummy_kernel();
kernel->set_simulator( sim);
kernel->connect_memory( mem);
kernel->connect_exception_handler();
kernel->load_file( TEST_PATH "/mips-tt-no-delayed-branches.bin");
sim->set_kernel( kernel);
CHECK_NOTHROW( sim->set_pc( kernel->get_start_pc()) );
Expand All @@ -77,6 +80,7 @@ TEST_CASE( "Make_A_Step: Func_Sim")
auto kernel = Kernel::create_dummy_kernel();
kernel->set_simulator( sim);
kernel->connect_memory( mem);
kernel->connect_exception_handler();
kernel->load_file( TEST_PATH "/mips-tt-no-delayed-branches.bin");
sim->set_kernel( kernel);

Expand All @@ -98,6 +102,7 @@ TEST_CASE( "Run one instruction: Func_Sim")
auto kernel = Kernel::create_dummy_kernel();
kernel->set_simulator( sim);
kernel->connect_memory( mem);
kernel->connect_exception_handler();
kernel->load_file( TEST_PATH "/mips-tt-no-delayed-branches.bin");
sim->set_kernel( kernel);

Expand Down Expand Up @@ -147,6 +152,7 @@ TEST_CASE( "Run_SMC_trace: Func_Sim")
auto kernel = Kernel::create_mars_kernel();
kernel->set_simulator( sim);
kernel->connect_memory( mem);
kernel->connect_exception_handler();
kernel->load_file( TEST_PATH "/mips-tt-no-delayed-branches.bin");
sim->set_kernel( kernel);

Expand All @@ -165,6 +171,7 @@ TEST_CASE( "Torture_Test: MIPS32 calls without kernel")
auto kernel = Kernel::create_dummy_kernel();
kernel->set_simulator( sim);
kernel->connect_memory( mem);
kernel->connect_exception_handler();
kernel->load_file( TEST_PATH "/mips-tt-no-delayed-branches.bin");
sim->set_kernel( kernel);

Expand All @@ -179,17 +186,19 @@ TEST_CASE( "Torture_Test: MIPS32 calls without kernel")
CHECK( sim->get_exit_code() == 0);
}

static auto get_simulator_with_test( const std::string& isa, const std::string& test, bool enable_hooks)
static auto get_simulator_with_test( const std::string& isa, const std::string& test, bool enable_hooks, bool enable_mars)
{
auto sim = Simulator::create_functional_simulator(isa);
auto mem = FuncMemory::create_default_hierarchied_memory();
sim->set_memory( mem);
if ( enable_hooks)
sim->enable_driver_hooks();

auto kernel = Kernel::create_mars_kernel();
kernel->connect_memory( mem);
auto kernel = enable_mars ? Kernel::create_mars_kernel() : Kernel::create_dummy_kernel();
kernel->set_simulator( sim);
kernel->connect_memory( mem);
kernel->connect_exception_handler();

sim->set_kernel( kernel);
kernel->load_file( test);

Expand All @@ -199,28 +208,28 @@ static auto get_simulator_with_test( const std::string& isa, const std::string&

TEST_CASE( "Torture_Test: Stop on trap")
{
CHECK( get_simulator_with_test("mips32", TEST_PATH "/mips-tt-no-delayed-branches.bin", true)->run( 1) == Trap::BREAKPOINT );
auto trap = get_simulator_with_test("mips32", TEST_PATH "/mips-tt-no-delayed-branches.bin", true)->run( 10000);
CHECK( get_simulator_with_test("mips32", TEST_PATH "/mips-tt-no-delayed-branches.bin", true, false)->run( 1) == Trap::BREAKPOINT );
auto trap = get_simulator_with_test("mips32", TEST_PATH "/mips-tt-no-delayed-branches.bin", true, false)->run( 10000);
CHECK( trap != Trap::NO_TRAP );
CHECK( trap != Trap::HALT );
}

TEST_CASE( "Torture_Test: MIPS32 calls ")
{
CHECK( get_simulator_with_test("mips32", TEST_PATH "/mips-tt-no-delayed-branches.bin", false)->run( 10000) == Trap::HALT );
CHECK( get_simulator_with_test("mips32", TEST_PATH "/mips-tt-no-delayed-branches.bin", false, true)->run( 10000) == Trap::HALT );
}

static bool riscv_tt( const std::string& isa, const std::string& name)
{
auto sim = get_simulator_with_test( isa, name, false);
auto sim = get_simulator_with_test( isa, name, false, false);
auto trap = sim->run_no_limit();
return trap == Trap::HALT && sim->read_cpu_register( 3) == 1;
}

TEST_CASE( "Torture_Test: integration")
{
CHECK( get_simulator_with_test("mars", TEST_PATH "/mips-tt-no-delayed-branches.bin", false)->run_no_limit() == Trap::HALT );
CHECK( get_simulator_with_test("mips32", TEST_PATH "/mips-tt.bin", false)->run_no_limit() == Trap::HALT );
CHECK( get_simulator_with_test("mars", TEST_PATH "/mips-tt-no-delayed-branches.bin", false, true)->run_no_limit() == Trap::HALT );
CHECK( get_simulator_with_test("mips32", TEST_PATH "/mips-tt.bin", false, true)->run_no_limit() == Trap::HALT );
CHECK( riscv_tt("riscv32", TEST_PATH "/rv32ui-p-simple"));
CHECK( riscv_tt("riscv64", TEST_PATH "/rv64ui-p-simple"));
CHECK( riscv_tt("riscv64", TEST_PATH "/rv64uc-p-rvc"));
Expand Down
6 changes: 6 additions & 0 deletions simulator/infra/macro.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,4 +358,10 @@ static inline T gen_or_combine( T value, size_t shamt)
return value;
}

template<typename T>
static inline T trap_vector_address( T value)
{
return value >> 2U & ~(bitmask<T>( 3));
}

#endif
1 change: 1 addition & 0 deletions simulator/kernel/base_kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class BaseKernel : public Kernel
public:
void set_simulator( const std::shared_ptr<CPUModel>& s) override { sim = std::make_unique<CPUReplicant>( s); }
void connect_memory( std::shared_ptr<FuncMemory> m) override { mem = std::make_unique<FuncMemoryReplicant>( m); }
void connect_exception_handler() override { }
void add_replica_simulator( const std::shared_ptr<CPUModel>& s) override { sim->add_replica( s); }
void add_replica_memory( const std::shared_ptr<FuncMemory>& s) override { mem->add_replica( s); }
void load_file( const std::string& name) override;
Expand Down
1 change: 1 addition & 0 deletions simulator/kernel/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Kernel {

virtual void set_simulator( const std::shared_ptr<CPUModel>& s) = 0;
virtual void connect_memory( std::shared_ptr<FuncMemory> m) = 0;
virtual void connect_exception_handler() = 0;
virtual void add_replica_simulator( const std::shared_ptr<CPUModel>& s) = 0;
virtual void add_replica_memory( const std::shared_ptr<FuncMemory>& s) = 0;
virtual void load_file( const std::string& name) = 0;
Expand Down
Loading

0 comments on commit 5398b07

Please sign in to comment.