From a90632108d257a0cbe05269e503e2cb4377f4a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chaine?= Date: Sun, 28 Apr 2024 07:55:41 +0000 Subject: [PATCH 1/9] Adds riscv-tests binary generation to the build system --- CMakeLists.txt | 4 ++ cmake/riscv.cmake | 83 ++++++++++++++++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/riscv-tests/CMakeLists.txt | 73 ++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+) create mode 100644 cmake/riscv.cmake create mode 100644 tests/riscv-tests/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 484edf5..48b2563 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,10 @@ add_dependency(ECAP5_DTLIB GIT ecap5/ecap5-dtlib TAG 2-implement-an-instrumented-wishbone-slave) +add_dependency(riscv-tests + GIT ecap5/riscv-tests + TAG master) + # Configure dependencies include(${CMAKE_CURRENT_LIST_DIR}/cmake/ecap5-treq.cmake) diff --git a/cmake/riscv.cmake b/cmake/riscv.cmake new file mode 100644 index 0000000..f04e1a3 --- /dev/null +++ b/cmake/riscv.cmake @@ -0,0 +1,83 @@ +#include(CMakeForceCompiler) + +# usage +# cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/rv32imac.cmake ../ + +# Look for GCC in path +# https://xpack.github.io/riscv-none-embed-gcc/ +FIND_FILE( RISCV_XPACK_GCC_COMPILER_EXE "riscv-none-embed-gcc.exe" PATHS ENV INCLUDE) +FIND_FILE( RISCV_XPACK_GCC_COMPILER "riscv-none-embed-gcc" PATHS ENV INCLUDE) +# New versions of xpack +FIND_FILE( RISCV_XPACK_NEW_GCC_COMPILER_EXE "riscv-none-elf-gcc.exe" PATHS ENV INCLUDE) +FIND_FILE( RISCV_XPACK_NEW_GCC_COMPILER "riscv-none-elf-gcc" PATHS ENV INCLUDE) + +# Look for RISC-V github GCC +# https://github.com/riscv/riscv-gnu-toolchain +FIND_FILE( RISCV_XPACK_GCC_COMPILER_EXT "riscv32-unknown-elf-gcc.exe" PATHS ENV INCLUDE) +FIND_FILE( RISCV_XPACK_GCC_COMPILER "riscv32-unknown-elf-gcc" PATHS ENV INCLUDE) + +# Select which is found +if (EXISTS ${RISCV_XPACK_NEW_GCC_COMPILER}) +set( RISCV_GCC_COMPILER ${RISCV_XPACK_NEW_GCC_COMPILER}) +elseif (EXISTS ${RISCV_XPACK_GCC_NEW_COMPILER_EXE}) +set( RISCV_GCC_COMPILER ${RISCV_XPACK_NEW_GCC_COMPILER_EXE}) +elseif (EXISTS ${RISCV_XPACK_GCC_COMPILER}) +set( RISCV_GCC_COMPILER ${RISCV_XPACK_GCC_COMPILER}) +elseif (EXISTS ${RISCV_XPACK_GCC_COMPILER_EXE}) +set( RISCV_GCC_COMPILER ${RISCV_XPACK_GCC_COMPILER_EXE}) +elseif (EXISTS ${RISCV_GITHUB_GCC_COMPILER}) +set( RISCV_GCC_COMPILER ${RISCV_GITHUB_GCC_COMPILER}) +elseif (EXISTS ${RISCV_GITHUB_GCC_COMPILER_EXE}) +set( RISCV_GCC_COMPILER ${RISCV_GITHUB_GCC_COMPILER_EXE}) +else() +message(FATAL_ERROR "RISC-V GCC not found. ${RISCV_GITHUB_GCC_COMPILER} ${RISCV_XPACK_GCC_COMPILER} ${RISCV_GITHUB_GCC_COMPILER_EXE} ${RISCV_XPACK_GCC_COMPILER_EXE}") +endif() + +message(STATUS "RISC-V GCC found: ${RISCV_GCC_COMPILER}") + +get_filename_component(RISCV_TOOLCHAIN_BIN_PATH ${RISCV_GCC_COMPILER} DIRECTORY) +get_filename_component(RISCV_TOOLCHAIN_BIN_GCC ${RISCV_GCC_COMPILER} NAME_WE) +get_filename_component(RISCV_TOOLCHAIN_BIN_EXT ${RISCV_GCC_COMPILER} EXT) + +message(STATUS "RISC-V GCC Path: ${RISCV_TOOLCHAIN_BIN_PATH}" ) + +STRING(REGEX REPLACE "\-gcc" "-" CROSS_COMPILE ${RISCV_TOOLCHAIN_BIN_GCC}) +message(STATUS "RISC-V Cross Compile: ${CROSS_COMPILE}" ) + +# The Generic system name is used for embedded targets (targets without OS) in +# CMake +set( CMAKE_SYSTEM_NAME Generic ) +set( CMAKE_SYSTEM_PROCESSOR rv32imac_zicsr ) +set( CMAKE_EXECUTABLE_SUFFIX ".elf") + +# specify the cross compiler. We force the compiler so that CMake doesn't +# attempt to build a simple test program as this will fail without us using +# the -nostartfiles option on the command line +#CMAKE_FORCE_C_COMPILER( "${RISCV_TOOLCHAIN_BIN_PATH}/${CROSS_COMPILE}gcc${RISCV_TOOLCHAIN_BIN_EXT}" GNU ) +#CMAKE_FORCE_CXX_COMPILER( "${RISCV_TOOLCHAIN_BIN_PATH}/${CROSS_COMPILE}g++${RISCV_TOOLCHAIN_BIN_EXT}" GNU ) +set(CMAKE_ASM_COMPILER {CROSS_COMPILE}gcc ) +set(CMAKE_AR ${CROSS_COMPILE}ar) +set(CMAKE_ASM_COMPILER ${CROSS_COMPILE}gcc) +set(CMAKE_C_COMPILER ${CROSS_COMPILE}gcc) +set(CMAKE_CXX_COMPILER ${CROSS_COMPILE}g++) + +# We must set the OBJCOPY setting into cache so that it's available to the +# whole project. Otherwise, this does not get set into the CACHE and therefore +# the build doesn't know what the OBJCOPY filepath is +set( CMAKE_OBJCOPY ${RISCV_TOOLCHAIN_BIN_PATH}/${CROSS_COMPILE}objcopy + CACHE FILEPATH "The toolchain objcopy command " FORCE ) + +set( CMAKE_OBJDUMP ${RISCV_TOOLCHAIN_BIN_PATH}/${CROSS_COMPILE}objdump + CACHE FILEPATH "The toolchain objdump command " FORCE ) + +# Set the common build flags + +# Set the CMAKE C flags (which should also be used by the assembler! +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g" ) +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=${CMAKE_SYSTEM_PROCESSOR}" ) + +set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "" ) +set( CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "" ) +set( CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "" ) +set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -march=${CMAKE_SYSTEM_PROCESSOR} -nostartfiles " ) + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c274e0a..dee1a99 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -114,3 +114,4 @@ add_testbench(ecap5_dproc PUBLIC) add_custom_target(build DEPENDS ${TEST_BINARIES}) add_custom_target(tests DEPENDS ${TEST_TARGETS}) +add_subdirectory(riscv-tests) diff --git a/tests/riscv-tests/CMakeLists.txt b/tests/riscv-tests/CMakeLists.txt new file mode 100644 index 0000000..bda5153 --- /dev/null +++ b/tests/riscv-tests/CMakeLists.txt @@ -0,0 +1,73 @@ +# __ _ +# ________/ / ___ _(_)__ ___ +# / __/ __/ _ \/ _ `/ / _ \/ -_) +# \__/\__/_//_/\_,_/_/_//_/\__/ +# +# Copyright (C) Clément Chain +# This file is part of ECAP5-DPROC +# +# ECAP5-DPROC is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ECAP5-DPROC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ECAP5-DPROC. If not, see . + +include(${CMAKE_SOURCE_DIR}/cmake/riscv.cmake) + +enable_language(ASM) + +set(TVM rv32ui) # Target Virtual Machine +set(TE p) # Target Environment + +# Paths +set(SOURCE_DIR ${riscv_tests_SOURCE_DIR}/isa/${TVM}/) +set(ENV_DIR ${riscv_tests_SOURCE_DIR}/env/${TE}/) +set(INCLUDE_DIRS ${ENV_DIR} + ${riscv_tests_SOURCE_DIR}/isa/macros/scalar) + +# Compile options +set(CC_OPTS -static + -mcmodel=medany + -fvisibility=hidden + -nostdlib + -nostartfiles) + +set(TARGETS simple + add addi + and andi + auipc + beq bge bgeu blt bltu bne + fence_i + jal jalr + lb lbu lh lhu lw + lui + ma_data + or ori + sb sh sw + sll slli + slt slti + sltiu sltu + sra srai + srl srli + sub + xor xori) + +set(ALL_TARGETS) +foreach(TARGET IN LISTS TARGETS) + set(FULL_TARGET ${TVM}-${TE}-${TARGET}) + add_executable(${FULL_TARGET} ${SOURCE_DIR}/${TARGET}.S) + add_compile_options(${CC_OPTS} -march=rv32g -mabi=ilp32) + target_include_directories(${FULL_TARGET} PRIVATE ${INCLUDE_DIRS}) + target_link_options(${FULL_TARGET} PRIVATE -T${ENV_DIR}/link.ld) + + list(APPEND ALL_TARGETS ${FULL_TARGET}) +endforeach() + +add_custom_target(riscv-tests DEPENDS ${ALL_TARGETS}) From 1af2f692977913efaa08ac229df351c482233b14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chaine?= Date: Sun, 28 Apr 2024 16:31:55 +0000 Subject: [PATCH 2/9] Starts implementing an elf loader --- cmake/riscv.cmake | 1 - tests/CMakeLists.txt | 19 +++ tests/riscv-tests/CMakeLists.txt | 16 ++- tests/riscv-tests/env/link.ld | 17 +++ tests/riscv-tests/env/riscv_test.h | 217 +++++++++++++++++++++++++++++ tests/riscv-tests/riscv-tests.cpp | 173 +++++++++++++++++++++++ 6 files changed, 437 insertions(+), 6 deletions(-) create mode 100644 tests/riscv-tests/env/link.ld create mode 100644 tests/riscv-tests/env/riscv_test.h create mode 100644 tests/riscv-tests/riscv-tests.cpp diff --git a/cmake/riscv.cmake b/cmake/riscv.cmake index f04e1a3..0006c0f 100644 --- a/cmake/riscv.cmake +++ b/cmake/riscv.cmake @@ -48,7 +48,6 @@ message(STATUS "RISC-V Cross Compile: ${CROSS_COMPILE}" ) # CMake set( CMAKE_SYSTEM_NAME Generic ) set( CMAKE_SYSTEM_PROCESSOR rv32imac_zicsr ) -set( CMAKE_EXECUTABLE_SUFFIX ".elf") # specify the cross compiler. We force the compiler so that CMake doesn't # attempt to build a simple test program as this will fail without us using diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index dee1a99..a79559a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -115,3 +115,22 @@ add_custom_target(build DEPENDS ${TEST_BINARIES}) add_custom_target(tests DEPENDS ${TEST_TARGETS}) add_subdirectory(riscv-tests) +add_executable(riscv-tests-executable ${CMAKE_CURRENT_SOURCE_DIR}/riscv-tests/riscv-tests.cpp) +add_dependencies(riscv-tests-executable riscv-tests-binaries) +target_include_directories(riscv-tests-executable PRIVATE ${TEST_INCLUDE_DIR}) +verilate(riscv-tests-executable + PREFIX Vecap5_dproc + SOURCES ${SV_HEADERS} + ${SRC_DIR}/ecap5_dproc.sv + INCLUDE_DIRS ${SRC_DIR} + TRACE) +get_target_property(RISCV_TESTS_EXECUTABLE riscv-tests-executable BINARY_DIR) +if(${DEBUGLOG}) + set(RUN_TARGET_ARGUMENT "-v") +endif() +add_custom_command( + COMMAND ${RISCV_TESTS_EXECUTABLE}/riscv-tests-executable ${RUN_TARGET_ARGUMENT} + OUTPUT ${TESTDATA_DIR}/riscv-tests.csv + DEPENDS riscv-tests-executable + WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}) +add_custom_target(riscv-tests DEPENDS ${TESTDATA_DIR}/riscv-tests.csv) diff --git a/tests/riscv-tests/CMakeLists.txt b/tests/riscv-tests/CMakeLists.txt index bda5153..c3e8722 100644 --- a/tests/riscv-tests/CMakeLists.txt +++ b/tests/riscv-tests/CMakeLists.txt @@ -28,9 +28,7 @@ set(TE p) # Target Environment # Paths set(SOURCE_DIR ${riscv_tests_SOURCE_DIR}/isa/${TVM}/) -set(ENV_DIR ${riscv_tests_SOURCE_DIR}/env/${TE}/) -set(INCLUDE_DIRS ${ENV_DIR} - ${riscv_tests_SOURCE_DIR}/isa/macros/scalar) +set(ENV_DIR ${CMAKE_CURRENT_SOURCE_DIR}/env/) # Compile options set(CC_OPTS -static @@ -38,6 +36,9 @@ set(CC_OPTS -static -fvisibility=hidden -nostdlib -nostartfiles) +set(CC_INCS ${riscv_tests_SOURCE_DIR}/env + ${ENV_DIR} + ${riscv_tests_SOURCE_DIR}/isa/macros/scalar) set(TARGETS simple add addi @@ -64,10 +65,15 @@ foreach(TARGET IN LISTS TARGETS) set(FULL_TARGET ${TVM}-${TE}-${TARGET}) add_executable(${FULL_TARGET} ${SOURCE_DIR}/${TARGET}.S) add_compile_options(${CC_OPTS} -march=rv32g -mabi=ilp32) - target_include_directories(${FULL_TARGET} PRIVATE ${INCLUDE_DIRS}) + target_include_directories(${FULL_TARGET} PRIVATE ${CC_INCS}) target_link_options(${FULL_TARGET} PRIVATE -T${ENV_DIR}/link.ld) list(APPEND ALL_TARGETS ${FULL_TARGET}) endforeach() -add_custom_target(riscv-tests DEPENDS ${ALL_TARGETS}) +add_custom_target(riscv-tests-binaries DEPENDS ${ALL_TARGETS}) + +# Generate simulation executable + +set(TEST_INCLUDE_DIR ${ecap5_dtlib_SOURCE_DIR}/include) +set(SV_HEADERS ${SRC_DIR}/include/ecap5_dproc_pkg.svh) diff --git a/tests/riscv-tests/env/link.ld b/tests/riscv-tests/env/link.ld new file mode 100644 index 0000000..c6efc56 --- /dev/null +++ b/tests/riscv-tests/env/link.ld @@ -0,0 +1,17 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +SECTIONS +{ + . = 0x0; + .text.init : { *(.text.init) } + . = ALIGN(0x1000); + .tohost : { *(.tohost) } + . = ALIGN(0x1000); + .text : { *(.text) } + . = ALIGN(0x1000); + .data : { *(.data) } + .bss : { *(.bss) } + _end = .; +} + diff --git a/tests/riscv-tests/env/riscv_test.h b/tests/riscv-tests/env/riscv_test.h new file mode 100644 index 0000000..bbb5a1a --- /dev/null +++ b/tests/riscv-tests/env/riscv_test.h @@ -0,0 +1,217 @@ +// See LICENSE for license details. + +#ifndef _ENV_PHYSICAL_SINGLE_CORE_H +#define _ENV_PHYSICAL_SINGLE_CORE_H + +#include "encoding.h" + +//----------------------------------------------------------------------- +// Begin Macro +//----------------------------------------------------------------------- + +#define RVTEST_RV64U \ + .macro init; \ + .endm + +#define RVTEST_RV64UF \ + .macro init; \ + RVTEST_FP_ENABLE; \ + .endm + +#define RVTEST_RV64UV \ + .macro init; \ + RVTEST_VECTOR_ENABLE; \ + .endm + +#define RVTEST_RV32U \ + .macro init; \ + .endm + +#define RVTEST_RV32UF \ + .macro init; \ + RVTEST_FP_ENABLE; \ + .endm + +#define RVTEST_RV32UV \ + .macro init; \ + RVTEST_VECTOR_ENABLE; \ + .endm + +#define RVTEST_RV64M \ + .macro init; \ + RVTEST_ENABLE_MACHINE; \ + .endm + +#define RVTEST_RV64S \ + .macro init; \ + RVTEST_ENABLE_SUPERVISOR; \ + .endm + +#define RVTEST_RV32M \ + .macro init; \ + RVTEST_ENABLE_MACHINE; \ + .endm + +#define RVTEST_RV32S \ + .macro init; \ + RVTEST_ENABLE_SUPERVISOR; \ + .endm + +#if __riscv_xlen == 64 +# define CHECK_XLEN li a0, 1; slli a0, a0, 31; bgez a0, 1f; RVTEST_PASS; 1: +#else +# define CHECK_XLEN li a0, 1; slli a0, a0, 31; bltz a0, 1f; RVTEST_PASS; 1: +#endif + +#define INIT_XREG \ + li x1, 0; \ + li x2, 0; \ + li x3, 0; \ + li x4, 0; \ + li x5, 0; \ + li x6, 0; \ + li x7, 0; \ + li x8, 0; \ + li x9, 0; \ + li x10, 0; \ + li x11, 0; \ + li x12, 0; \ + li x13, 0; \ + li x14, 0; \ + li x15, 0; \ + li x16, 0; \ + li x17, 0; \ + li x18, 0; \ + li x19, 0; \ + li x20, 0; \ + li x21, 0; \ + li x22, 0; \ + li x23, 0; \ + li x24, 0; \ + li x25, 0; \ + li x26, 0; \ + li x27, 0; \ + li x28, 0; \ + li x29, 0; \ + li x30, 0; \ + li x31, 0; + +#define INIT_PMP \ + la t0, 1f; \ + csrw mtvec, t0; \ + /* Set up a PMP to permit all accesses */ \ + li t0, (1 << (31 + (__riscv_xlen / 64) * (53 - 31))) - 1; \ + csrw pmpaddr0, t0; \ + li t0, PMP_NAPOT | PMP_R | PMP_W | PMP_X; \ + csrw pmpcfg0, t0; \ + .align 2; \ +1: + +#define INIT_RNMI \ + la t0, 1f; \ + csrw mtvec, t0; \ + csrwi CSR_MNSTATUS, MNSTATUS_NMIE; \ + .align 2; \ +1: + +#define INIT_SATP \ + la t0, 1f; \ + csrw mtvec, t0; \ + csrwi satp, 0; \ + .align 2; \ +1: + +#define DELEGATE_NO_TRAPS \ + csrwi mie, 0; \ + la t0, 1f; \ + csrw mtvec, t0; \ + csrwi medeleg, 0; \ + csrwi mideleg, 0; \ + .align 2; \ +1: + +#define RVTEST_ENABLE_SUPERVISOR \ + li a0, MSTATUS_MPP & (MSTATUS_MPP >> 1); \ + csrs mstatus, a0; \ + li a0, SIP_SSIP | SIP_STIP; \ + csrs mideleg, a0; \ + +#define RVTEST_ENABLE_MACHINE \ + li a0, MSTATUS_MPP; \ + csrs mstatus, a0; \ + +#define RVTEST_FP_ENABLE \ + li a0, MSTATUS_FS & (MSTATUS_FS >> 1); \ + csrs mstatus, a0; \ + csrwi fcsr, 0 + +#define RVTEST_VECTOR_ENABLE \ + li a0, (MSTATUS_VS & (MSTATUS_VS >> 1)) | \ + (MSTATUS_FS & (MSTATUS_FS >> 1)); \ + csrs mstatus, a0; \ + csrwi fcsr, 0; \ + csrwi vcsr, 0; + +#define RISCV_MULTICORE_DISABLE \ + csrr a0, mhartid; \ + 1: bnez a0, 1b + +#define EXTRA_TVEC_USER +#define EXTRA_TVEC_MACHINE +#define EXTRA_INIT +#define EXTRA_INIT_TIMER +#define FILTER_TRAP +#define FILTER_PAGE_FAULT + +#define INTERRUPT_HANDLER j other_exception /* No interrupts should occur */ + +#define RVTEST_CODE_BEGIN \ + .section .text.init; \ + .align 6; \ + .weak stvec_handler; \ + .weak mtvec_handler; \ + .globl _start; \ +_start: \ + INIT_XREG; \ + li TESTNUM, 0; \ + CHECK_XLEN; \ + init; \ + EXTRA_INIT; \ + EXTRA_INIT_TIMER; + +//----------------------------------------------------------------------- +// End Macro +//----------------------------------------------------------------------- + +#define RVTEST_CODE_END \ + unimp + +//----------------------------------------------------------------------- +// Pass/Fail Macro +//----------------------------------------------------------------------- + +#define TESTNUM gp + +#define RVTEST_PASS \ + li TESTNUM, 1; \ + +#define RVTEST_FAIL \ + li TESTNUM, 0; + +//----------------------------------------------------------------------- +// Data Section Macro +//----------------------------------------------------------------------- + +#define EXTRA_DATA + +#define RVTEST_DATA_BEGIN \ + EXTRA_DATA \ + .pushsection .tohost,"aw",@progbits; \ + .align 6; .global tohost; tohost: .dword 0; .size tohost, 8; \ + .align 6; .global fromhost; fromhost: .dword 0; .size fromhost, 8;\ + .popsection; \ + .align 4; .global begin_signature; begin_signature: + +#define RVTEST_DATA_END .align 4; .global end_signature; end_signature: + +#endif diff --git a/tests/riscv-tests/riscv-tests.cpp b/tests/riscv-tests/riscv-tests.cpp new file mode 100644 index 0000000..31e5cb3 --- /dev/null +++ b/tests/riscv-tests/riscv-tests.cpp @@ -0,0 +1,173 @@ +/* __ _ + * ________/ / ___ _(_)__ ___ + * / __/ __/ _ \/ _ `/ / _ \/ -_) + * \__/\__/_//_/\_,_/_/_//_/\__/ + * + * Copyright (C) Clément Chaine + * This file is part of ECAP5-DPROC + * + * ECAP5-DPROC is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ECAP5-DPROC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ECAP5-DPROC. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "Vecap5_dproc_ecap5_dproc_pkg.h" +#include "Vecap5_dproc.h" +#include "testbench.h" + +#define MAX_BINARY_SIZE 1024 + +class TB_Riscv_tests: public Testbench { +public: + uint8_t memory[MAX_BINARY_SIZE]; + + void reset() { + this->core->rst_i = 1; + for(int i = 0; i < 5; i++) { + this->tick(); + } + this->core->rst_i = 0; + + Testbench::reset(); + + // Clear memory + memset(memory, 0, MAX_BINARY_SIZE); + } + + void set_memory(std::string path) { + memset(memory, 0, MAX_BINARY_SIZE); + this->load_elf(path, memory); + } + + void dump_memory() { + char ascii[17]; + int i, j; + ascii[16] = '\0'; + printf("%08x: ", 0); + for (i = 0; i < MAX_BINARY_SIZE; ++i) { + printf("%02X", ((unsigned char*)this->memory)[i]); + if(i % 2 == 1) { + printf(" "); + } + if (((unsigned char*)this->memory)[i] >= ' ' && ((unsigned char*)this->memory)[i] <= '~') { + ascii[i % 16] = ((unsigned char*)this->memory)[i]; + } else { + ascii[i % 16] = '.'; + } + if ((i+1) % 8 == 0 || i+1 == MAX_BINARY_SIZE) { + if ((i+1) % 16 == 0) { + printf(" %s \n", ascii); + if(i+1 < MAX_BINARY_SIZE) { + printf("%08x: ", i); + } + } else if (i+1 == MAX_BINARY_SIZE) { + ascii[(i+1) % 16] = '\0'; + if ((i+1) % 16 <= 8) { + printf(" "); + } + for (j = (i+1) % 16; j < 16; ++j) { + printf(" "); + } + printf(" %s \n", ascii); + } + } + } + } + + void load_elf(std::string path, void * buffer) { + FILE * fd = fopen(path.c_str(), "rb"); + if(fd == NULL) { + printf("Couldn't find elf file at path %s\n", path.c_str()); + return; + } + + // Check elf magic + uint8_t magic = 0; + fread(&magic, 1, 1, fd); + if(magic != 0x7F) { + printf("The file %s is not an elf binary\n", path.c_str()); + return; + } + + // Read elf header and find elf program header + uint32_t ph_offset = 0; + fseek(fd, 28, SEEK_SET); + fread(&ph_offset, 4, 1, fd); + + // Find the number of program segments + uint16_t ph_entry_size = 0; + uint16_t ph_num_entries = 0; + fseek(fd, 42, SEEK_SET); + fread(&ph_entry_size, 2, 1, fd); + fseek(fd, 44, SEEK_SET); + fread(&ph_num_entries, 2, 1, fd); + + // For each segment, copy the data to the provided buffer + for(int i = 0; i < ph_num_netries; i++) { + uint32_t p_type = 0; + fseek(fd, ph_offset + ph_entry_size * i, SEEK_SET); + + uint32_t p_offset = 0; + uint32_t p_vaddr = 0; + uint32_t p_filesz = 0; + uint32_t p_memsz = 0; + } + + + fclose(fd); + } +}; + +void tb_riscv_tests_simple(TB_Riscv_tests * tb) { + Vecap5_dproc * core = tb->core; + tb->reset(); + +// tb->dump_memory(); + tb->set_memory("riscv-tests/rv32ui-p-simple"); +// tb->dump_memory(); +} + +int main(int argc, char ** argv, char ** env) { + srand(time(NULL)); + Verilated::traceEverOn(true); + + // Check arguments + bool verbose = parse_verbose(argc, argv); + + TB_Riscv_tests * tb = new TB_Riscv_tests(); + tb->open_trace("waves/riscv-tests.vcd"); + tb->open_testdata("testdata/riscv-tests.csv"); + tb->set_debug_log(verbose); + + /************************************************************/ + + tb_riscv_tests_simple(tb); + + /************************************************************/ + + printf("[RISCV-TESTS]: "); + if(tb->success) { + printf("Done\n"); + } else { + printf("Failed\n"); + } + + delete tb; + exit(EXIT_SUCCESS); +} From 72b6f3395dbb557d6e61ee93acceb336dbbd4384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chaine?= Date: Mon, 29 Apr 2024 15:55:06 +0000 Subject: [PATCH 3/9] Finishes the elf parser --- tests/riscv-tests/riscv-tests.cpp | 49 ++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/tests/riscv-tests/riscv-tests.cpp b/tests/riscv-tests/riscv-tests.cpp index 31e5cb3..4926e9d 100644 --- a/tests/riscv-tests/riscv-tests.cpp +++ b/tests/riscv-tests/riscv-tests.cpp @@ -31,7 +31,8 @@ #include "Vecap5_dproc.h" #include "testbench.h" -#define MAX_BINARY_SIZE 1024 +#define KO * 1024 +#define MAX_BINARY_SIZE (32 KO) class TB_Riscv_tests: public Testbench { public: @@ -55,12 +56,16 @@ class TB_Riscv_tests: public Testbench { this->load_elf(path, memory); } - void dump_memory() { + void dump_memory(uint32_t size) { + if(size > MAX_BINARY_SIZE) { + size = MAX_BINARY_SIZE; + } + char ascii[17]; int i, j; ascii[16] = '\0'; printf("%08x: ", 0); - for (i = 0; i < MAX_BINARY_SIZE; ++i) { + for (i = 0; i < size; ++i) { printf("%02X", ((unsigned char*)this->memory)[i]); if(i % 2 == 1) { printf(" "); @@ -70,13 +75,13 @@ class TB_Riscv_tests: public Testbench { } else { ascii[i % 16] = '.'; } - if ((i+1) % 8 == 0 || i+1 == MAX_BINARY_SIZE) { + if ((i+1) % 8 == 0 || i+1 == size) { if ((i+1) % 16 == 0) { printf(" %s \n", ascii); - if(i+1 < MAX_BINARY_SIZE) { + if(i+1 < size) { printf("%08x: ", i); } - } else if (i+1 == MAX_BINARY_SIZE) { + } else if (i+1 == size) { ascii[(i+1) % 16] = '\0'; if ((i+1) % 16 <= 8) { printf(" "); @@ -119,16 +124,40 @@ class TB_Riscv_tests: public Testbench { fread(&ph_num_entries, 2, 1, fd); // For each segment, copy the data to the provided buffer - for(int i = 0; i < ph_num_netries; i++) { + for(int i = 0; i < ph_num_entries; i++) { uint32_t p_type = 0; fseek(fd, ph_offset + ph_entry_size * i, SEEK_SET); + fread(&p_type, 4, 1, fd); uint32_t p_offset = 0; + fseek(fd, ph_offset + ph_entry_size * i + 4, SEEK_SET); + fread(&p_offset, 4, 1, fd); + uint32_t p_vaddr = 0; + fseek(fd, ph_offset + ph_entry_size * i + 8, SEEK_SET); + fread(&p_vaddr, 4, 1, fd); + uint32_t p_filesz = 0; + fseek(fd, ph_offset + ph_entry_size * i + 16, SEEK_SET); + fread(&p_filesz, 4, 1, fd); + uint32_t p_memsz = 0; - } + fseek(fd, ph_offset + ph_entry_size * i + 20, SEEK_SET); + fread(&p_memsz, 4, 1, fd); + + // If it is a LOAD segment + if(p_type == 1) { + // Check if bigger than the memory size + if(p_vaddr + p_memsz > MAX_BINARY_SIZE) { + printf("Memory overflow with segment %d when loading binary %s\n Memory end address : %08x, Segment end address: %08x\n\n", i, path.c_str(), MAX_BINARY_SIZE-1, p_vaddr + p_memsz - 1); + return; + } + // Copy the segment data + fseek(fd, p_offset, SEEK_SET); + fread(memory + p_vaddr, 1, p_filesz, fd); + } + } fclose(fd); } @@ -138,9 +167,9 @@ void tb_riscv_tests_simple(TB_Riscv_tests * tb) { Vecap5_dproc * core = tb->core; tb->reset(); -// tb->dump_memory(); + tb->dump_memory(1024); tb->set_memory("riscv-tests/rv32ui-p-simple"); -// tb->dump_memory(); + tb->dump_memory(1024); } int main(int argc, char ** argv, char ** env) { From d7bed84b2fd0f766b06bcbec10acfa0c4f54bf31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chaine?= Date: Wed, 1 May 2024 15:28:16 +0000 Subject: [PATCH 4/9] Fixes cmake build following update to cmake in the development environment --- cmake/FindSphinx.cmake | 2 +- cmake/riscv.cmake | 17 ++--------------- tests/riscv-tests/CMakeLists.txt | 21 +++++++++++++-------- 3 files changed, 16 insertions(+), 24 deletions(-) diff --git a/cmake/FindSphinx.cmake b/cmake/FindSphinx.cmake index 41d0b19..04f5d78 100644 --- a/cmake/FindSphinx.cmake +++ b/cmake/FindSphinx.cmake @@ -1,6 +1,6 @@ include(FindPackageHandleStandardArgs) -find_package(PythonInterp) +find_package(Python3) if(PYTHONINTERP_FOUND) get_filename_component(_PYTHON_DIR "${PYTHON_EXECUTABLE}" DIRECTORY) set( diff --git a/cmake/riscv.cmake b/cmake/riscv.cmake index 0006c0f..fade172 100644 --- a/cmake/riscv.cmake +++ b/cmake/riscv.cmake @@ -13,8 +13,8 @@ FIND_FILE( RISCV_XPACK_NEW_GCC_COMPILER "riscv-none-elf-gcc" PATHS ENV INCLUDE) # Look for RISC-V github GCC # https://github.com/riscv/riscv-gnu-toolchain -FIND_FILE( RISCV_XPACK_GCC_COMPILER_EXT "riscv32-unknown-elf-gcc.exe" PATHS ENV INCLUDE) -FIND_FILE( RISCV_XPACK_GCC_COMPILER "riscv32-unknown-elf-gcc" PATHS ENV INCLUDE) +FIND_FILE( RISCV_XPACK_GCC_COMPILER_EXT "riscv64-unknown-elf-gcc.exe" PATHS ENV INCLUDE) +FIND_FILE( RISCV_XPACK_GCC_COMPILER "riscv64-unknown-elf-gcc" PATHS ENV INCLUDE) # Select which is found if (EXISTS ${RISCV_XPACK_NEW_GCC_COMPILER}) @@ -47,7 +47,6 @@ message(STATUS "RISC-V Cross Compile: ${CROSS_COMPILE}" ) # The Generic system name is used for embedded targets (targets without OS) in # CMake set( CMAKE_SYSTEM_NAME Generic ) -set( CMAKE_SYSTEM_PROCESSOR rv32imac_zicsr ) # specify the cross compiler. We force the compiler so that CMake doesn't # attempt to build a simple test program as this will fail without us using @@ -68,15 +67,3 @@ set( CMAKE_OBJCOPY ${RISCV_TOOLCHAIN_BIN_PATH}/${CROSS_COMPILE}objcopy set( CMAKE_OBJDUMP ${RISCV_TOOLCHAIN_BIN_PATH}/${CROSS_COMPILE}objdump CACHE FILEPATH "The toolchain objdump command " FORCE ) - -# Set the common build flags - -# Set the CMAKE C flags (which should also be used by the assembler! -set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g" ) -set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=${CMAKE_SYSTEM_PROCESSOR}" ) - -set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "" ) -set( CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "" ) -set( CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "" ) -set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -march=${CMAKE_SYSTEM_PROCESSOR} -nostartfiles " ) - diff --git a/tests/riscv-tests/CMakeLists.txt b/tests/riscv-tests/CMakeLists.txt index c3e8722..f62eaf3 100644 --- a/tests/riscv-tests/CMakeLists.txt +++ b/tests/riscv-tests/CMakeLists.txt @@ -19,7 +19,12 @@ # You should have received a copy of the GNU General Public License # along with ECAP5-DPROC. If not, see . -include(${CMAKE_SOURCE_DIR}/cmake/riscv.cmake) +set(CROSS_COMPILE riscv64-unknown-elf-) +set(CMAKE_ASM_COMPILER ${CROSS_COMPILE}gcc) +set(CMAKE_AR ${CROSS_COMPILE}ar) +set(CMAKE_ASM_COMPILER ${CROSS_COMPILE}gcc) +set(CMAKE_C_COMPILER ${CROSS_COMPILE}gcc) +set(CMAKE_CXX_COMPILER ${CROSS_COMPILE}g++) enable_language(ASM) @@ -31,11 +36,11 @@ set(SOURCE_DIR ${riscv_tests_SOURCE_DIR}/isa/${TVM}/) set(ENV_DIR ${CMAKE_CURRENT_SOURCE_DIR}/env/) # Compile options -set(CC_OPTS -static - -mcmodel=medany - -fvisibility=hidden - -nostdlib - -nostartfiles) +set(CC_OPTS "-static \ + -mcmodel=medany \ + -fvisibility=hidden \ + -nostdlib \ + -nostartfiles") set(CC_INCS ${riscv_tests_SOURCE_DIR}/env ${ENV_DIR} ${riscv_tests_SOURCE_DIR}/isa/macros/scalar) @@ -64,9 +69,9 @@ set(ALL_TARGETS) foreach(TARGET IN LISTS TARGETS) set(FULL_TARGET ${TVM}-${TE}-${TARGET}) add_executable(${FULL_TARGET} ${SOURCE_DIR}/${TARGET}.S) - add_compile_options(${CC_OPTS} -march=rv32g -mabi=ilp32) + set_target_properties(${FULL_TARGET} PROPERTIES COMPILE_FLAGS "${CC_OPTS} -march=rv32g -mabi=ilp32" + LINK_FLAGS "${CC_OPTS} -march=rv32g -mabi=ilp32 -T${ENV_DIR}/link.ld") target_include_directories(${FULL_TARGET} PRIVATE ${CC_INCS}) - target_link_options(${FULL_TARGET} PRIVATE -T${ENV_DIR}/link.ld) list(APPEND ALL_TARGETS ${FULL_TARGET}) endforeach() From 032d011058972e4294dff7b9cfa98f8e2d4cadaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chaine?= Date: Wed, 1 May 2024 15:52:23 +0000 Subject: [PATCH 5/9] Starts implementing the riscv-tests cpp logic --- config/gtkwave/config/riscv-tests.gtkw | 200 +++++++++++++++++++++++++ tests/riscv-tests/env/riscv_test.h | 3 +- tests/riscv-tests/riscv-tests.cpp | 53 ++++++- 3 files changed, 253 insertions(+), 3 deletions(-) create mode 100644 config/gtkwave/config/riscv-tests.gtkw diff --git a/config/gtkwave/config/riscv-tests.gtkw b/config/gtkwave/config/riscv-tests.gtkw new file mode 100644 index 0000000..63ffeaa --- /dev/null +++ b/config/gtkwave/config/riscv-tests.gtkw @@ -0,0 +1,200 @@ +[*] +[*] GTKWave Analyzer v3.4.0 (w)1999-2022 BSI +[*] Wed May 1 15:51:54 2024 +[*] +[dumpfile] "/Users/cchaine/Desktop/Documents/projects/.ecap5.nosync/design/proc/build/tests/waves/riscv-tests.vcd" +[dumpfile_mtime] "Wed May 1 15:45:54 2024" +[dumpfile_size] 81947 +[savefile] "/Users/cchaine/Desktop/Documents/projects/.ecap5.nosync/design/proc/config/gtkwave/config/riscv-tests.gtkw" +[timestart] 1 +[size] 2320 982 +[pos] -32 -107 +*-5.572440 153 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +[markername] AA +[markername] BB +[markername] CC +[markername] DD +[markername] EE +[markername] FF +[markername] GG +[markername] HH +[markername] II +[markername] JJ +[markername] KK +[markername] LL +[markername] MM +[markername] NN +[markername] OO +[markername] PP +[markername] QQ +[markername] RR +[markername] SS +[markername] TT +[markername] UU +[markername] VV +[markername] WW +[markername] XX +[markername] YY +[markername] ZZ +[treeopen] TOP. +[sst_width] 253 +[signals_width] 351 +[sst_expanded] 1 +[sst_vpaned_height] 342 +@28 +TOP.clk_i +TOP.drq_i +TOP.irq_i +TOP.rst_i +@c00200 +-Master Wishbone +@22 +[color] 2 +TOP.wb_adr_o[31:0] +[color] 2 +TOP.wb_dat_i[31:0] +[color] 2 +TOP.wb_dat_o[31:0] +@28 +[color] 2 +TOP.wb_we_o +@22 +[color] 2 +TOP.wb_sel_o[3:0] +@28 +[color] 2 +TOP.wb_stb_o +[color] 2 +TOP.wb_ack_i +[color] 2 +TOP.wb_cyc_o +[color] 2 +TOP.wb_stall_i +@1401200 +-Master Wishbone +@c00200 +-IFM +@28 +TOP.ecap5_dproc.branch +@22 +TOP.ecap5_dproc.branch_target[31:0] +@800200 +-IFM Wishbone +@1000200 +-IFM Wishbone +@28 +TOP.ecap5_dproc.if_dec_ready +TOP.ecap5_dproc.if_dec_valid +@22 +TOP.ecap5_dproc.if_instr[31:0] +TOP.ecap5_dproc.if_pc[31:0] +@28 +TOP.ecap5_dproc.if_wb_ack_i +@22 +TOP.ecap5_dproc.if_wb_adr_o[31:0] +@28 +TOP.ecap5_dproc.if_wb_cyc_o +@22 +TOP.ecap5_dproc.if_wb_dat_i[31:0] +TOP.ecap5_dproc.if_wb_sel_o[3:0] +@28 +TOP.ecap5_dproc.if_wb_stall_i +TOP.ecap5_dproc.if_wb_stb_o +TOP.ecap5_dproc.if_wb_we_o +@1401200 +-IFM +@c00200 +-DECM +@28 +TOP.ecap5_dproc.dec_alu_op[2:0] +@22 +TOP.ecap5_dproc.dec_alu_operand1[31:0] +TOP.ecap5_dproc.dec_alu_operand2[31:0] +@28 +TOP.ecap5_dproc.dec_alu_shift_left +TOP.ecap5_dproc.dec_alu_signed_shift +TOP.ecap5_dproc.dec_alu_sub +TOP.ecap5_dproc.dec_branch_cond[2:0] +@22 +TOP.ecap5_dproc.dec_branch_offset[19:0] +@28 +TOP.ecap5_dproc.dec_ex_ready +TOP.ecap5_dproc.dec_ex_valid +TOP.ecap5_dproc.dec_ls_enable +@22 +TOP.ecap5_dproc.dec_ls_sel[3:0] +@28 +TOP.ecap5_dproc.dec_ls_unsigned_load +TOP.ecap5_dproc.dec_ls_write +@22 +TOP.ecap5_dproc.dec_ls_write_data[31:0] +TOP.ecap5_dproc.dec_pc[31:0] +TOP.ecap5_dproc.dec_reg_addr[4:0] +@28 +TOP.ecap5_dproc.dec_reg_write +@1401200 +-DECM +@c00200 +-EXM +@28 +TOP.ecap5_dproc.ex_ls_enable +TOP.ecap5_dproc.ex_ls_ready +@22 +TOP.ecap5_dproc.ex_ls_sel[3:0] +@28 +TOP.ecap5_dproc.ex_ls_unsigned_load +TOP.ecap5_dproc.ex_ls_valid +TOP.ecap5_dproc.ex_ls_write +@22 +TOP.ecap5_dproc.ex_ls_write_data[31:0] +TOP.ecap5_dproc.ex_reg_addr[4:0] +@28 +TOP.ecap5_dproc.ex_reg_write +@22 +TOP.ecap5_dproc.ex_result[31:0] +@1401200 +-EXM +@c00200 +-LSM +-LSM Wishbone +@1401200 +-LSM Wishbone +@22 +TOP.ecap5_dproc.ls_reg_addr[4:0] +TOP.ecap5_dproc.ls_reg_data[31:0] +@28 +TOP.ecap5_dproc.ls_reg_write +TOP.ecap5_dproc.ls_valid +TOP.ecap5_dproc.ls_wb_ack_i +@22 +TOP.ecap5_dproc.ls_wb_adr_o[31:0] +@28 +TOP.ecap5_dproc.ls_wb_cyc_o +@22 +TOP.ecap5_dproc.ls_wb_dat_i[31:0] +TOP.ecap5_dproc.ls_wb_dat_o[31:0] +TOP.ecap5_dproc.ls_wb_sel_o[3:0] +@28 +TOP.ecap5_dproc.ls_wb_stall_i +TOP.ecap5_dproc.ls_wb_stb_o +TOP.ecap5_dproc.ls_wb_we_o +@1401200 +-LSM +@c00200 +-REGM +@22 +TOP.ecap5_dproc.reg_raddr1[4:0] +TOP.ecap5_dproc.reg_raddr2[4:0] +TOP.ecap5_dproc.reg_rdata1[31:0] +TOP.ecap5_dproc.reg_rdata2[31:0] +TOP.ecap5_dproc.reg_waddr[4:0] +TOP.ecap5_dproc.reg_wdata[31:0] +@28 +TOP.ecap5_dproc.reg_write +@1401200 +-REGM +@28 +TOP.ecap5_dproc.hzd_dec_stall_request +TOP.ecap5_dproc.hzd_ex_discard_request +[pattern_trace] 1 +[pattern_trace] 0 diff --git a/tests/riscv-tests/env/riscv_test.h b/tests/riscv-tests/env/riscv_test.h index bbb5a1a..ed9bc17 100644 --- a/tests/riscv-tests/env/riscv_test.h +++ b/tests/riscv-tests/env/riscv_test.h @@ -184,7 +184,8 @@ _start: \ //----------------------------------------------------------------------- #define RVTEST_CODE_END \ - unimp +_end: \ + j _end //----------------------------------------------------------------------- // Pass/Fail Macro diff --git a/tests/riscv-tests/riscv-tests.cpp b/tests/riscv-tests/riscv-tests.cpp index 4926e9d..8f4d39a 100644 --- a/tests/riscv-tests/riscv-tests.cpp +++ b/tests/riscv-tests/riscv-tests.cpp @@ -34,6 +34,8 @@ #define KO * 1024 #define MAX_BINARY_SIZE (32 KO) +#define MAX_TICKCOUNT 1000 + class TB_Riscv_tests: public Testbench { public: uint8_t memory[MAX_BINARY_SIZE]; @@ -51,6 +53,51 @@ class TB_Riscv_tests: public Testbench { memset(memory, 0, MAX_BINARY_SIZE); } + void tick() { + static uint8_t state = 0; + + // handle wishbone bus + switch(state) { + case 0: { + if((this->core->wb_stb_o == 1) && (this->core->wb_cyc_o == 1)) { + // check overflow + uint32_t data; + if(this->core->wb_adr_o >= MAX_BINARY_SIZE) { + printf("Runtime memory overflow\n Requested address : %08x, Memory end address : %08x\n\n", this->core->wb_adr_o, MAX_BINARY_SIZE-1); + data = 0; + } else { + memcpy(&data, memory + this->core->wb_adr_o, 4); + switch(this->core->wb_sel_o) { + case 0x1: + data &= 0xFF; + break; + case 0x3: + data &= 0xFFFF; + break; + case 0xF: + break; + default: + printf("Invalid wishbone sel signal : %08x\n", this->core->wb_sel_o); + break; + } + } + this->core->wb_dat_i = data; + this->core->wb_ack_i = 1; + state = 1; + break; + } + } + case 1: { + this->core->wb_dat_i = 0; + this->core->wb_ack_i = 0; + state = 0; + break; + } + } + + Testbench::tick(); + } + void set_memory(std::string path) { memset(memory, 0, MAX_BINARY_SIZE); this->load_elf(path, memory); @@ -167,9 +214,11 @@ void tb_riscv_tests_simple(TB_Riscv_tests * tb) { Vecap5_dproc * core = tb->core; tb->reset(); - tb->dump_memory(1024); tb->set_memory("riscv-tests/rv32ui-p-simple"); - tb->dump_memory(1024); + + while(tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } } int main(int argc, char ** argv, char ** env) { From d8a067e5a110173dc5f1ef09ddb458e4c1932f30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chaine?= Date: Wed, 1 May 2024 17:01:01 +0000 Subject: [PATCH 6/9] Updates the waveform config for riscv-tests --- config/gtkwave/config/riscv-tests.gtkw | 113 +++++++++++++++++-------- 1 file changed, 78 insertions(+), 35 deletions(-) diff --git a/config/gtkwave/config/riscv-tests.gtkw b/config/gtkwave/config/riscv-tests.gtkw index 63ffeaa..ed16116 100644 --- a/config/gtkwave/config/riscv-tests.gtkw +++ b/config/gtkwave/config/riscv-tests.gtkw @@ -1,14 +1,14 @@ [*] [*] GTKWave Analyzer v3.4.0 (w)1999-2022 BSI -[*] Wed May 1 15:51:54 2024 +[*] Wed May 1 17:00:22 2024 [*] [dumpfile] "/Users/cchaine/Desktop/Documents/projects/.ecap5.nosync/design/proc/build/tests/waves/riscv-tests.vcd" -[dumpfile_mtime] "Wed May 1 15:45:54 2024" +[dumpfile_mtime] "Wed May 1 16:54:54 2024" [dumpfile_size] 81947 [savefile] "/Users/cchaine/Desktop/Documents/projects/.ecap5.nosync/design/proc/config/gtkwave/config/riscv-tests.gtkw" -[timestart] 1 -[size] 2320 982 -[pos] -32 -107 +[timestart] 928 +[size] 2320 783 +[pos] -1 -1 *-5.572440 153 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 [markername] AA [markername] BB @@ -38,9 +38,9 @@ [markername] ZZ [treeopen] TOP. [sst_width] 253 -[signals_width] 351 +[signals_width] 285 [sst_expanded] 1 -[sst_vpaned_height] 342 +[sst_vpaned_height] 480 @28 TOP.clk_i TOP.drq_i @@ -72,23 +72,17 @@ TOP.wb_cyc_o TOP.wb_stall_i @1401200 -Master Wishbone -@c00200 +@800200 -IFM @28 +[color] 2 TOP.ecap5_dproc.branch @22 +[color] 2 TOP.ecap5_dproc.branch_target[31:0] -@800200 --IFM Wishbone -@1000200 +@c00200 -IFM Wishbone @28 -TOP.ecap5_dproc.if_dec_ready -TOP.ecap5_dproc.if_dec_valid -@22 -TOP.ecap5_dproc.if_instr[31:0] -TOP.ecap5_dproc.if_pc[31:0] -@28 TOP.ecap5_dproc.if_wb_ack_i @22 TOP.ecap5_dproc.if_wb_adr_o[31:0] @@ -102,69 +96,99 @@ TOP.ecap5_dproc.if_wb_stall_i TOP.ecap5_dproc.if_wb_stb_o TOP.ecap5_dproc.if_wb_we_o @1401200 +-IFM Wishbone +@4022 +[color] 2 +^>1 /Users/cchaine/Desktop/Documents/projects/.ecap5.nosync/design/proc/config/gtkwave/filters/decode_instr_filter_process.py +TOP.ecap5_dproc.if_instr[31:0] +@22 +[color] 2 +TOP.ecap5_dproc.if_pc[31:0] +@1000200 -IFM +@28 +TOP.ecap5_dproc.if_dec_valid +TOP.ecap5_dproc.if_dec_ready @c00200 -DECM -@28 -TOP.ecap5_dproc.dec_alu_op[2:0] @22 +[color] 5 TOP.ecap5_dproc.dec_alu_operand1[31:0] +[color] 5 TOP.ecap5_dproc.dec_alu_operand2[31:0] @28 +[color] 5 +TOP.ecap5_dproc.dec_alu_op[2:0] +[color] 5 +TOP.ecap5_dproc.dec_alu_sub +[color] 5 TOP.ecap5_dproc.dec_alu_shift_left +[color] 5 TOP.ecap5_dproc.dec_alu_signed_shift -TOP.ecap5_dproc.dec_alu_sub +[color] 5 TOP.ecap5_dproc.dec_branch_cond[2:0] @22 +[color] 5 TOP.ecap5_dproc.dec_branch_offset[19:0] @28 -TOP.ecap5_dproc.dec_ex_ready -TOP.ecap5_dproc.dec_ex_valid +[color] 5 TOP.ecap5_dproc.dec_ls_enable @22 +[color] 5 TOP.ecap5_dproc.dec_ls_sel[3:0] @28 +[color] 5 TOP.ecap5_dproc.dec_ls_unsigned_load +[color] 5 TOP.ecap5_dproc.dec_ls_write @22 +[color] 5 TOP.ecap5_dproc.dec_ls_write_data[31:0] +[color] 5 TOP.ecap5_dproc.dec_pc[31:0] +[color] 5 TOP.ecap5_dproc.dec_reg_addr[4:0] @28 +[color] 5 TOP.ecap5_dproc.dec_reg_write @1401200 -DECM +@28 +TOP.ecap5_dproc.dec_ex_valid +TOP.ecap5_dproc.dec_ex_ready @c00200 -EXM @28 +[color] 3 TOP.ecap5_dproc.ex_ls_enable -TOP.ecap5_dproc.ex_ls_ready @22 +[color] 3 TOP.ecap5_dproc.ex_ls_sel[3:0] @28 +[color] 3 TOP.ecap5_dproc.ex_ls_unsigned_load -TOP.ecap5_dproc.ex_ls_valid +[color] 3 TOP.ecap5_dproc.ex_ls_write @22 +[color] 3 TOP.ecap5_dproc.ex_ls_write_data[31:0] +[color] 3 TOP.ecap5_dproc.ex_reg_addr[4:0] @28 +[color] 3 TOP.ecap5_dproc.ex_reg_write @22 +[color] 3 TOP.ecap5_dproc.ex_result[31:0] @1401200 -EXM +@28 +TOP.ecap5_dproc.ex_ls_valid +TOP.ecap5_dproc.ex_ls_ready @c00200 -LSM -LSM Wishbone -@1401200 --LSM Wishbone -@22 -TOP.ecap5_dproc.ls_reg_addr[4:0] -TOP.ecap5_dproc.ls_reg_data[31:0] @28 -TOP.ecap5_dproc.ls_reg_write -TOP.ecap5_dproc.ls_valid TOP.ecap5_dproc.ls_wb_ack_i @22 TOP.ecap5_dproc.ls_wb_adr_o[31:0] @@ -179,19 +203,38 @@ TOP.ecap5_dproc.ls_wb_stall_i TOP.ecap5_dproc.ls_wb_stb_o TOP.ecap5_dproc.ls_wb_we_o @1401200 +-LSM Wishbone +@28 +[color] 7 +TOP.ecap5_dproc.ls_reg_write +@22 +[color] 7 +TOP.ecap5_dproc.ls_reg_addr[4:0] +[color] 7 +TOP.ecap5_dproc.ls_reg_data[31:0] +@1401200 -LSM -@c00200 +@28 +TOP.ecap5_dproc.ls_valid +@c00201 -REGM -@22 +@23 +[color] 1 TOP.ecap5_dproc.reg_raddr1[4:0] +[color] 1 TOP.ecap5_dproc.reg_raddr2[4:0] +[color] 1 TOP.ecap5_dproc.reg_rdata1[31:0] +[color] 1 TOP.ecap5_dproc.reg_rdata2[31:0] +[color] 1 TOP.ecap5_dproc.reg_waddr[4:0] +[color] 1 TOP.ecap5_dproc.reg_wdata[31:0] -@28 +@29 +[color] 1 TOP.ecap5_dproc.reg_write -@1401200 +@1401201 -REGM @28 TOP.ecap5_dproc.hzd_dec_stall_request From 8e0f885fa722cef541f630e8186662035776b3fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chaine?= Date: Wed, 1 May 2024 19:01:01 +0000 Subject: [PATCH 7/9] Finishes integrating riscv-tests --- config/gtkwave/config/decode.gtkw | 14 +- config/gtkwave/config/riscv-tests.gtkw | 67 +- .../gtkwave/filters/fetch_state_filter.gtkw | 2 +- .../filters/fetch_testcase_filter.gtkw | 36 +- src/decode.sv | 9 +- src/fetch.sv | 57 +- src/regs.sv | 4 + tests/benches/decode/tb_decode.cpp | 8 +- tests/benches/ecap5_dproc/tb_ecap5_dproc.cpp | 18 +- tests/benches/fetch/tb_fetch.cpp | 1567 +---------------- tests/riscv-tests/CMakeLists.txt | 15 +- tests/riscv-tests/env/riscv_test.h | 12 +- tests/riscv-tests/riscv-tests.cpp | 1225 ++++++++++++- 13 files changed, 1411 insertions(+), 1623 deletions(-) diff --git a/config/gtkwave/config/decode.gtkw b/config/gtkwave/config/decode.gtkw index 7cd1077..e1842b6 100644 --- a/config/gtkwave/config/decode.gtkw +++ b/config/gtkwave/config/decode.gtkw @@ -1,15 +1,15 @@ [*] [*] GTKWave Analyzer v3.4.0 (w)1999-2022 BSI -[*] Mon Apr 1 14:48:23 2024 +[*] Thu May 2 06:35:18 2024 [*] [dumpfile] "/Users/cchaine/Desktop/Documents/projects/.ecap5.nosync/design/proc/build/tests/waves/decode.vcd" -[dumpfile_mtime] "Mon Apr 1 14:47:51 2024" -[dumpfile_size] 56106 +[dumpfile_mtime] "Thu May 2 06:34:18 2024" +[dumpfile_size] 65913 [savefile] "/Users/cchaine/Desktop/Documents/projects/.ecap5.nosync/design/proc/config/gtkwave/config/decode.gtkw" -[timestart] 887 -[size] 2160 829 +[timestart] 2274 +[size] 2320 1043 [pos] -1 -1 -*-4.654594 963 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +*-4.654594 2440 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 [markername] AA [markername] BB [markername] CC @@ -51,6 +51,8 @@ TOP.tb_decode.clk_i TOP.tb_decode.rst_i @200 -Input +@29 +TOP.tb_decode.stall_request_i @28 TOP.tb_decode.input_valid_i TOP.tb_decode.input_ready_o diff --git a/config/gtkwave/config/riscv-tests.gtkw b/config/gtkwave/config/riscv-tests.gtkw index ed16116..2cd62f4 100644 --- a/config/gtkwave/config/riscv-tests.gtkw +++ b/config/gtkwave/config/riscv-tests.gtkw @@ -1,15 +1,15 @@ [*] [*] GTKWave Analyzer v3.4.0 (w)1999-2022 BSI -[*] Wed May 1 17:00:22 2024 +[*] Thu May 2 09:56:53 2024 [*] -[dumpfile] "/Users/cchaine/Desktop/Documents/projects/.ecap5.nosync/design/proc/build/tests/waves/riscv-tests.vcd" -[dumpfile_mtime] "Wed May 1 16:54:54 2024" -[dumpfile_size] 81947 +[dumpfile] "/Users/cchaine/Desktop/Documents/projects/.ecap5.nosync/design/proc/build/tests/waves/riscv-tests-lb.vcd" +[dumpfile_mtime] "Thu May 2 09:49:29 2024" +[dumpfile_size] 160338 [savefile] "/Users/cchaine/Desktop/Documents/projects/.ecap5.nosync/design/proc/config/gtkwave/config/riscv-tests.gtkw" -[timestart] 928 -[size] 2320 783 +[timestart] 1134 +[size] 2320 1043 [pos] -1 -1 -*-5.572440 153 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +*-5.572440 1440 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 [markername] AA [markername] BB [markername] CC @@ -37,16 +37,17 @@ [markername] YY [markername] ZZ [treeopen] TOP. +[treeopen] TOP.ecap5_dproc. [sst_width] 253 [signals_width] 285 [sst_expanded] 1 -[sst_vpaned_height] 480 +[sst_vpaned_height] 293 @28 TOP.clk_i TOP.drq_i TOP.irq_i TOP.rst_i -@c00200 +@800200 -Master Wishbone @22 [color] 2 @@ -70,7 +71,7 @@ TOP.wb_ack_i TOP.wb_cyc_o [color] 2 TOP.wb_stall_i -@1401200 +@1000200 -Master Wishbone @800200 -IFM @@ -80,23 +81,27 @@ TOP.ecap5_dproc.branch @22 [color] 2 TOP.ecap5_dproc.branch_target[31:0] -@c00200 +@800201 -IFM Wishbone -@28 -TOP.ecap5_dproc.if_wb_ack_i -@22 +@23 TOP.ecap5_dproc.if_wb_adr_o[31:0] -@28 -TOP.ecap5_dproc.if_wb_cyc_o -@22 TOP.ecap5_dproc.if_wb_dat_i[31:0] +@29 +TOP.ecap5_dproc.if_wb_we_o +@23 TOP.ecap5_dproc.if_wb_sel_o[3:0] -@28 -TOP.ecap5_dproc.if_wb_stall_i +@29 TOP.ecap5_dproc.if_wb_stb_o -TOP.ecap5_dproc.if_wb_we_o -@1401200 +TOP.ecap5_dproc.if_wb_ack_i +TOP.ecap5_dproc.if_wb_cyc_o +TOP.ecap5_dproc.if_wb_stall_i +@1000201 -IFM Wishbone +@2028 +^1 /Users/cchaine/Desktop/Documents/projects/.ecap5.nosync/design/proc/config/gtkwave/filters/fetch_state_filter.gtkw +TOP.ecap5_dproc.fetch_inst.state_q[2:0] +@28 +TOP.ecap5_dproc.fetch_inst.fetch_request @4022 [color] 2 ^>1 /Users/cchaine/Desktop/Documents/projects/.ecap5.nosync/design/proc/config/gtkwave/filters/decode_instr_filter_process.py @@ -116,16 +121,20 @@ TOP.ecap5_dproc.if_dec_ready TOP.ecap5_dproc.dec_alu_operand1[31:0] [color] 5 TOP.ecap5_dproc.dec_alu_operand2[31:0] -@28 +@2028 [color] 5 +^2 /Users/cchaine/Desktop/Documents/projects/.ecap5.nosync/design/proc/config/gtkwave/filters/execute_alu_op_filter.gtkw TOP.ecap5_dproc.dec_alu_op[2:0] +@28 [color] 5 TOP.ecap5_dproc.dec_alu_sub [color] 5 TOP.ecap5_dproc.dec_alu_shift_left [color] 5 TOP.ecap5_dproc.dec_alu_signed_shift +@2028 [color] 5 +^3 /Users/cchaine/Desktop/Documents/projects/.ecap5.nosync/design/proc/config/gtkwave/filters/execute_branch_cond_filter.gtkw TOP.ecap5_dproc.dec_branch_cond[2:0] @22 [color] 5 @@ -185,7 +194,7 @@ TOP.ecap5_dproc.ex_result[31:0] @28 TOP.ecap5_dproc.ex_ls_valid TOP.ecap5_dproc.ex_ls_ready -@c00200 +@800200 -LSM -LSM Wishbone @28 @@ -202,7 +211,7 @@ TOP.ecap5_dproc.ls_wb_sel_o[3:0] TOP.ecap5_dproc.ls_wb_stall_i TOP.ecap5_dproc.ls_wb_stb_o TOP.ecap5_dproc.ls_wb_we_o -@1401200 +@1000200 -LSM Wishbone @28 [color] 7 @@ -212,13 +221,13 @@ TOP.ecap5_dproc.ls_reg_write TOP.ecap5_dproc.ls_reg_addr[4:0] [color] 7 TOP.ecap5_dproc.ls_reg_data[31:0] -@1401200 +@1000200 -LSM @28 TOP.ecap5_dproc.ls_valid -@c00201 +@c00200 -REGM -@23 +@22 [color] 1 TOP.ecap5_dproc.reg_raddr1[4:0] [color] 1 @@ -231,10 +240,10 @@ TOP.ecap5_dproc.reg_rdata2[31:0] TOP.ecap5_dproc.reg_waddr[4:0] [color] 1 TOP.ecap5_dproc.reg_wdata[31:0] -@29 +@28 [color] 1 TOP.ecap5_dproc.reg_write -@1401201 +@1401200 -REGM @28 TOP.ecap5_dproc.hzd_dec_stall_request diff --git a/config/gtkwave/filters/fetch_state_filter.gtkw b/config/gtkwave/filters/fetch_state_filter.gtkw index 8fe8052..f3528c5 100644 --- a/config/gtkwave/filters/fetch_state_filter.gtkw +++ b/config/gtkwave/filters/fetch_state_filter.gtkw @@ -3,4 +3,4 @@ 010 MEMORY_WAIT 011 DONE 100 MEMORY_STALL -101 PIPELINE_STALL +101 OUTPUT diff --git a/config/gtkwave/filters/fetch_testcase_filter.gtkw b/config/gtkwave/filters/fetch_testcase_filter.gtkw index 67bd94b..622c70b 100644 --- a/config/gtkwave/filters/fetch_testcase_filter.gtkw +++ b/config/gtkwave/filters/fetch_testcase_filter.gtkw @@ -2,28 +2,14 @@ 2 T_MEMORY_STALL 3 T_MEMORY_WAIT 4 T_PIPELINE_STALL -5 T_DEBUG_DURING_REQUEST -6 T_DEBUG_DURING_ACK -7 T_DEBUG_DURING_WAIT -8 T_DEBUG_DURING_MEMORY_STALL -9 T_DEBUG_ON_OUTPUT_HANDSHAKE -10 T_DEBUG_DURING_PIPELINE_STALL -11 T_DEBUG_BACK_TO_BACK -12 T_INTERRUPT_DURING_REQUEST -13 T_INTERRUPT_DURING_ACK -14 T_INTERRUPT_DURING_WAIT -15 T_INTERRUPT_DURING_MEMORY_STALL -16 T_INTERRUPT_ON_OUTPUT_HANDSHAKE -17 T_INTERRUPT_DURING_PIPELINE_STALL -19 T_INTERRUPT_BACK_TO_BACK -20 T_BRANCH_DURING_REQUEST -21 T_BRANCH_DURING_ACK -22 T_BRANCH_DURING_WAIT -23 T_BRANCH_DURING_MEMORY_STALL -24 T_BRANCH_ON_OUTPUT_HANDSHAKE -25 T_BRANCH_DURING_PIPELINE_STALL -26 T_BRANCH_BACK_TO_BACK -27 T_PRECEDENCE_DEBUG -28 T_PRECEDENCE_INTERRUPT -29 T_PRECEDENCE_BRANCH -30 T_PRECEDENCE_INCREMENT +5 T_JUMP_AFTER_RESET +6 T_JUMP_DURING_ACK +7 T_JUMP_DURING_WAIT +8 T_JUMP_DURING_MEMORY_STALL +9 T_JUMP_ON_OUTPUT_HANDSHAKE +10 T_JUMP_DURING_PIPELINE_STALL +11 T_JUMP_BACK_TO_BACK +12 T_PRECEDENCE_DEBUG +13 T_PRECEDENCE_INTERRUPT +14 T_PRECEDENCE_BRANCH +15 T_PRECEDENCE_INCREMENT diff --git a/src/decode.sv b/src/decode.sv index 5c2eb8a..b38d5f5 100644 --- a/src/decode.sv +++ b/src/decode.sv @@ -159,7 +159,7 @@ end always_comb begin : alu_interface case(opcode) - OPCODE_LUI, OPCODE_AUIPC, OPCODE_JAL: + OPCODE_AUIPC, OPCODE_JAL: alu_operand1_d = pc_i; OPCODE_JALR, OPCODE_BRANCH, OPCODE_OP, OPCODE_OP_IMM, OPCODE_LOAD, OPCODE_STORE: alu_operand1_d = rdata1_i; @@ -271,7 +271,7 @@ always_ff @(posedge clk_i) begin output_valid_q <= 0; end else begin - if(output_ready_i) begin + if(output_ready_i && ~stall_request_i) begin pc_q <= pc_i; alu_operand1_q <= input_valid_i ? alu_operand1_d : '0; @@ -293,6 +293,11 @@ always_ff @(posedge clk_i) begin ls_sel_q <= ls_sel_d; ls_unsigned_load_q <= ls_unsigned_load_d; end + if(stall_request_i) begin + ls_enable_q <= 0; + reg_write_q <= 0; + reg_addr_q <= 0; + end output_valid_q <= output_valid_d; end diff --git a/src/fetch.sv b/src/fetch.sv index def0b49..06b61bf 100644 --- a/src/fetch.sv +++ b/src/fetch.sv @@ -103,7 +103,13 @@ always_comb begin : state_machine MEMORY_STALL: begin if(!wb_stall_i) begin // The memory is unstalled - state_d = REQUEST; + if(wb_ack_i) begin + // The response has been received directly + state_d = DONE; + end else begin + // Wait for the response to be received + state_d = MEMORY_WAIT; + end end end REQUEST: begin @@ -131,10 +137,19 @@ always_comb begin : state_machine end end PIPELINE_STALL: begin + // Either the output is ready or a jump was requested which cancels + // the output if(output_ready_i || pending_jump_q) begin - // Either the output is ready or a jump was requested which cancels - // the output - state_d = IDLE; + if(fetch_request) begin + // A memory request shall be triggered + if(wb_stall_i) begin + // The memory is stalled + state_d = MEMORY_STALL; + end else begin + // The memory is ready + state_d = REQUEST; + end + end end end default: begin @@ -150,17 +165,31 @@ always_comb begin : wishbone_read case(state_q) IDLE: begin if(fetch_request) begin - wb_adr_d = pc_q; + wb_adr_d = pc_d; wb_stb_d = 1; wb_cyc_d = 1; end end + MEMORY_STALL: begin + if(!wb_stall_i) begin + wb_stb_d = 0; + end + end REQUEST: begin wb_stb_d = 0; end DONE: begin wb_cyc_d = 0; end + PIPELINE_STALL: begin + if(output_ready_i || pending_jump_q) begin + if(fetch_request) begin + wb_adr_d = pc_d; + wb_stb_d = 1; + wb_cyc_d = 1; + end + end + end default: begin end endcase @@ -179,6 +208,14 @@ always_comb begin : output_management pending_jump_d = 0; end end + MEMORY_STALL: begin + if(!wb_stall_i) begin + // The memory is unstalled + if(wb_ack_i) begin + instr_d = wb_dat_i; + end + end + end REQUEST: begin if(wb_ack_i) begin instr_d = wb_dat_i; @@ -199,6 +236,9 @@ always_comb begin : output_management PIPELINE_STALL: begin if(output_ready_i || pending_jump_q) begin output_valid_d = 0; + if(fetch_request) begin + pending_jump_d = 0; + end end end default: begin @@ -216,7 +256,7 @@ end always_comb begin : pc_update pc_d = pc_q; // 3. Default increment - if (output_valid_d && output_ready_i) begin + if (output_valid_q && output_ready_i) begin pc_d = pc_q + 4; end // 2. Control flow change request @@ -248,15 +288,16 @@ always_ff @(posedge clk_i) begin wb_adr_q <= wb_adr_d; wb_stb_q <= wb_stb_d; wb_cyc_q <= wb_cyc_d; - output_valid_q <= output_valid_d; instr_q <= instr_d; pc_q <= pc_d; // Jump triggering if(drq_i || irq_i || branch_i) begin pending_jump_q <= 1; + output_valid_q <= 0; end else begin pending_jump_q <= pending_jump_d; + output_valid_q <= output_valid_d; end end // Store a delayed rst to detect a falling edge for instruction fetch trigger @@ -278,6 +319,6 @@ assign wb_cyc_o = wb_cyc_q; assign output_valid_o = output_valid_q; assign instr_o = instr_q; -assign pc_o = pc_qq; +assign pc_o = pc_q; endmodule // fetch diff --git a/src/regs.sv b/src/regs.sv index 29d4104..49b2e81 100644 --- a/src/regs.sv +++ b/src/regs.sv @@ -52,6 +52,10 @@ assign rdata2_o = registers[raddr2_i]; task automatic set_register_value(input logic[4:0] addr, input logic[31:0] value); registers[addr] = value; endtask + export "DPI-C" task get_register_value; + task automatic get_register_value(input logic[4:0] addr, output logic[31:0] out); + out = registers[addr]; + endtask `endif endmodule // regs diff --git a/tests/benches/decode/tb_decode.cpp b/tests/benches/decode/tb_decode.cpp index cbbf917..5cbdaa1 100644 --- a/tests/benches/decode/tb_decode.cpp +++ b/tests/benches/decode/tb_decode.cpp @@ -401,7 +401,7 @@ void tb_decode_lui(TB_Decode * tb) { //````````````````````````````````` // Checks - tb->check(COND_alu, (core->alu_operand1_o == pc) && + tb->check(COND_alu, (core->alu_operand1_o == 0) && (core->alu_operand2_o == (imm << 12)) && (core->alu_op_o == Vtb_decode_ecap5_dproc_pkg::ALU_ADD) && (core->alu_sub_o == 0)); @@ -3311,10 +3311,10 @@ void tb_decode_hazard(TB_Decode * tb) { tb->check(COND_alu, (core->alu_operand1_o == rdata1) && (core->alu_operand2_o == rdata2) && - (core->alu_op_o == Vtb_decode_ecap5_dproc_pkg::ALU_OR)); + (core->alu_op_o == Vtb_decode_ecap5_dproc_pkg::ALU_AND)); tb->check(COND_branch, (core->branch_cond_o == Vtb_decode_ecap5_dproc_pkg::NO_BRANCH)); - tb->check(COND_writeback, (core->reg_write_o == 1) && - (core->reg_addr_o == rd)); + tb->check(COND_writeback, (core->reg_write_o == 0) && + (core->reg_addr_o == 0)); tb->check(COND_loadstore, (core->ls_enable_o == 0)); tb->check(COND_output_valid, (core->output_valid_o == 0)); diff --git a/tests/benches/ecap5_dproc/tb_ecap5_dproc.cpp b/tests/benches/ecap5_dproc/tb_ecap5_dproc.cpp index 09008df..e14e7b9 100644 --- a/tests/benches/ecap5_dproc/tb_ecap5_dproc.cpp +++ b/tests/benches/ecap5_dproc/tb_ecap5_dproc.cpp @@ -77,20 +77,20 @@ class TB_Ecap5_dproc : public Testbench { Testbench::tick(); // Check pipeline bubbles - if(prev_if_dec_valid == 0) { + if(prev_if_dec_valid == 0 && this->core->tb_ecap5_dproc->dut->dec_ex_valid == 1) { this->check(COND_bubble, (this->core->tb_ecap5_dproc->dut->dec_alu_operand1 == 0) && - (this->core->tb_ecap5_dproc->dut->dec_alu_operand2 == 0) && - (this->core->tb_ecap5_dproc->dut->dec_alu_op == Vtb_ecap5_dproc_ecap5_dproc_pkg::ALU_ADD) && - (this->core->tb_ecap5_dproc->dut->dec_alu_sub == 0) && - (this->core->tb_ecap5_dproc->dut->dec_branch_cond == Vtb_ecap5_dproc_ecap5_dproc_pkg::NO_BRANCH) && - (this->core->tb_ecap5_dproc->dut->dec_ls_enable == 0) && - (this->core->tb_ecap5_dproc->dut->dec_reg_write == 0)); + (this->core->tb_ecap5_dproc->dut->dec_alu_operand2 == 0) && + (this->core->tb_ecap5_dproc->dut->dec_alu_op == Vtb_ecap5_dproc_ecap5_dproc_pkg::ALU_ADD) && + (this->core->tb_ecap5_dproc->dut->dec_alu_sub == 0) && + (this->core->tb_ecap5_dproc->dut->dec_branch_cond == Vtb_ecap5_dproc_ecap5_dproc_pkg::NO_BRANCH) && + (this->core->tb_ecap5_dproc->dut->dec_ls_enable == 0) && + (this->core->tb_ecap5_dproc->dut->dec_reg_write == 0)); } - if(prev_dec_ex_valid == 0) { + if(prev_dec_ex_valid == 0 && this->core->tb_ecap5_dproc->dut->ex_ls_valid == 1) { this->check(COND_bubble, (this->core->tb_ecap5_dproc->dut->ex_ls_enable == 0) && (this->core->tb_ecap5_dproc->dut->ex_reg_write == 0)); } - if(prev_ex_ls_valid == 0) { + if(prev_ex_ls_valid == 0 && this->core->tb_ecap5_dproc->dut->ls_valid == 1) { this->check(COND_bubble, (this->core->tb_ecap5_dproc->dut->ls_reg_write == 0)); } if(prev_ls_valid == 0) { diff --git a/tests/benches/fetch/tb_fetch.cpp b/tests/benches/fetch/tb_fetch.cpp index 3a137b9..e7e0b6f 100644 --- a/tests/benches/fetch/tb_fetch.cpp +++ b/tests/benches/fetch/tb_fetch.cpp @@ -46,31 +46,17 @@ enum TestcaseId { T_MEMORY_STALL = 2, T_MEMORY_WAIT = 3, T_PIPELINE_STALL = 4, - T_DEBUG_DURING_REQUEST = 5, - T_DEBUG_DURING_ACK = 6, - T_DEBUG_DURING_WAIT = 7, - T_DEBUG_DURING_MEMORY_STALL = 8, - T_DEBUG_ON_OUTPUT_HANDSHAKE = 9, - T_DEBUG_DURING_PIPELINE_STALL = 10, - T_DEBUG_BACK_TO_BACK = 11, - T_INTERRUPT_DURING_REQUEST = 12, - T_INTERRUPT_DURING_ACK = 13, - T_INTERRUPT_DURING_WAIT = 14, - T_INTERRUPT_DURING_MEMORY_STALL = 15, - T_INTERRUPT_ON_OUTPUT_HANDSHAKE = 16, - T_INTERRUPT_DURING_PIPELINE_STALL = 17, - T_INTERRUPT_BACK_TO_BACK = 19, - T_BRANCH_DURING_REQUEST = 20, - T_BRANCH_DURING_ACK = 21, - T_BRANCH_DURING_WAIT = 22, - T_BRANCH_DURING_MEMORY_STALL = 23, - T_BRANCH_ON_OUTPUT_HANDSHAKE = 24, - T_BRANCH_DURING_PIPELINE_STALL = 25, - T_BRANCH_BACK_TO_BACK = 26, - T_PRECEDENCE_DEBUG = 27, - T_PRECEDENCE_INTERRUPT = 28, - T_PRECEDENCE_BRANCH = 29, - T_PRECEDENCE_INCREMENT = 30 + T_JUMP_DURING_REQUEST = 5, + T_JUMP_DURING_ACK = 6, + T_JUMP_DURING_WAIT = 7, + T_JUMP_DURING_MEMORY_STALL = 8, + T_JUMP_ON_OUTPUT_HANDSHAKE = 9, + T_JUMP_DURING_PIPELINE_STALL = 10, + T_JUMP_BACK_TO_BACK = 11, + T_PRECEDENCE_DEBUG = 12, + T_PRECEDENCE_INTERRUPT = 13, + T_PRECEDENCE_BRANCH = 14, + T_PRECEDENCE_INCREMENT = 15 }; class TB_Fetch : public Testbench { @@ -282,10 +268,10 @@ void tb_fetch_memory_stall(TB_Fetch * tb) { //````````````````````````````````` // Checks - tb->check(COND_state, (core->tb_fetch->dut->state_q == 1)); + tb->check(COND_state, (core->tb_fetch->dut->state_q == 2)); tb->check(COND_wishbone, (core->wb_adr_o == Vtb_fetch_ecap5_dproc_pkg::BOOT_ADDRESS) && (core->wb_we_o == 0) && - (core->wb_stb_o == 1) && + (core->wb_stb_o == 0) && (core->wb_cyc_o == 1)); //````````````````````````````````` @@ -548,10 +534,13 @@ void tb_fetch_pipeline_stall(TB_Fetch * tb) { //````````````````````````````````` // Checks - tb->check(COND_state, (core->tb_fetch->dut->state_q == 0)); - tb->check(COND_wishbone, (core->wb_stb_o == 0) && - (core->wb_cyc_o == 0)); - tb->check(COND_output_valid, (core->output_valid_o == 0)); + tb->check(COND_state, (core->tb_fetch->dut->state_q == 1)); + tb->check(COND_wishbone, (core->wb_adr_o == Vtb_fetch_ecap5_dproc_pkg::BOOT_ADDRESS + 4) && + (core->wb_we_o == 0) && + (core->wb_sel_o == 0xF) && + (core->wb_stb_o == 1) && + (core->wb_cyc_o == 1)); + tb->check(COND_output_valid, (core->output_valid_o == 0)); //````````````````````````````````` // Formal Checks @@ -573,20 +562,13 @@ void tb_fetch_pipeline_stall(TB_Fetch * tb) { "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); } -/*============================================*/ -/* Debug */ -/*============================================*/ - -void tb_fetch_debug_during_request(TB_Fetch * tb) { +void tb_fetch_jump_after_reset(TB_Fetch * tb) { Vtb_fetch * core = tb->core; - core->testcase = T_DEBUG_DURING_REQUEST; + core->testcase = T_JUMP_DURING_REQUEST; // The following actions are performed in this test : // tick 0. Set inputs for no stall with debug request - // tick 1. Acknowledge request with response data (core makes request) - // tick 2. Nothing (core latches response) - // tick 3. Nothing (core cancels output) - // tick 4. Nothing (core makes request) + // tick 1. Nothing (core makes request) //================================= // Tick (0) @@ -610,63 +592,23 @@ void tb_fetch_debug_during_request(TB_Fetch * tb) { //````````````````````````````````` // Checks - tb->check(COND_wishbone, (core->wb_adr_o == Vtb_fetch_ecap5_dproc_pkg::BOOT_ADDRESS)); - - //````````````````````````````````` - // Set inputs - - uint32_t data = rand(); - core->wb_dat_i = data; - core->wb_ack_i = 1; - - core->drq_i = 0; - - //================================= - // Tick (2) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->wb_dat_i = 0; - core->wb_ack_i = 0; - - //================================= - // Tick (3) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_output_valid, (core->output_valid_o == 0)); - - //================================= - // Tick (4) - - tb->tick(); - - //````````````````````````````````` - // Checks - tb->check(COND_wishbone, (core->wb_adr_o == Vtb_fetch_ecap5_dproc_pkg::DEBUG_ADDRESS)); //````````````````````````````````` // Formal Checks - CHECK("tb_fetch.debug_during_request.01", + CHECK("tb_fetch.jump_after_reset.01", tb->conditions[COND_wishbone], "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - CHECK("tb_fetch.debug_during_request.02", + CHECK("tb_fetch.jump_after_reset.02", tb->conditions[COND_output_valid], "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); } -void tb_fetch_debug_during_ack(TB_Fetch * tb) { +void tb_fetch_jump_during_ack(TB_Fetch * tb) { Vtb_fetch * core = tb->core; - core->testcase = T_DEBUG_DURING_ACK; + core->testcase = T_JUMP_DURING_ACK; // The following actions are performed in this test : // tick 0. Set inputs for no stall not interrupt @@ -739,18 +681,18 @@ void tb_fetch_debug_during_ack(TB_Fetch * tb) { //````````````````````````````````` // Formal Checks - CHECK("tb_fetch.debug_during_ack.01", + CHECK("tb_fetch.jump_during_ack.01", tb->conditions[COND_wishbone], "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - CHECK("tb_fetch.debug_during_ack.02", + CHECK("tb_fetch.jump_during_ack.02", tb->conditions[COND_output_valid], "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); } -void tb_fetch_debug_during_wait(TB_Fetch * tb) { +void tb_fetch_jump_during_wait(TB_Fetch * tb) { Vtb_fetch * core = tb->core; - core->testcase = T_DEBUG_DURING_WAIT; + core->testcase = T_JUMP_DURING_WAIT; // The following actions are performed in this test : // tick 0. Set inputs for no stall not interrupt @@ -847,18 +789,18 @@ void tb_fetch_debug_during_wait(TB_Fetch * tb) { //````````````````````````````````` // Formal Checks - CHECK("tb_fetch.debug_during_wait.01", + CHECK("tb_fetch.jump_during_wait.01", tb->conditions[COND_wishbone], "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - CHECK("tb_fetch.debug_during_wait.02", + CHECK("tb_fetch.jump_during_wait.02", tb->conditions[COND_output_valid], "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); } -void tb_fetch_debug_during_memory_stall(TB_Fetch * tb) { +void tb_fetch_jump_during_memory_stall(TB_Fetch * tb) { Vtb_fetch * core = tb->core; - core->testcase = T_DEBUG_DURING_MEMORY_STALL; + core->testcase = T_JUMP_DURING_MEMORY_STALL; // The following actions are performed in this test : // tick 0. Set inputs for memory stall not interrupt @@ -966,18 +908,18 @@ void tb_fetch_debug_during_memory_stall(TB_Fetch * tb) { //````````````````````````````````` // Formal Checks - CHECK("tb_fetch.debug_during_memory_stall.01", + CHECK("tb_fetch.jump_during_memory_stall.01", tb->conditions[COND_wishbone], "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - CHECK("tb_fetch.debug_during_memory_stall.02", + CHECK("tb_fetch.jump_during_memory_stall.02", tb->conditions[COND_output_valid], "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); } -void tb_fetch_debug_on_output_handshake(TB_Fetch * tb) { +void tb_fetch_jump_on_output_handshake(TB_Fetch * tb) { Vtb_fetch * core = tb->core; - core->testcase = T_DEBUG_ON_OUTPUT_HANDSHAKE; + core->testcase = T_JUMP_ON_OUTPUT_HANDSHAKE; // The following actions are performed in this test : // tick 0. Set inputs for no stall not interrupt @@ -1038,7 +980,7 @@ void tb_fetch_debug_on_output_handshake(TB_Fetch * tb) { //````````````````````````````````` // Checks - tb->check(COND_output_valid, (core->output_valid_o == 1)); + tb->check(COND_output_valid, (core->output_valid_o == 0)); //================================= // Tick (4) @@ -1053,18 +995,18 @@ void tb_fetch_debug_on_output_handshake(TB_Fetch * tb) { //````````````````````````````````` // Formal Checks - CHECK("tb_fetch.debug_on_output_handshake.01", + CHECK("tb_fetch.jump_on_output_handshake.01", tb->conditions[COND_wishbone], "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - CHECK("tb_fetch.debug_on_output_handshake.02", + CHECK("tb_fetch.jump_on_output_handshake.02", tb->conditions[COND_output_valid], "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); } -void tb_fetch_debug_during_pipeline_stall(TB_Fetch * tb) { +void tb_fetch_jump_during_pipeline_stall(TB_Fetch * tb) { Vtb_fetch * core = tb->core; - core->testcase = T_DEBUG_DURING_PIPELINE_STALL; + core->testcase = T_JUMP_DURING_PIPELINE_STALL; // The following actions are performed in this test : // tick 0. Set inputs for pipeline stall not interrupt @@ -1155,18 +1097,18 @@ void tb_fetch_debug_during_pipeline_stall(TB_Fetch * tb) { //````````````````````````````````` // Formal Checks - CHECK("tb_fetch.debug_during_pipeline_stall.01", + CHECK("tb_fetch.jump_during_pipeline_stall.01", tb->conditions[COND_wishbone], "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - CHECK("tb_fetch.debug_during_pipeline_stall.02", + CHECK("tb_fetch.jump_during_pipeline_stall.02", tb->conditions[COND_output_valid], "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); } -void tb_fetch_debug_back_to_back(TB_Fetch * tb) { +void tb_fetch_jump_back_to_back(TB_Fetch * tb) { Vtb_fetch * core = tb->core; - core->testcase = T_DEBUG_BACK_TO_BACK; + core->testcase = T_JUMP_BACK_TO_BACK; // The following actions are performed in this test : // tick 0. Set inputs for no stall not interrupt @@ -1243,1394 +1185,15 @@ void tb_fetch_debug_back_to_back(TB_Fetch * tb) { //````````````````````````````````` // Formal Checks - CHECK("tb_fetch.debug_back_to_back.01", - tb->conditions[COND_wishbone], - "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - - CHECK("tb_fetch.debug_back_to_back.02", - tb->conditions[COND_output_valid], - "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); -} - -/*============================================*/ -/* Interrupt */ -/*============================================*/ - -void tb_fetch_interrupt_during_request(TB_Fetch * tb) { - Vtb_fetch * core = tb->core; - core->testcase = T_INTERRUPT_DURING_REQUEST; - - // The following actions are performed in this test : - // tick 0. Set inputs for no stall with interrupt request - // tick 1. Acknowledge request with response data (core makes request) - // tick 2. Nothing (core latches response) - // tick 3. Nothing (core cancels output) - // tick 4. Nothing (core makes request) - - //================================= - // Tick (0) - - tb->reset(); - - // Leave the reset state - core->irq_i = 0; - core->drq_i = 0; - core->branch_i = 0; - core->output_ready_i = 1; - core->wb_stall_i = 0; - - core->irq_i = 1; - - //================================= - // Tick (1) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_wishbone, (core->wb_adr_o == Vtb_fetch_ecap5_dproc_pkg::BOOT_ADDRESS)); - - //````````````````````````````````` - // Set inputs - - uint32_t data = rand(); - core->wb_dat_i = data; - core->wb_ack_i = 1; - - core->irq_i = 0; - - //================================= - // Tick (2) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->wb_dat_i = 0; - core->wb_ack_i = 0; - - //================================= - // Tick (3) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_output_valid, (core->output_valid_o == 0)); - - //================================= - // Tick (4) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_wishbone, (core->wb_adr_o == Vtb_fetch_ecap5_dproc_pkg::INTERRUPT_ADDRESS)); - - //````````````````````````````````` - // Formal Checks - - CHECK("tb_fetch.interrupt_during_request.01", - tb->conditions[COND_wishbone], - "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - - CHECK("tb_fetch.interrupt_during_request.02", - tb->conditions[COND_output_valid], - "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); -} - -void tb_fetch_interrupt_during_ack(TB_Fetch * tb) { - Vtb_fetch * core = tb->core; - core->testcase = T_INTERRUPT_DURING_ACK; - - // The following actions are performed in this test : - // tick 0. Set inputs for no stall not interrupt - // tick 1. Acknowledge request with response data and interrupt request (core makes request) - // tick 2. Nothing (core latches response) - // tick 3. Nothing (core outputs response) - // tick 4. Nothing (core makes request) - - //================================= - // Tick (0) - - tb->reset(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 0; - core->drq_i = 0; - core->branch_i = 0; - core->output_ready_i = 1; - core->wb_stall_i = 0; - - //================================= - // Tick (1) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 1; - - uint32_t data = rand(); - core->wb_dat_i = data; - core->wb_ack_i = 1; - - //================================= - // Tick (2) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 0; - - core->wb_dat_i = 0; - core->wb_ack_i = 0; - - //================================= - // Tick (3) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_output_valid, (core->output_valid_o == 0)); - - //================================= - // Tick (4) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_wishbone, (core->wb_adr_o == Vtb_fetch_ecap5_dproc_pkg::INTERRUPT_ADDRESS)); - - //````````````````````````````````` - // Formal Checks - - CHECK("tb_fetch.interrupt_during_ack.01", + CHECK("tb_fetch.jump_back_to_back.01", tb->conditions[COND_wishbone], "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - CHECK("tb_fetch.interrupt_during_ack.02", + CHECK("tb_fetch.jump_back_to_back.02", tb->conditions[COND_output_valid], "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); } -void tb_fetch_interrupt_during_wait(TB_Fetch * tb) { - Vtb_fetch * core = tb->core; - core->testcase = T_INTERRUPT_DURING_WAIT; - - // The following actions are performed in this test : - // tick 0. Set inputs for no stall not interrupt - // tick 1. Nothing (core waits response) - // tick 2. Interrupt request (core waits response) - // tick 3. Nothing (core waits response) - // tick 4. Acknowledge request with response data (core waits response) - // tick 5. Nothing (core latches response) - // tick 6. Nothing (core output cancelled) - // tick 7. Nothing (core makes request) - - //================================= - // Tick (0) - - tb->reset(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 0; - core->drq_i = 0; - core->branch_i = 0; - core->output_ready_i = 1; - core->wb_stall_i = 0; - - //================================= - // Tick (1) - - tb->tick(); - - //================================= - // Tick (2) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 1; - - //================================= - // Tick (3) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 0; - - //================================= - // Tick (4) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - uint32_t data = rand(); - core->wb_dat_i = data; - core->wb_ack_i = 1; - - //================================= - // Tick (5) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->wb_dat_i = 0; - core->wb_ack_i = 0; - - //================================= - // Tick (6) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_output_valid, (core->output_valid_o == 0)); - - //================================= - // Tick (7) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_wishbone, (core->wb_adr_o == Vtb_fetch_ecap5_dproc_pkg::INTERRUPT_ADDRESS)); - - //````````````````````````````````` - // Formal Checks - - CHECK("tb_fetch.interrupt_during_wait.01", - tb->conditions[COND_wishbone], - "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - - CHECK("tb_fetch.interrupt_during_wait.02", - tb->conditions[COND_output_valid], - "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); -} - -void tb_fetch_interrupt_during_memory_stall(TB_Fetch * tb) { - Vtb_fetch * core = tb->core; - core->testcase = T_INTERRUPT_DURING_MEMORY_STALL; - - // The following actions are performed in this test : - // tick 0. Set inputs for memory stall not interrupt - // tick 1. Nothing (core holds request) - // tick 2. Interrupt request (core holds request) - // tick 3. Nothing (core holds request) - // tick 4. Unstall memory (core holds request) - // tick 5. Acknowledge request with response data (core latches response) - // tick 6. Nothing (core latches response) - // tick 7. Nothing (core output cancelled) - // tick 8. Nothing (core makes request) - - //================================= - // Tick (0) - - tb->reset(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 0; - core->drq_i = 0; - core->branch_i = 0; - core->output_ready_i = 1; - core->wb_stall_i = 1; - - //================================= - // Tick (1) - - tb->tick(); - - //================================= - // Tick (2) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 1; - - //================================= - // Tick (3) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 0; - - //================================= - // Tick (4) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->wb_stall_i = 0; - - //================================= - // Tick (5) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - uint32_t data = rand(); - core->wb_dat_i = data; - core->wb_ack_i = 1; - - //================================= - // Tick (6) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->wb_dat_i = 0; - core->wb_ack_i = 0; - - //================================= - // Tick (7) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_output_valid, (core->output_valid_o == 0)); - - //================================= - // Tick (8) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_wishbone, (core->wb_adr_o == Vtb_fetch_ecap5_dproc_pkg::INTERRUPT_ADDRESS)); - - //````````````````````````````````` - // Formal Checks - - CHECK("tb_fetch.interrupt_during_memory_stall.01", - tb->conditions[COND_wishbone], - "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - - CHECK("tb_fetch.interrupt_during_memory_stall.02", - tb->conditions[COND_output_valid], - "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); -} - -void tb_fetch_interrupt_on_output_handshake(TB_Fetch * tb) { - Vtb_fetch * core = tb->core; - core->testcase = T_INTERRUPT_ON_OUTPUT_HANDSHAKE; - - // The following actions are performed in this test : - // tick 0. Set inputs for no stall not interrupt - // tick 1. Acknowledge request with response data (core makes request) - // tick 2. Interrupt request (core latches response) - // tick 3. Nothing (core outputs response) - // tick 4. Nothing (core makes request) - - //================================= - // Tick (0) - - tb->reset(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 0; - core->drq_i = 0; - core->branch_i = 0; - core->output_ready_i = 1; - core->wb_stall_i = 0; - - //================================= - // Tick (1) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - uint32_t data = rand(); - core->wb_dat_i = data; - core->wb_ack_i = 1; - - //================================= - // Tick (2) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->wb_dat_i = 0; - core->wb_ack_i = 0; - - core->irq_i = 1; - - //================================= - // Tick (3) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 0; - - //````````````````````````````````` - // Checks - - tb->check(COND_output_valid, (core->output_valid_o == 1)); - - //================================= - // Tick (4) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_wishbone, (core->wb_adr_o == Vtb_fetch_ecap5_dproc_pkg::INTERRUPT_ADDRESS)); - - //````````````````````````````````` - // Formal Checks - - CHECK("tb_fetch.interrupt_on_output_handshake.01", - tb->conditions[COND_wishbone], - "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - - CHECK("tb_fetch.interrupt_on_output_handshake.02", - tb->conditions[COND_output_valid], - "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); -} - -void tb_fetch_interrupt_during_pipeline_stall(TB_Fetch * tb) { - Vtb_fetch * core = tb->core; - core->testcase = T_INTERRUPT_DURING_PIPELINE_STALL; - - // The following actions are performed in this test : - // tick 0. Set inputs for pipeline stall not interrupt - // tick 1. Acknowledge request with response data (core makes request) - // tick 2. Nothing (core latches response) - // tick 3. Interrupt request (core holds response) - // tick 4. Nothing (core holds response) - // tick 5. Nothing (core cancels response) - // tick 6. Nothing (core makes request) - - //================================= - // Tick (0) - - tb->reset(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 0; - core->drq_i = 0; - core->branch_i = 0; - core->output_ready_i = 0; - core->wb_stall_i = 0; - - //================================= - // Tick (1) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - uint32_t data = rand(); - core->wb_dat_i = data; - core->wb_ack_i = 1; - - //================================= - // Tick (2) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->wb_dat_i = 0; - core->wb_ack_i = 0; - - //================================= - // Tick (3) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 1; - - //================================= - // Tick (4) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 0; - - //================================= - // Tick (5) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_output_valid, (core->output_valid_o == 0)); - - //================================= - // Tick (6) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_wishbone, (core->wb_adr_o == Vtb_fetch_ecap5_dproc_pkg::INTERRUPT_ADDRESS)); - - //````````````````````````````````` - // Formal Checks - - CHECK("tb_fetch.interrupt_during_pipeline_stall.01", - tb->conditions[COND_wishbone], - "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - - CHECK("tb_fetch.interrupt_during_pipeline_stall.02", - tb->conditions[COND_output_valid], - "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); -} - -void tb_fetch_interrupt_back_to_back(TB_Fetch * tb) { - Vtb_fetch * core = tb->core; - core->testcase = T_INTERRUPT_BACK_TO_BACK; - - // The following actions are performed in this test : - // tick 0. Set inputs for no stall not interrupt - // tick 1. Acknowledge request with response data and interrupt request (core makes request) - // tick 2. Interrupt request (core latches response) - // tick 3. Nothing (core cancels output) - // tick 4. Nothing (core makes request) - - //================================= - // Tick (0) - - tb->reset(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 0; - core->drq_i = 0; - core->branch_i = 0; - core->output_ready_i = 1; - core->wb_stall_i = 0; - - //================================= - // Tick (1) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - uint32_t data = rand(); - core->wb_dat_i = data; - core->wb_ack_i = 1; - - core->irq_i = 1; - - //================================= - // Tick (2) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 1; - - core->wb_dat_i = 0; - core->wb_ack_i = 0; - - //================================= - // Tick (3) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_output_valid, (core->output_valid_o == 0)); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 0; - - //================================= - // Tick (4) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_wishbone, (core->wb_adr_o == Vtb_fetch_ecap5_dproc_pkg::INTERRUPT_ADDRESS)); - - //````````````````````````````````` - // Formal Checks - - CHECK("tb_fetch.interrupt_back_to_back.01", - tb->conditions[COND_wishbone], - "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - - CHECK("tb_fetch.interrupt_back_to_back.02", - tb->conditions[COND_output_valid], - "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); -} - -/*============================================*/ -/* Branch */ -/*============================================*/ - -void tb_fetch_branch_during_request(TB_Fetch * tb) { - Vtb_fetch * core = tb->core; - core->testcase = T_BRANCH_DURING_REQUEST; - - // The following actions are performed in this test : - // tick 0. Set inputs for no stall with branch request - // tick 1. Acknowledge request with response data (core makes request) - // tick 2. Nothing (core latches response) - // tick 3. Nothing (core cancels output) - // tick 4. Nothing (core makes request) - - //================================= - // Tick (0) - - tb->reset(); - - // Leave the reset state - core->irq_i = 0; - core->drq_i = 0; - core->branch_i = 0; - core->output_ready_i = 1; - core->wb_stall_i = 0; - - core->branch_i = 1; - uint32_t branch_target = rand() % 0xFFFFF; - core->branch_target_i = branch_target; - - //================================= - // Tick (1) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_wishbone, (core->wb_adr_o == Vtb_fetch_ecap5_dproc_pkg::BOOT_ADDRESS)); - - //````````````````````````````````` - // Set inputs - - uint32_t data = rand(); - core->wb_dat_i = data; - core->wb_ack_i = 1; - - core->branch_i = 0; - - //================================= - // Tick (2) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->wb_dat_i = 0; - core->wb_ack_i = 0; - - //================================= - // Tick (3) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_output_valid, (core->output_valid_o == 0)); - - //================================= - // Tick (4) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_wishbone, (core->wb_adr_o == branch_target)); - - //````````````````````````````````` - // Formal Checks - - CHECK("tb_fetch.branch_during_request.01", - tb->conditions[COND_wishbone], - "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - - CHECK("tb_fetch.branch_during_request.02", - tb->conditions[COND_output_valid], - "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); -} - -void tb_fetch_branch_during_ack(TB_Fetch * tb) { - Vtb_fetch * core = tb->core; - core->testcase = T_BRANCH_DURING_ACK; - - // The following actions are performed in this test : - // tick 0. Set inputs for no stall not interrupt - // tick 1. Acknowledge request with response data and branch request (core makes request) - // tick 2. Nothing (core latches response) - // tick 3. Nothing (core outputs response) - // tick 4. Nothing (core makes request) - - //================================= - // Tick (0) - - tb->reset(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 0; - core->drq_i = 0; - core->branch_i = 0; - core->output_ready_i = 1; - core->wb_stall_i = 0; - - //================================= - // Tick (1) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->branch_i = 1; - uint32_t branch_target = rand() % 0xFFFFF; - core->branch_target_i = branch_target; - - uint32_t data = rand(); - core->wb_dat_i = data; - core->wb_ack_i = 1; - - //================================= - // Tick (2) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->branch_i = 0; - - core->wb_dat_i = 0; - core->wb_ack_i = 0; - - //================================= - // Tick (3) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_output_valid, (core->output_valid_o == 0)); - - //================================= - // Tick (4) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_wishbone, (core->wb_adr_o == branch_target)); - - //````````````````````````````````` - // Formal Checks - - CHECK("tb_fetch.branch_during_ack.01", - tb->conditions[COND_wishbone], - "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - - CHECK("tb_fetch.branch_during_ack.02", - tb->conditions[COND_output_valid], - "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); -} - -void tb_fetch_branch_during_wait(TB_Fetch * tb) { - Vtb_fetch * core = tb->core; - core->testcase = T_BRANCH_DURING_WAIT; - - // The following actions are performed in this test : - // tick 0. Set inputs for no stall not interrupt - // tick 1. Nothing (core waits response) - // tick 2. Branch request (core waits response) - // tick 3. Nothing (core waits response) - // tick 4. Acknowledge request with response data (core waits response) - // tick 5. Nothing (core latches response) - // tick 6. Nothing (core output cancelled) - // tick 7. Nothing (core makes request) - - //================================= - // Tick (0) - - tb->reset(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 0; - core->drq_i = 0; - core->branch_i = 0; - core->output_ready_i = 1; - core->wb_stall_i = 0; - - //================================= - // Tick (1) - - tb->tick(); - - //================================= - // Tick (2) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->branch_i = 1; - uint32_t branch_target = rand() % 0xFFFFF; - core->branch_target_i = branch_target; - - //================================= - // Tick (3) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->branch_i = 0; - - //================================= - // Tick (4) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - uint32_t data = rand(); - core->wb_dat_i = data; - core->wb_ack_i = 1; - - //================================= - // Tick (5) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->wb_dat_i = 0; - core->wb_ack_i = 0; - - //================================= - // Tick (6) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_output_valid, (core->output_valid_o == 0)); - - //================================= - // Tick (7) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_wishbone, (core->wb_adr_o == branch_target)); - - //````````````````````````````````` - // Formal Checks - - CHECK("tb_fetch.branch_during_wait.01", - tb->conditions[COND_wishbone], - "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - - CHECK("tb_fetch.branch_during_wait.02", - tb->conditions[COND_output_valid], - "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); -} - -void tb_fetch_branch_during_memory_stall(TB_Fetch * tb) { - Vtb_fetch * core = tb->core; - core->testcase = T_BRANCH_DURING_MEMORY_STALL; - - // The following actions are performed in this test : - // tick 0. Set inputs for memory stall not interrupt - // tick 1. Nothing (core holds request) - // tick 2. Branch request (core holds request) - // tick 3. Nothing (core holds request) - // tick 4. Unstall memory (core holds request) - // tick 5. Acknowledge request with response data (core latches response) - // tick 6. Nothing (core latches response) - // tick 7. Nothing (core output cancelled) - // tick 8. Nothing (core makes request) - - //================================= - // Tick (0) - - tb->reset(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 0; - core->drq_i = 0; - core->branch_i = 0; - core->output_ready_i = 1; - core->wb_stall_i = 1; - - //================================= - // Tick (1) - - tb->tick(); - - //================================= - // Tick (2) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->branch_i = 1; - uint32_t branch_target = rand() % 0xFFFFF; - core->branch_target_i = branch_target; - - //================================= - // Tick (3) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->branch_i = 0; - - //================================= - // Tick (4) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->wb_stall_i = 0; - - //================================= - // Tick (5) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - uint32_t data = rand(); - core->wb_dat_i = data; - core->wb_ack_i = 1; - - //================================= - // Tick (6) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->wb_dat_i = 0; - core->wb_ack_i = 0; - - //================================= - // Tick (7) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_output_valid, (core->output_valid_o == 0)); - - //================================= - // Tick (8) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_wishbone, (core->wb_adr_o == branch_target)); - - //````````````````````````````````` - // Formal Checks - - CHECK("tb_fetch.branch_during_memory_stall.01", - tb->conditions[COND_wishbone], - "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - - CHECK("tb_fetch.branch_during_memory_stall.02", - tb->conditions[COND_output_valid], - "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); -} - -void tb_fetch_branch_on_output_handshake(TB_Fetch * tb) { - Vtb_fetch * core = tb->core; - core->testcase = T_BRANCH_ON_OUTPUT_HANDSHAKE; - - // The following actions are performed in this test : - // tick 0. Set inputs for no stall not interrupt - // tick 1. Acknowledge request with response data (core makes request) - // tick 2. Branch request (core latches response) - // tick 3. Nothing (core outputs response) - // tick 4. Nothing (core makes request) - - //================================= - // Tick (0) - - tb->reset(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 0; - core->drq_i = 0; - core->branch_i = 0; - core->output_ready_i = 1; - core->wb_stall_i = 0; - - //================================= - // Tick (1) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - uint32_t data = rand(); - core->wb_dat_i = data; - core->wb_ack_i = 1; - - //================================= - // Tick (2) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->wb_dat_i = 0; - core->wb_ack_i = 0; - - core->branch_i = 1; - uint32_t branch_target = rand() % 0xFFFFF; - core->branch_target_i = branch_target; - - //================================= - // Tick (3) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->branch_i = 0; - - //````````````````````````````````` - // Checks - - tb->check(COND_output_valid, (core->output_valid_o == 1)); - - //================================= - // Tick (4) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_wishbone, (core->wb_adr_o == branch_target)); - - //````````````````````````````````` - // Formal Checks - - CHECK("tb_fetch.branch_on_output_handshake.01", - tb->conditions[COND_wishbone], - "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - - CHECK("tb_fetch.branch_on_output_handshake.02", - tb->conditions[COND_output_valid], - "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); -} - -void tb_fetch_branch_during_pipeline_stall(TB_Fetch * tb) { - Vtb_fetch * core = tb->core; - core->testcase = T_BRANCH_DURING_PIPELINE_STALL; - - // The following actions are performed in this test : - // tick 0. Set inputs for pipeline stall not interrupt - // tick 1. Acknowledge request with response data (core makes request) - // tick 2. Nothing (core latches response) - // tick 3. Branch request (core holds response) - // tick 4. Nothing (core holds response) - // tick 5. Nothing (core cancels response) - // tick 6. Nothing (core makes request) - - //================================= - // Tick (0) - - tb->reset(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 0; - core->drq_i = 0; - core->branch_i = 0; - core->output_ready_i = 0; - core->wb_stall_i = 0; - - //================================= - // Tick (1) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - uint32_t data = rand(); - core->wb_dat_i = data; - core->wb_ack_i = 1; - - //================================= - // Tick (2) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->wb_dat_i = 0; - core->wb_ack_i = 0; - - //================================= - // Tick (3) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->branch_i = 1; - uint32_t branch_target = rand() % 0xFFFFF; - core->branch_target_i = branch_target; - - //================================= - // Tick (4) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->branch_i = 0; - - //================================= - // Tick (5) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_output_valid, (core->output_valid_o == 0)); - - //================================= - // Tick (6) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_wishbone, (core->wb_adr_o == branch_target)); - - //````````````````````````````````` - // Formal Checks - - CHECK("tb_fetch.branch_during_pipeline_stall.01", - tb->conditions[COND_wishbone], - "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - - CHECK("tb_fetch.branch_during_pipeline_stall.02", - tb->conditions[COND_output_valid], - "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); -} - -void tb_fetch_branch_back_to_back(TB_Fetch * tb) { - Vtb_fetch * core = tb->core; - core->testcase = T_BRANCH_BACK_TO_BACK; - - // The following actions are performed in this test : - // tick 0. Set inputs for no stall not interrupt - // tick 1. Acknowledge request with response data and interrupt request (core makes request) - // tick 2. Branch request (core latches response) - // tick 3. Nothing (core cancels output) - // tick 4. Nothing (core makes request) - - //================================= - // Tick (0) - - tb->reset(); - - //````````````````````````````````` - // Set inputs - - core->irq_i = 0; - core->drq_i = 0; - core->branch_i = 0; - core->output_ready_i = 1; - core->wb_stall_i = 0; - - //================================= - // Tick (1) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - uint32_t data = rand(); - core->wb_dat_i = data; - core->wb_ack_i = 1; - - core->branch_i = 1; - uint32_t branch_target = rand() % 0xFFFFF; - core->branch_target_i = branch_target; - - //================================= - // Tick (2) - - tb->tick(); - - //````````````````````````````````` - // Set inputs - - core->branch_i = 1; - core->branch_target_i = rand(); - - core->wb_dat_i = 0; - core->wb_ack_i = 0; - - //================================= - // Tick (3) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_output_valid, (core->output_valid_o == 0)); - - //````````````````````````````````` - // Set inputs - - core->branch_i = 0; - - //================================= - // Tick (4) - - tb->tick(); - - //````````````````````````````````` - // Checks - - tb->check(COND_wishbone, (core->wb_adr_o == branch_target)); - - //````````````````````````````````` - // Formal Checks - - CHECK("tb_fetch.branch_back_to_back.01", - tb->conditions[COND_wishbone], - "Failed to implement the wishbone protocol", tb->err_cycles[COND_wishbone]); - - CHECK("tb_fetch.branch_back_to_back.02", - tb->conditions[COND_output_valid], - "Failed to implement the output_valid_o signal", tb->err_cycles[COND_output_valid]); -} - -/*============================================*/ -/* Precedence */ -/*============================================*/ - void tb_fetch_precedence_debug(TB_Fetch * tb) { Vtb_fetch * core = tb->core; core->testcase = T_PRECEDENCE_DEBUG; @@ -2969,29 +1532,13 @@ int main(int argc, char ** argv, char ** env) { tb_fetch_pipeline_stall(tb); - tb_fetch_debug_during_request(tb); - tb_fetch_debug_during_ack(tb); - tb_fetch_debug_during_wait(tb); - tb_fetch_debug_during_memory_stall(tb); - tb_fetch_debug_on_output_handshake(tb); - tb_fetch_debug_during_pipeline_stall(tb); - tb_fetch_debug_back_to_back(tb); - - tb_fetch_interrupt_during_request(tb); - tb_fetch_interrupt_during_ack(tb); - tb_fetch_interrupt_during_wait(tb); - tb_fetch_interrupt_during_memory_stall(tb); - tb_fetch_interrupt_on_output_handshake(tb); - tb_fetch_interrupt_during_pipeline_stall(tb); - tb_fetch_interrupt_back_to_back(tb); - - tb_fetch_branch_during_request(tb); - tb_fetch_branch_during_ack(tb); - tb_fetch_branch_during_wait(tb); - tb_fetch_branch_during_memory_stall(tb); - tb_fetch_branch_on_output_handshake(tb); - tb_fetch_branch_during_pipeline_stall(tb); - tb_fetch_branch_back_to_back(tb); + tb_fetch_jump_after_reset(tb); + tb_fetch_jump_during_ack(tb); + tb_fetch_jump_during_wait(tb); + tb_fetch_jump_during_memory_stall(tb); + tb_fetch_jump_on_output_handshake(tb); + tb_fetch_jump_during_pipeline_stall(tb); + tb_fetch_jump_back_to_back(tb); tb_fetch_precedence_debug(tb); tb_fetch_precedence_interrupt(tb); diff --git a/tests/riscv-tests/CMakeLists.txt b/tests/riscv-tests/CMakeLists.txt index f62eaf3..f88918e 100644 --- a/tests/riscv-tests/CMakeLists.txt +++ b/tests/riscv-tests/CMakeLists.txt @@ -68,12 +68,17 @@ set(TARGETS simple set(ALL_TARGETS) foreach(TARGET IN LISTS TARGETS) set(FULL_TARGET ${TVM}-${TE}-${TARGET}) - add_executable(${FULL_TARGET} ${SOURCE_DIR}/${TARGET}.S) - set_target_properties(${FULL_TARGET} PROPERTIES COMPILE_FLAGS "${CC_OPTS} -march=rv32g -mabi=ilp32" - LINK_FLAGS "${CC_OPTS} -march=rv32g -mabi=ilp32 -T${ENV_DIR}/link.ld") - target_include_directories(${FULL_TARGET} PRIVATE ${CC_INCS}) + add_executable(${FULL_TARGET}.elf ${SOURCE_DIR}/${TARGET}.S) + set_target_properties(${FULL_TARGET}.elf PROPERTIES COMPILE_FLAGS "${CC_OPTS} -march=rv32g -mabi=ilp32" + LINK_FLAGS "${CC_OPTS} -march=rv32g -mabi=ilp32 -T${ENV_DIR}/link.ld") + target_include_directories(${FULL_TARGET}.elf PRIVATE ${CC_INCS}) - list(APPEND ALL_TARGETS ${FULL_TARGET}) + add_custom_command( + OUTPUT ${FULL_TARGET}.dump + COMMAND ${CROSS_COMPILE}objdump -d ${FULL_TARGET}.elf -Mno-aliases -Mnumeric > ${FULL_TARGET}.dump + VERBATIM) + + list(APPEND ALL_TARGETS ${FULL_TARGET}.elf ${FULL_TARGET}.dump) endforeach() add_custom_target(riscv-tests-binaries DEPENDS ${ALL_TARGETS}) diff --git a/tests/riscv-tests/env/riscv_test.h b/tests/riscv-tests/env/riscv_test.h index ed9bc17..47822e4 100644 --- a/tests/riscv-tests/env/riscv_test.h +++ b/tests/riscv-tests/env/riscv_test.h @@ -185,19 +185,23 @@ _start: \ #define RVTEST_CODE_END \ _end: \ - j _end + li t0, 0xFFEEBBCC; \ + jr t0 //----------------------------------------------------------------------- // Pass/Fail Macro //----------------------------------------------------------------------- -#define TESTNUM gp +#define TESTNUM x3 +#define TESTRES x4 #define RVTEST_PASS \ - li TESTNUM, 1; \ + li TESTRES, 1; \ + j _end #define RVTEST_FAIL \ - li TESTNUM, 0; + li TESTRES, 0; \ + j _end //----------------------------------------------------------------------- // Data Section Macro diff --git a/tests/riscv-tests/riscv-tests.cpp b/tests/riscv-tests/riscv-tests.cpp index 8f4d39a..0d0964e 100644 --- a/tests/riscv-tests/riscv-tests.cpp +++ b/tests/riscv-tests/riscv-tests.cpp @@ -34,13 +34,19 @@ #define KO * 1024 #define MAX_BINARY_SIZE (32 KO) -#define MAX_TICKCOUNT 1000 +#define MAX_TICKCOUNT 3000 + +#define END_ADDRESS 0xFFEEBBCC class TB_Riscv_tests: public Testbench { public: uint8_t memory[MAX_BINARY_SIZE]; + bool is_done; void reset() { + this->is_done = 0; + this->tickcount = 0; + this->core->rst_i = 1; for(int i = 0; i < 5; i++) { this->tick(); @@ -60,25 +66,48 @@ class TB_Riscv_tests: public Testbench { switch(state) { case 0: { if((this->core->wb_stb_o == 1) && (this->core->wb_cyc_o == 1)) { + uint32_t data = 0; + // check test end + if(this->core->wb_adr_o == END_ADDRESS) { + this->is_done = 1; // check overflow - uint32_t data; - if(this->core->wb_adr_o >= MAX_BINARY_SIZE) { + } else if(this->core->wb_adr_o >= MAX_BINARY_SIZE) { printf("Runtime memory overflow\n Requested address : %08x, Memory end address : %08x\n\n", this->core->wb_adr_o, MAX_BINARY_SIZE-1); - data = 0; } else { - memcpy(&data, memory + this->core->wb_adr_o, 4); - switch(this->core->wb_sel_o) { - case 0x1: - data &= 0xFF; - break; - case 0x3: - data &= 0xFFFF; - break; - case 0xF: - break; - default: - printf("Invalid wishbone sel signal : %08x\n", this->core->wb_sel_o); - break; + if(this->core->wb_we_o == 0) { + // Read + memcpy(&data, memory + this->core->wb_adr_o, 4); + switch(this->core->wb_sel_o) { + case 0x1: + data &= 0xFF; + break; + case 0x3: + data &= 0xFFFF; + break; + case 0xF: + break; + default: + printf("Invalid wishbone sel signal during read: %08x\n", this->core->wb_sel_o); + break; + } + } else { + // Write + uint8_t size = 0; + switch(this->core->wb_sel_o) { + case 0x1: + size = 1; + break; + case 0x3: + size = 2; + break; + case 0xF: + size = 4; + break; + default: + printf("Invalid wishbone sel signal during write: %08x\n", this->core->wb_sel_o); + break; + } + memcpy(memory + this->core->wb_adr_o, &this->core->wb_dat_o, size); } } this->core->wb_dat_i = data; @@ -208,17 +237,1135 @@ class TB_Riscv_tests: public Testbench { fclose(fd); } + + void get_register(uint8_t addr, uint32_t * value) { + const svScope scope = svGetScopeFromName("TOP.ecap5_dproc.regs_inst"); + assert(scope); + svSetScope(scope); + this->core->get_register_value((svLogicVecVal*)&addr, (svLogicVecVal*)value); + } }; void tb_riscv_tests_simple(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-simple.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-simple.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + CHECK("riscv-tests.simple.01", + tb->is_done, + "Failed to terminate (timeout)"); + CHECK("riscv-tests.simple.02", + true, + "Failed"); + + tb->close_trace(); +} + +void tb_riscv_tests_add(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-add.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-add.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.add.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.add.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_addi(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-addi.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-addi.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.addi.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.addi.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_and(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-and.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-and.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.and.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.and.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_andi(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-andi.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-andi.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.andi.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.andi.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_auipc(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-auipc.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-auipc.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.auipc.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.auipc.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_beq(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-beq.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-beq.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.beq.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.beq.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_bge(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-bge.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-bge.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.bge.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.bge.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_bgeu(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-bgeu.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-bgeu.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.bgeu.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.bgeu.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_blt(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-blt.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-blt.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.blt.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.blt.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_bltu(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-bltu.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-bltu.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.bltu.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.bltu.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_bne(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-bne.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-bne.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.bne.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.bne.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_fence_i(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-fence_i.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-fence_i.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.fence_i.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.fence_i.02", + result == 1, + "Failed during testcase", testcase); + + CHECK("riscv-tests.fence_i.TODO", + 0, + "TODO"); + + tb->close_trace(); +} + +void tb_riscv_tests_jal(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-jal.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-jal.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.jal.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.jal.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_jalr(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-jalr.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-jalr.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.jalr.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.jalr.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_lb(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-lb.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-lb.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.lb.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.lb.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_lbu(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-lbu.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-lbu.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.lbu.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.lbu.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_lh(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-lh.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-lh.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.lh.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.lh.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_lhu(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-lhu.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-lhu.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.lhu.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.lhu.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_lw(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-lw.vcd"); + Vecap5_dproc * core = tb->core; tb->reset(); - tb->set_memory("riscv-tests/rv32ui-p-simple"); + tb->set_memory("riscv-tests/rv32ui-p-lw.elf"); - while(tb->tickcount < MAX_TICKCOUNT) { + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { tb->tick(); } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.lw.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.lw.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_lui(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-lui.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-lui.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.lui.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.lui.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_ma_data(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-ma_data.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-ma_data.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.ma_data.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.ma_data.02", + result == 1, + "Failed during testcase", testcase); + + CHECK("riscv-tests.ma_data.TODO", + 0, + "TODO"); + + tb->close_trace(); +} + +void tb_riscv_tests_or(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-or.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-or.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.or.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.or.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_ori(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-ori.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-ori.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.ori.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.ori.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_sb(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-sb.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-sb.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.sb.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.sb.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_sh(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-sh.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-sh.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.sh.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.sh.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_sw(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-sw.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-sw.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.sw.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.sw.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_sll(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-sll.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-sll.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.sll.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.sll.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_slli(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-slli.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-slli.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.slli.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.slli.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_slt(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-slt.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-slt.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.slt.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.slt.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_slti(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-slti.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-slti.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.slti.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.slti.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_sltiu(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-sltiu.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-sltiu.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.sltiu.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.sltiu.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_sltu(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-sltu.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-sltu.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.sltu.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.sltu.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_sra(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-sra.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-sra.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.sra.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.sra.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_srai(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-srai.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-srai.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.srai.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.srai.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_srl(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-srl.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-srl.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.srl.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.srl.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_srli(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-srli.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-srli.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.srli.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.srli.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_sub(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-sub.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-sub.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.sub.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.sub.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_xor(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-xor.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-xor.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.xor.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.xor.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); +} + +void tb_riscv_tests_xori(TB_Riscv_tests * tb) { + tb->open_trace("waves/riscv-tests-xori.vcd"); + + Vecap5_dproc * core = tb->core; + tb->reset(); + + tb->set_memory("riscv-tests/rv32ui-p-xori.elf"); + + while(!tb->is_done && tb->tickcount < MAX_TICKCOUNT) { + tb->tick(); + } + + uint32_t testcase; + tb->get_register(3, &testcase); + uint32_t result; + tb->get_register(4, &result); + + CHECK("riscv-tests.xori.01", + tb->is_done, + "Failed to terminate (timeout)"); + + CHECK("riscv-tests.xori.02", + result == 1, + "Failed during testcase", testcase); + + tb->close_trace(); } int main(int argc, char ** argv, char ** env) { @@ -229,13 +1376,51 @@ int main(int argc, char ** argv, char ** env) { bool verbose = parse_verbose(argc, argv); TB_Riscv_tests * tb = new TB_Riscv_tests(); - tb->open_trace("waves/riscv-tests.vcd"); tb->open_testdata("testdata/riscv-tests.csv"); tb->set_debug_log(verbose); /************************************************************/ tb_riscv_tests_simple(tb); + tb_riscv_tests_add(tb); + tb_riscv_tests_addi(tb); + tb_riscv_tests_and(tb); + tb_riscv_tests_andi(tb); + tb_riscv_tests_auipc(tb); + tb_riscv_tests_beq(tb); + tb_riscv_tests_bge(tb); + tb_riscv_tests_bgeu(tb); + tb_riscv_tests_blt(tb); + tb_riscv_tests_bltu(tb); + tb_riscv_tests_bne(tb); + tb_riscv_tests_fence_i(tb); + tb_riscv_tests_jal(tb); + tb_riscv_tests_jalr(tb); + tb_riscv_tests_lb(tb); + tb_riscv_tests_lbu(tb); + tb_riscv_tests_lh(tb); + tb_riscv_tests_lhu(tb); + tb_riscv_tests_lw(tb); + tb_riscv_tests_lui(tb); + tb_riscv_tests_ma_data(tb); + tb_riscv_tests_or(tb); + tb_riscv_tests_ori(tb); + tb_riscv_tests_sb(tb); + tb_riscv_tests_sh(tb); + tb_riscv_tests_sw(tb); + tb_riscv_tests_sll(tb); + tb_riscv_tests_slli(tb); + tb_riscv_tests_slt(tb); + tb_riscv_tests_slti(tb); + tb_riscv_tests_sltiu(tb); + tb_riscv_tests_sltu(tb); + tb_riscv_tests_sra(tb); + tb_riscv_tests_srai(tb); + tb_riscv_tests_srl(tb); + tb_riscv_tests_srli(tb); + tb_riscv_tests_sub(tb); + tb_riscv_tests_xor(tb); + tb_riscv_tests_xori(tb); /************************************************************/ From 1409d1cd7988c318a26a7d474818aac143a821cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chaine?= Date: Thu, 2 May 2024 14:58:35 +0000 Subject: [PATCH 8/9] Fixes x0 register not being zero --- config/treq.json | 2 +- docs/CMakeLists.txt | 1 + docs/src/_static/css/custom.css | 85 +++++++++++++++++++++++++++++++ docs/src/assets/logo.svg | 31 +++++++++++ docs/src/conf.py | 1 + src/regs.sv | 4 +- tests/CMakeLists.txt | 10 ++-- tests/benches/regs/tb_regs.cpp | 46 +++++++++++++++-- tests/riscv-tests/riscv-tests.cpp | 7 +++ 9 files changed, 177 insertions(+), 10 deletions(-) create mode 100644 docs/src/assets/logo.svg diff --git a/config/treq.json b/config/treq.json index b427bb4..7011d82 100644 --- a/config/treq.json +++ b/config/treq.json @@ -1,6 +1,6 @@ { "spec_dir_path": "../docs/src/arch", - "test_dir_path": "../tests/benches/", + "test_dir_path": "../tests/", "testdata_dir_path": "../build/tests/testdata/", "matrix_path": "../config/traceability-matrix.csv", "spec_format" : "RST" diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index e4e2c0c..9df6c3e 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -8,6 +8,7 @@ if(Sphinx_FOUND) "${CMAKE_CURRENT_LIST_DIR}/src/_ext/requirement.py" "${CMAKE_CURRENT_LIST_DIR}/src/_static/css/custom.css" "${CMAKE_CURRENT_LIST_DIR}/src/assets/architecture.svg" + "${CMAKE_CURRENT_LIST_DIR}/src/assets/logo.svg" "${CMAKE_CURRENT_LIST_DIR}/src/index.rst" "${CMAKE_CURRENT_LIST_DIR}/src/arch/index.rst" "${CMAKE_CURRENT_LIST_DIR}/src/arch/1_introduction.rst" diff --git a/docs/src/_static/css/custom.css b/docs/src/_static/css/custom.css index 25a4aa1..fa0dd2b 100644 --- a/docs/src/_static/css/custom.css +++ b/docs/src/_static/css/custom.css @@ -1,3 +1,88 @@ .wy-table-responsive table td, .wy-table-responsive table th { white-space: inherit; } + +.wy-side-nav-search .wy-dropdown>a.icon img.logo, .wy-side-nav-search>a.icon img.logo { + width: 60%; + border-radius: 15px; +} + +.wy-side-nav-search .wy-dropdown>a, .wy-side-nav-search>a { + color: white; +} + +.wy-side-nav-search .wy-dropdown>a:visited, .wy-side-nav-search>a:visited { + color: white; +} + +.wy-nav-top { + background-color: #d22a46; +} + +.wy-nav-top a{ + color: white; +} + +.wy-nav-top a:visited { + color: white; +} + +.icon-home { + color: #d22a46; +} + +.icon-home:visited { + color: #d22a46; +} + +.wy-side-nav-search { + background-color: #251a1b; +} + +.wy-menu-vertical header, .wy-menu-vertical p.caption { + color: white; +} + +.breadcrumb-item a { + color: #d22a46; +} +.breadcrumb-item a:visited { + color: #d22a46; +} +.wy-breadcrumbs-aside a { + color: #d22a46; +} +.wy-breadcrumbs-aside a:visited { + color: #d22a46; +} + +a:visited { + color: #2980b9; +} + +footer a{ + color: #d22a46; +} +footer a:visited { + color: #d22a46; +} + +.wy-menu-vertical li { + background-color: white; +} +.wy-menu-vertical a{ + color: #343131; +} +.wy-menu-vertical a:visited{ + color: #343131; +} +.wy-menu-vertical a:hover { + color: #404040; + background-color: #d6d6d6; +} +.wy-menu-vertical a:hover button.toctree-expand { + color: #a3A3A3; +} +.wy-menu-vertical a button.toctree-expand { + color: #a3A3A3; +} diff --git a/docs/src/assets/logo.svg b/docs/src/assets/logo.svg new file mode 100644 index 0000000..b86bf13 --- /dev/null +++ b/docs/src/assets/logo.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/src/conf.py b/docs/src/conf.py index b6f4b0b..2f35d62 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -30,6 +30,7 @@ html_theme = 'sphinx_rtd_theme' html_static_path = ['_static'] +html_logo = 'assets/logo.svg' html_theme_options = { 'display_version': True, 'collapse_navigation': False, diff --git a/src/regs.sv b/src/regs.sv index 49b2e81..ef66e7c 100644 --- a/src/regs.sv +++ b/src/regs.sv @@ -44,8 +44,8 @@ always @ (posedge clk_i) begin end end -assign rdata1_o = registers[raddr1_i]; -assign rdata2_o = registers[raddr2_i]; +assign rdata1_o = raddr1_i == '0 ? '0 : registers[raddr1_i]; +assign rdata2_o = raddr2_i == '0 ? '0 : registers[raddr2_i]; `ifdef VERILATOR export "DPI-C" task set_register_value; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a79559a..2cc8f02 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -110,10 +110,7 @@ add_testbench(memory) add_testbench(hazard) add_testbench(ecap5_dproc PUBLIC) -# Main targets -add_custom_target(build DEPENDS ${TEST_BINARIES}) -add_custom_target(tests DEPENDS ${TEST_TARGETS}) - +# riscv-tests add_subdirectory(riscv-tests) add_executable(riscv-tests-executable ${CMAKE_CURRENT_SOURCE_DIR}/riscv-tests/riscv-tests.cpp) add_dependencies(riscv-tests-executable riscv-tests-binaries) @@ -134,3 +131,8 @@ add_custom_command( DEPENDS riscv-tests-executable WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}) add_custom_target(riscv-tests DEPENDS ${TESTDATA_DIR}/riscv-tests.csv) + +# Main targets +add_custom_target(build DEPENDS ${TEST_BINARIES} riscv-tests-executable) +add_custom_target(tests DEPENDS ${TEST_TARGETS} riscv-tests) + diff --git a/tests/benches/regs/tb_regs.cpp b/tests/benches/regs/tb_regs.cpp index 5f39054..765cd44 100644 --- a/tests/benches/regs/tb_regs.cpp +++ b/tests/benches/regs/tb_regs.cpp @@ -42,7 +42,8 @@ enum TestcaseId { T_WRITE_X0 = 3, T_WRITE = 4, T_PARALLEL_READ = 5, - T_READ_BEFORE_WRITE = 6 + T_READ_BEFORE_WRITE = 6, + T_READ_X0 = 7 }; class TB_Regs : public Testbench { @@ -61,6 +62,43 @@ class TB_Regs : public Testbench { } }; +void tb_regs_read_x0(TB_Regs * tb) { + Vtb_regs * core = tb->core; + core->testcase = T_READ_X0; + + // The following actions are performed in this test : + // tick 0. Set the inputs to read x0 through port a + // tick 1. Set the inputs to read x0 through port b + + tb->reset(); + + core->raddr1_i = 0; + core->write_i = 0; + + //================================= + // Tick (0) + + tb->tick(); + + //````````````````````````````````` + // Checks + + tb->check(COND_read, (core->rdata1_o == 0)); + + //````````````````````````````````` + // Set inputs + + core->raddr2_i = 0; + tb->check(COND_read, (core->rdata2_o == 0)); + + //````````````````````````````````` + // Formal Checks + + CHECK("tb_regs.read_x0.01", + tb->conditions[COND_read], + "Failed to read registers x0", tb->err_cycles[COND_read]); +} + void tb_regs_read_port_a(TB_Regs * tb) { Vtb_regs * core = tb->core; core->testcase = T_READ_PORTA; @@ -70,7 +108,7 @@ void tb_regs_read_port_a(TB_Regs * tb) { tb->reset(); - for(int i = 0; i < 32; i++) { + for(int i = 1; i < 32; i++) { //````````````````````````````````` // Set inputs @@ -108,7 +146,7 @@ void tb_regs_read_port_b(TB_Regs * tb) { tb->reset(); - for(int i = 0; i < 32; i++) { + for(int i = 1; i < 32; i++) { //````````````````````````````````` // Set inputs @@ -343,6 +381,8 @@ int main(int argc, char ** argv, char ** env) { /************************************************************/ + tb_regs_read_x0(tb); + tb_regs_read_port_a(tb); tb_regs_read_port_b(tb); diff --git a/tests/riscv-tests/riscv-tests.cpp b/tests/riscv-tests/riscv-tests.cpp index 0d0964e..c12560a 100644 --- a/tests/riscv-tests/riscv-tests.cpp +++ b/tests/riscv-tests/riscv-tests.cpp @@ -244,6 +244,13 @@ class TB_Riscv_tests: public Testbench { svSetScope(scope); this->core->get_register_value((svLogicVecVal*)&addr, (svLogicVecVal*)value); } + + void close_trace() { + if(this->trace != NULL) { + this->trace->close(); + this->trace = NULL; + } + } }; void tb_riscv_tests_simple(TB_Riscv_tests * tb) { From 701aa13d4d9742e18d4a712520a98b96c335dc76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chaine?= Date: Thu, 2 May 2024 15:03:46 +0000 Subject: [PATCH 9/9] Fix the documentation sidebar logo size when in mobile view --- docs/src/_static/css/custom.css | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/_static/css/custom.css b/docs/src/_static/css/custom.css index fa0dd2b..3786d64 100644 --- a/docs/src/_static/css/custom.css +++ b/docs/src/_static/css/custom.css @@ -4,6 +4,7 @@ .wy-side-nav-search .wy-dropdown>a.icon img.logo, .wy-side-nav-search>a.icon img.logo { width: 60%; + max-width: 300px; border-radius: 15px; }