Skip to content

Commit

Permalink
E2E Simple Tests (#62)
Browse files Browse the repository at this point in the history
Adds 2 simple E2E tests:
- unsigned dwords multiplication
- bubble sort algorithm
  • Loading branch information
mmamayka authored Oct 3, 2023
1 parent ee91ab1 commit 758e13d
Show file tree
Hide file tree
Showing 16 changed files with 199 additions and 40 deletions.
1 change: 0 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,3 @@
[submodule "third_party/capstone"]
path = third_party/capstone
url = https://github.com/capstone-engine/capstone

2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.22.1)

project(BESM-666
LANGUAGES ASM CXX
LANGUAGES ASM C CXX
VERSION 1.0.0
DESCRIPTION "Pet RISCV Simulator"
)
Expand Down
41 changes: 29 additions & 12 deletions e2e_test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,40 @@ if (DEFINED BESM666__E2E_TESTS_BUILD)
target_link_options(besm666-e2eif PUBLIC
"-T" "${CMAKE_CURRENT_SOURCE_DIR}/e2e-linker.ld"
"-mcmodel=medany" "-fvisibility=hidden" "-nostdlib"
"-nostartfiles" "-march=rv64id"
"-nostartfiles" "-lgcc"
)
target_compile_options(besm666-e2eif PUBLIC
"-march=rv64id" "-O2"
)

function(besm666_e2etest_asm SOURCE_NAME)
get_filename_component(TARGET_NAME ${SOURCE_NAME} NAME_WE)
add_executable(${TARGET_NAME})
target_sources(${TARGET_NAME} PRIVATE ${SOURCE_NAME})
target_link_libraries(${TARGET_NAME} PRIVATE besm666-e2eif)
set_property(SOURCE ${SOURCE_NAME} APPEND PROPERTY COMPILE_OPTIONS
"-x" "assembler-with-cpp")
add_test(
NAME ${TARGET_NAME}
COMMAND ${CMAKE_BINARY_DIR}/../besm-666/e2e_test/besm666-a0-validator ${TARGET_NAME}
)
get_filename_component(TARGET_NAME ${SOURCE_NAME} NAME_WE)
add_executable(${TARGET_NAME})
target_sources(${TARGET_NAME} PRIVATE ${SOURCE_NAME})
target_link_libraries(${TARGET_NAME} PRIVATE besm666-e2eif)
set_property(SOURCE ${SOURCE_NAME} APPEND PROPERTY COMPILE_OPTIONS
"-x" "assembler-with-cpp")
add_test(
NAME ${TARGET_NAME}
COMMAND ${CMAKE_BINARY_DIR}/../besm-666/e2e_test/besm666-a0-validator ${TARGET_NAME}
)
endfunction(besm666_e2etest_asm)

besm666_e2etest_asm(./dummy-test.s)
function(besm666_e2etest_c SOURCE_NAME)
get_filename_component(TARGET_NAME ${SOURCE_NAME} NAME_WE)
add_executable(${TARGET_NAME})
target_sources(${TARGET_NAME} PRIVATE ${SOURCE_NAME})
target_include_directories(${TARGET_NAME} PRIVATE .)
target_link_libraries(${TARGET_NAME} PRIVATE besm666-e2eif)
add_test(
NAME ${TARGET_NAME}
COMMAND ${CMAKE_BINARY_DIR}/../besm-666/e2e_test/besm666-a0-validator ${TARGET_NAME}
)
endfunction(besm666_e2etest_c)

besm666_e2etest_asm(./mult-test.s)
besm666_e2etest_c(./bubblesort-test.c)
besm666_e2etest_c(./primenumber-test.c)
endif()

if (DEFINED BESM666__SIMULATOR_BUILD)
Expand Down
9 changes: 9 additions & 0 deletions e2e_test/bootstrap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef BESM666_E2ETEST_BOOTSTRAP_H
#define BESM666_E2ETEST_BOOTSTRAP_H

typedef unsigned long long rv64dw;

unsigned long long start();
unsigned long long do_nothing_with_value(unsigned long long);

#endif /* BESM666_E2ETEST_BOOTSTRAP_H */
1 change: 0 additions & 1 deletion e2e_test/bootstrap.s
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

.option norvc
.section ".text.init"
.global _start
Expand Down
44 changes: 44 additions & 0 deletions e2e_test/bubblesort-test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include "bootstrap.h"

rv64dw array[] = {
5, 4, 6, 8, 3, 6, 2, 7, 9, 4, 2, 5, 7, 8, 9, 4, 2, 2, 9,
5, 4, 6, 8, 3, 6, 2, 7, 9, 4, 2, 5, 7, 8, 9, 4, 2, 2, 9,
5, 4, 6, 8, 3, 6, 2, 7, 9, 4, 2, 5, 7, 8, 9, 4, 2, 2, 9,
5, 4, 6, 8, 3, 6, 2, 7, 9, 4, 2, 5, 7, 8, 9, 4, 2, 2, 9,
5, 4, 6, 8, 3, 6, 2, 7, 9, 4, 2, 5, 7, 8, 9, 4, 2, 2, 9,
5, 4, 6, 8, 3, 6, 2, 7, 9, 4, 2, 5, 7, 8, 9, 4, 2, 2, 9,
5, 4, 6, 8, 3, 6, 2, 7, 9, 4, 2, 5, 7, 8, 9, 4, 2, 2, 9,
5, 4, 6, 8, 3, 6, 2, 7, 9, 4, 2, 5, 7, 8, 9, 4, 2, 2, 9,
5, 4, 6, 8, 3, 6, 2, 7, 9, 4, 2, 5, 7, 8, 9, 4, 2, 2, 9,
5, 4, 6, 8, 3, 6, 2, 7, 9, 4, 2, 5, 7, 8, 9, 4, 2, 2, 9,
};

void bubble_sort(rv64dw* array, rv64dw size) {
rv64dw* last = array + size - 1;
for(rv64dw* i = array; i < last; ++i) {
for(rv64dw* j = i; j < last; ++j) {
rv64dw* cur = j;
rv64dw* next = j + 1;

if(*cur < *next) {
rv64dw tmp = *cur;
*cur = *next;
*next = tmp;
}
}
}
}

int validate_sort(rv64dw const* array, rv64dw size) {
for(rv64dw const* i = array; i < array + size - 1; ++i) {
if(*i < *(i + 1)) {
return 0;
}
}
return 1;
}

rv64dw start() {
bubble_sort(array, sizeof(array) / sizeof(array[0]));
return validate_sort(array, sizeof(array) / sizeof(array[0]));
}
53 changes: 53 additions & 0 deletions e2e_test/mult-test.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
.option norvc
.section .text
.global start

// multiplies two unsigned dwords
// a1 - first multiplier
// a2 - second multplier
// a0 - result
mul:
// leaf function, can reduce stack frame creation

add a0, zero, zero

.mul_loop:
andi t0, a2, 0x1
beqz t0, .mul_next
add a0, a0, a1
.mul_next:
srli a2, a2, 0x1
slli a1, a1, 0x1

bnez a2, .mul_loop

.mul_end:
jalr zero, ra, 0

start:
// creating stack frame of 8 bytes size
// to store ra register value onto the stack
addi sp, sp, -8
// store ra onto the stack
sd ra, 0(sp)

// load operands of mul function: want to get value of 15 * 8
li a1, 15
li a2, 8
call mul

li a1, 120
sub a0, a0, a1
bnez a0, .fail

.success:
li a0, 1
j .finish

.fail:
li a0, 0

.finish:
ld ra, 0(sp)
add sp, sp, 8
jalr zero, ra, 0
21 changes: 21 additions & 0 deletions e2e_test/primenumber-test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "bootstrap.h"

rv64dw __umoddi3(rv64dw value, rv64dw div) {
while(value >= div) {
value -= div;
}
return value;
}

int is_prime(rv64dw value) {
for(rv64dw i = 2; i < value / 2; ++i) {
if(value % i == 0) {
return 0;
}
}
return 1;
}

rv64dw start() {
return is_prime(1787);
}
2 changes: 2 additions & 0 deletions include/besm-666/sim/hart.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class Hart : public INonCopyable {
std::shared_ptr<HookManager> const &hookManager);

exec::GPRF const &getState() const { return exec_.getState(); }
size_t getInstrsExecuted() const { return instrsExecuted_; }

void runCycle();
bool finished() const;
Expand All @@ -34,6 +35,7 @@ class Hart : public INonCopyable {
std::shared_ptr<sim::HookManager> hookManager_;

RV64UDWord prevPC_;
size_t instrsExecuted_;
};

} // namespace besm::sim
2 changes: 2 additions & 0 deletions include/besm-666/sim/machine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class Machine : INonCopyable {
void run();

exec::GPRF const &getState() const;

size_t getInstrsExecuted() const { return hart_->getInstrsExecuted(); }
sim::HookManager::SPtr getHookManager() { return hookManager_; }

private:
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ target_include_directories(besm666_include INTERFACE
"$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
target_compile_options(besm666_include INTERFACE "-O2")
add_dependencies(besm666_include besm666_riscv_isa)

add_library(besm666_shared SHARED)
Expand Down
12 changes: 6 additions & 6 deletions src/exec/executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ void Executor::exec_JALR(Instruction const instr) {

void Executor::exec_BEQ(Instruction const instr) {
RV64UDWord pc = gprf_.read(GPRF::PC);
RV64UDWord offset = util::SignExtend<RV64UDWord, 12>(instr.immidiate) << 1;
RV64UDWord offset = util::SignExtend<RV64UDWord, 12>(instr.immidiate);
RV64UDWord opnd1 = gprf_.read(instr.rs1);
RV64UDWord opnd2 = gprf_.read(instr.rs2);

Expand All @@ -422,7 +422,7 @@ void Executor::exec_BEQ(Instruction const instr) {

void Executor::exec_BNE(Instruction const instr) {
RV64UDWord pc = gprf_.read(GPRF::PC);
RV64UDWord offset = util::SignExtend<RV64UDWord, 12>(instr.immidiate) << 1;
RV64UDWord offset = util::SignExtend<RV64UDWord, 12>(instr.immidiate);
RV64UDWord opnd1 = gprf_.read(instr.rs1);
RV64UDWord opnd2 = gprf_.read(instr.rs2);

Expand All @@ -436,7 +436,7 @@ void Executor::exec_BNE(Instruction const instr) {

void Executor::exec_BLT(Instruction const instr) {
RV64UDWord pc = gprf_.read(GPRF::PC);
RV64UDWord offset = util::SignExtend<RV64UDWord, 12>(instr.immidiate) << 1;
RV64UDWord offset = util::SignExtend<RV64UDWord, 12>(instr.immidiate);
RV64DWord opnd1 = util::Signify(gprf_.read(instr.rs1));
RV64DWord opnd2 = util::Signify(gprf_.read(instr.rs2));

Expand All @@ -450,7 +450,7 @@ void Executor::exec_BLT(Instruction const instr) {

void Executor::exec_BLTU(Instruction const instr) {
RV64UDWord pc = gprf_.read(GPRF::PC);
RV64UDWord offset = util::SignExtend<RV64UDWord, 12>(instr.immidiate) << 1;
RV64UDWord offset = util::SignExtend<RV64UDWord, 12>(instr.immidiate);
RV64UDWord opnd1 = gprf_.read(instr.rs1);
RV64UDWord opnd2 = gprf_.read(instr.rs2);

Expand All @@ -464,7 +464,7 @@ void Executor::exec_BLTU(Instruction const instr) {

void Executor::exec_BGE(Instruction const instr) {
RV64UDWord pc = gprf_.read(GPRF::PC);
RV64UDWord offset = util::SignExtend<RV64UDWord, 12>(instr.immidiate) << 1;
RV64UDWord offset = util::SignExtend<RV64UDWord, 12>(instr.immidiate);
RV64DWord opnd1 = util::Signify(gprf_.read(instr.rs1));
RV64DWord opnd2 = util::Signify(gprf_.read(instr.rs2));

Expand All @@ -478,7 +478,7 @@ void Executor::exec_BGE(Instruction const instr) {

void Executor::exec_BGEU(Instruction const instr) {
RV64UDWord pc = gprf_.read(GPRF::PC);
RV64UDWord offset = util::SignExtend<RV64UDWord, 12>(instr.immidiate) << 1;
RV64UDWord offset = util::SignExtend<RV64UDWord, 12>(instr.immidiate);
RV64UDWord opnd1 = gprf_.read(instr.rs1);
RV64UDWord opnd2 = gprf_.read(instr.rs2);

Expand Down
3 changes: 2 additions & 1 deletion src/sim/hart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Hart::SPtr Hart::Create(mem::PhysMem::SPtr pMem,
Hart::Hart(mem::PhysMem::SPtr pMem,
std::shared_ptr<HookManager> const &hookManager)
: mmu_(mem::MMU::Create(pMem)), exec_(mmu_), hookManager_(hookManager),
prevPC_(std::numeric_limits<RV64UDWord>::max()) {}
prevPC_(std::numeric_limits<RV64UDWord>::max()), instrsExecuted_(0) {}

void Hart::runCycle() {
RV64UDWord pc = exec_.getState().read(exec::GPRF::PC);
Expand All @@ -38,6 +38,7 @@ void Hart::runCycle() {
exec_.exec(instr);
hookManager_->triggerHooks(HookManager::INSTRUCTION_EXECUTE, *this,
nullptr);
++instrsExecuted_;
}

bool Hart::finished() const {
Expand Down
25 changes: 18 additions & 7 deletions standalone/main.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <chrono>
#include <cstdlib>
#include <iostream>

Expand Down Expand Up @@ -29,7 +30,8 @@ void InitVerboseLogging(besm::sim::Machine &machine) {
besm::RV64UWord bytecode =
*reinterpret_cast<besm::RV64UWord const *>(pBytecode);
std::clog << "[BESM-666] VERBOSE: Fetched bytecode " << std::hex
<< bytecode << std::dec << " at pc = " << pc << std::endl;
<< bytecode << std::dec << " at pc = " << std::hex << pc
<< std::dec << std::endl;

cs_insn *instruction;
size_t count = cs_disasm(
Expand Down Expand Up @@ -81,22 +83,31 @@ int main(int argc, char *argv[]) {

besm::sim::Config config = configBuilder.build();
besm::sim::Machine machine(config);

std::clog << "[BESM-666] INFO: Created RISCV machine." << std::endl;

if (verboseLogging) {
InitVerboseLogging(machine);
}

std::clog << "[BESM-666] INFO: Starting simulation" << std::endl;

auto time_start = std::chrono::steady_clock::now();
machine.run();
std::clog << "[BESM-666] Simulation finished. Machine state is"
<< std::endl;
auto time_end = std::chrono::steady_clock::now();

besm::exec::GPRFStateDumper(std::clog).dump(machine.getState());
double ellapsedSecond =
std::chrono::duration_cast<std::chrono::nanoseconds>(time_end -
time_start)
.count() *
1e-9;

size_t instrsExecuted = machine.getInstrsExecuted();

double mips = static_cast<double>(instrsExecuted) * 1e-6 / ellapsedSecond;

std::clog << "[BESM-666] Simulation finished. Machine state is"
<< std::endl;
std::clog << "[BESM-666] Simulation finished." << std::endl;
std::clog << "[BESM-666] Time = " << ellapsedSecond << "s, Insns "
<< instrsExecuted << ", MIPS = " << mips << std::endl;
besm::exec::GPRFStateDumper(std::clog).dump(machine.getState());

return 0;
Expand Down
Loading

0 comments on commit 758e13d

Please sign in to comment.