diff --git a/sim/AtomSim.cpp b/sim/AtomSim.cpp index 17475b08..d04ae90d 100644 --- a/sim/AtomSim.cpp +++ b/sim/AtomSim.cpp @@ -17,9 +17,12 @@ bool verbose_flag = false; bool debug_mode = false; bool trace_enabled = false; bool dump_regs_on_ebreak = false; -bool dump_signature = false; // Global vars +std::string ifile; +#ifdef TARGET_ATOMBONES +std::string signature_file = ""; +#endif const unsigned long int default_mem_size = 134217731; // 128MB (Code & Data) + 3 Bytes (Serial IO) const unsigned int default_entry_point = 0x00000000; const unsigned long int default_maxitr = 10000000; @@ -54,7 +57,7 @@ const std::string AtomSimBackend = "AtomBones"; * @param ifile input file name (pointer) * @param tdir trace_dir (pointer) */ -void parse_commandline_args(int argc, char**argv, std::string &ifile) +void parse_commandline_args(int argc, char**argv, std::string &infile) { try { @@ -67,11 +70,14 @@ void parse_commandline_args(int argc, char**argv, std::string &ifile) options.add_options("General") ("h,help", "Show this message") ("version", "Show version information") - ("i,input", "Specify an input file", cxxopts::value(ifile)); + ("i,input", "Specify an input file", cxxopts::value(infile)); options.add_options("Config") ("maxitr", "Specify maximum simulation iterations", cxxopts::value(maxitr)) - ("memsize", "Specify size of memory to simulate (Supported in AtomBones)", cxxopts::value(mem_size)); + #ifdef TARGET_ATOMBONES + ("memsize", "Specify size of memory to simulate", cxxopts::value(mem_size)) + #endif + ; options.add_options("Debug") ("v,verbose", "Turn on verbose output", cxxopts::value(verbose_flag)->default_value("false")) @@ -80,7 +86,10 @@ void parse_commandline_args(int argc, char**argv, std::string &ifile) ("trace-dir", "Specify a trace directory", cxxopts::value(trace_dir)->default_value(default_trace_dir)) ("dump-dir", "Specify a dump directory", cxxopts::value(dump_dir)->default_value(default_trace_dir)) ("ebreak-dump", "Enable state dump on ebreak", cxxopts::value(dump_regs_on_ebreak)->default_value("false")) - ("signature", "Dump signature after hault (Used for riscv compliance tests)", cxxopts::value(dump_signature)->default_value("false")); + #ifdef TARGET_ATOMBONES + ("signature", "Dump signature after hault (Used for riscv compliance tests)", cxxopts::value(signature_file)->default_value("")) + #endif + ; options.parse_positional({"input"}); @@ -119,7 +128,8 @@ void parse_commandline_args(int argc, char**argv, std::string &ifile) exit(0); } - std::cout << "Input File: " << ifile << "\n"; + if (verbose_flag) + std::cout << "Input File: " << infile << "\n"; } catch(const cxxopts::OptionException& e) @@ -158,7 +168,8 @@ void tick(long unsigned int cycles, Backend * b, const bool show_data = true) if (b->tb->m_core->AtomBones->atom_core->InstructionRegister == 0x100073) { - std::cout << "Exiting @ tick " << b->tb->m_tickcount << " due to ebreak\n"; + if (verbose_flag) + std::cout << "Exiting @ tick " << b->tb->m_tickcount << " due to ebreak\n"; if(dump_regs_on_ebreak) { @@ -179,6 +190,71 @@ void tick(long unsigned int cycles, Backend * b, const bool show_data = true) } fWrite(fcontents, std::string(trace_dir)+"/dump.txt"); } + + #ifdef TARGET_ATOMBONES + if(signature_file.length()!=0) + { + // ============= Get start and end address of signature. ============= + long int begin_signature_at = -1; + long int end_signature_at = -1; + + ELFIO::elfio reader; + + if (!reader.load(ifile)) + { + throwError("SIG", "Can't find or process ELF file : " + ifile + "\n", true); + } + + ELFIO::Elf_Half n = reader.sections.size(); + for ( ELFIO::Elf_Half i = 0; i < n; ++i ) // For all sections + { + ELFIO::section* sec = reader.sections[i]; + if ( SHT_SYMTAB == sec->get_type() || SHT_DYNSYM == sec->get_type() ) + { + ELFIO::symbol_section_accessor symbols( reader, sec ); + ELFIO::Elf_Xword sym_no = symbols.get_symbols_num(); + if ( sym_no > 0 ) + { + for ( ELFIO::Elf_Xword i = 0; i < sym_no; ++i ) { + std::string name; + ELFIO::Elf64_Addr value = 0; + ELFIO::Elf_Xword size = 0; + unsigned char bind = 0; + unsigned char type = 0; + ELFIO::Elf_Half section = 0; + unsigned char other = 0; + symbols.get_symbol( i, name, value, size, bind, type, + section, other ); + + if (name == "begin_signature") + begin_signature_at = value; + if (name == "end_signature") + end_signature_at = value; + } + } + } + } + + if(begin_signature_at == -1 || end_signature_at == -1) + { + throwError("SIG", "One or both of 'begin_signature' & 'end_signature' symbols missing from ELF symbol table: " + ifile + "\n", true); + } + + // ========= dump data to signature file ============== + std::vector fcontents; + printf("Dumping signature region [0x%08lx-0x%08lx]\n", begin_signature_at, end_signature_at); + + for(long int i=begin_signature_at; imem->fetchWord(i)); + fcontents.push_back(temp); + } + fWrite(fcontents, signature_file); + } + #endif + + exit(EXIT_SUCCESS); } if(b->tb->m_tickcount > maxitr) @@ -199,14 +275,13 @@ void tick(long unsigned int cycles, Backend * b, const bool show_data = true) */ int main(int argc, char **argv) { - std::cout << "AtomSim [" << AtomSimBackend << "]\n"; + if (verbose_flag) + std::cout << "AtomSim [" << AtomSimBackend << "]\n"; // Initialize verilator Verilated::commandArgs(argc, argv); - std::string ifile; - // Parse commandline arguments parse_commandline_args(argc, argv, ifile); @@ -345,13 +420,14 @@ int main(int argc, char **argv) } else { - std::cout << "_________________________________________________________________\n"; tick(-1, &bkend, false); } if(trace_enabled) // if trace file is open, close it before exiting bkend.tb->closeTrace(); - std::cout << "Simulation ended @ tick " << bkend.tb->m_tickcount_total << " due to : " << end_simulation_reason << std::endl; + + if (verbose_flag) + std::cout << "Simulation ended @ tick " << bkend.tb->m_tickcount_total << " due to : " << end_simulation_reason << std::endl; exit(EXIT_SUCCESS); } diff --git a/sim/Backend_AtomBones.hpp b/sim/Backend_AtomBones.hpp index 5bd83251..065f56d8 100644 --- a/sim/Backend_AtomBones.hpp +++ b/sim/Backend_AtomBones.hpp @@ -350,7 +350,8 @@ class Backend mem = new Memory(mem_size); unsigned int entry_point = mem->initFromElf(mem_init_file, std::vector{5, 6}); // load text & data sections - printf("Entry point : 0x%08x\n", entry_point); + if (verbose_flag) + printf("Entry point : 0x%08x\n", entry_point); // Set entry point tb->m_core->AtomBones->atom_core->ProgramCounter = entry_point; @@ -363,7 +364,8 @@ class Backend // get input file disassembly disassembly = getDisassembly(mem_init_file); - std::cout << "Initialization complete!\n"; + if (verbose_flag) + std::cout << "Initialization complete!\n"; } diff --git a/sim/defs.hpp b/sim/defs.hpp index 245e54ee..77a5d655 100644 --- a/sim/defs.hpp +++ b/sim/defs.hpp @@ -293,13 +293,11 @@ std::map getDisassembly(std::string filename) // Parse command output std::map dis; - - unsigned long int linebreak = 0; std::string line; while(std::getline(s, line)) { - for(int i=0; i /dev/null),) + $(error Target simulator executable '$(TARGET_SIM)` not found) +endif + +RUN_TARGET= $(TARGET_SIM) --maxitr=100000000 --signature=$(*).signature.output $(<) > $@ + +#RUN_TARGET= $(TARGET_SIM) --maxitr=100000000 $(<) > $(*).signature.output + +RISCV_PREFIX ?= riscv64-unknown-elf- +RISCV_GCC ?= $(RISCV_PREFIX)gcc +RISCV_OBJCOPY ?= $(RISCV_PREFIX)objcopy +RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump +RISCV_GCC_OPTS ?= -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles -march=rv32i -mabi=ilp32 + +COMPILE_TARGET=\ + $$(RISCV_GCC) $(1) $$(RISCV_GCC_OPTS) \ + -I$(ROOTDIR)/riscv-test-env/ \ + -I$(TARGETDIR)/$(RISCV_TARGET)/ \ + -T$(TARGETDIR)/$(RISCV_TARGET)/link.ld $$< \ + -o $$@; \ + $$(RISCV_OBJDUMP) -D $$@ > $$@.objdump; \ \ No newline at end of file diff --git a/test/riscv-target/atombones/link.ld b/test/riscv-target/atombones/link.ld new file mode 100644 index 00000000..6f01f1d4 --- /dev/null +++ b/test/riscv-target/atombones/link.ld @@ -0,0 +1,17 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +SECTIONS +{ + . = 0x00000000; + .text.init : { *(.text.init) } + . = ALIGN(0x1000); + .tohost : { *(.tohost) } + . = ALIGN(0x1000); + .text : { *(.text) } + . = ALIGN(0x1000); + .data : { *(.data) } + .data.string : { *(.data.string)} + .bss : { *(.bss) } + _end = .; +} \ No newline at end of file diff --git a/test/riscv-target/atombones/model_test copy.h b/test/riscv-target/atombones/model_test copy.h new file mode 100644 index 00000000..c81baacc --- /dev/null +++ b/test/riscv-target/atombones/model_test copy.h @@ -0,0 +1,161 @@ +#ifndef _COMPLIANCE_MODEL_H +#define _COMPLIANCE_MODEL_H + +#define RVMODEL_DATA_SECTION \ + .pushsection .tohost,"aw",@progbits; \ + .align 8; .global tohost; tohost: .dword 0; \ + .align 8; .global fromhost; fromhost: .dword 0; \ + .popsection; \ + .align 8; .global begin_regstate; begin_regstate: \ + .word 128; \ + .align 8; .global end_regstate; end_regstate: \ + .word 4; + + +//TODO: Add code here to run after all tests have been run +// The .align 4 ensures that the signature begins at a 16-byte boundary +#define RVMODEL_HALT \ + la a0, rvtest_begin_signatue \ + la a1, rvtest_end_signature \ + li a2, 0x00014001 \ + li a3, 0x00014003 \ + li a4, 0x00000001 \ + print_loop: \ + lw t0, 0(a0) \ + sw t0, 0(a2) \ + \ + sw a4, 0(a3) \ + sw x0, 0(a3) \ + \ + addi a0, a0, 1 \ + beq a0, a1 hault_me \ + j print_loop \ + \ + hault_me: \ + ebreak \ + +//TODO: declare the start of your signature region here. Nothing else to be used here. +// The .align 4 ensures that the signature ends at a 16-byte boundary +#define RVMODEL_DATA_BEGIN \ + .align 4; .global begin_signature; begin_signature: + +//TODO: declare the end of the signature region here. Add other target specific contents here. +#define RVMODEL_DATA_END \ + .alive 4; .global end_signature; end_signature: \ + RVMODEL_DATA_SECTION + + +//RVMODEL_BOOT +//TODO:Any specific target init code should be put here or the macro can be left empty + +// For code that has a split rom/ram area +// Code below will copy from the rom area to ram the +// data.strings and .data sections to ram. +// Use linksplit.ld +#define RVMODEL_BOOT \ + RVTEST_IO_INIT + +// _SP = (volatile register) +//TODO: Macro to output a string to IO +#define LOCAL_IO_WRITE_STR(_STR) RVMODEL_IO_WRITE_STR(x31, _STR) +#define RVMODEL_IO_WRITE_STR(_SP, _STR) \ + .section .data.string; \ +20001: \ + .string _STR; \ + .section .text.init; \ + la a0, 20001b; \ + jal FN_WriteStr; + +#define RSIZE 4 +// _SP = (volatile register) +#define LOCAL_IO_PUSH(_SP) \ + la _SP, begin_regstate; \ + sw ra, (1*RSIZE)(_SP); \ + sw t0, (2*RSIZE)(_SP); \ + sw t1, (3*RSIZE)(_SP); \ + sw t2, (4*RSIZE)(_SP); \ + sw t3, (5*RSIZE)(_SP); \ + sw t4, (6*RSIZE)(_SP); \ + sw s0, (7*RSIZE)(_SP); \ + sw a0, (8*RSIZE)(_SP); + +// _SP = (volatile register) +#define LOCAL_IO_POP(_SP) \ + la _SP, begin_regstate; \ + lw ra, (1*RSIZE)(_SP); \ + lw t0, (2*RSIZE)(_SP); \ + lw t1, (3*RSIZE)(_SP); \ + lw t2, (4*RSIZE)(_SP); \ + lw t3, (5*RSIZE)(_SP); \ + lw t4, (6*RSIZE)(_SP); \ + lw s0, (7*RSIZE)(_SP); \ + lw a0, (8*RSIZE)(_SP); + +//RVMODEL_IO_ASSERT_GPR_EQ +// _SP = (volatile register) +// _R = GPR +// _I = Immediate +// This code will check a test to see if the results +// match the expected value. +// It can also be used to tell if a set of tests is still running or has crashed +#if 0 +// Spinning | = "I am alive" +#define RVMODEL_IO_ASSERT_GPR_EQ(_SP, _R, _I) \ + LOCAL_IO_PUSH(_SP) \ + RVMODEL_IO_WRITE_STR2("|"); \ + RVMODEL_IO_WRITE_STR2("\b=\b"); \ + LOCAL_IO_POP(_SP) + +#else + +// Test to see if a specific test has passed or not. Can assert or not. +#define RVMODEL_IO_ASSERT_GPR_EQ(_SP, _R, _I) \ + LOCAL_IO_PUSH(_SP) \ + mv s0, _R; \ + li t5, _I; \ + beq s0, t5, 20002f; \ + RVMODEL_IO_WRITE_STR("Test Failed "); \ + RVMODEL_IO_WRITE_STR(": "); \ + RVMODEL_IO_WRITE_STR(# _R); \ + RVMODEL_IO_WRITE_STR("( "); \ + mv a0, s0; \ + jal FN_WriteNmbr; \ + RVMODEL_IO_WRITE_STR(" ) != "); \ + mv a0, t5; \ + jal FN_WriteNmbr; \ + j 20003f; \ +20002: \ + RVMODEL_IO_WRITE_STR("Test Passed "); \ +20003: \ + RVMODEL_IO_WRITE_STR("\n"); \ + LOCAL_IO_POP(_SP) + +#endif + +/*.section .text\ +// FN_WriteStr: Add code here to write a string to IO +// FN_WriteNmbr: Add code here to write a number (32/64bits) to IO +FN_WriteStr: \ + ret; \ +FN_WriteNmbr: \ + ret; +*/ +//RVTEST_IO_ASSERT_SFPR_EQ +#define RVMODEL_IO_ASSERT_SFPR_EQ(_F, _R, _I) +//RVTEST_IO_ASSERT_DFPR_EQ +#define RVMODEL_IO_ASSERT_DFPR_EQ(_D, _R, _I) + +// TODO: specify the routine for setting machine software interrupt +#define RVMODEL_SET_MSW_INT + +// TODO: specify the routine for clearing machine software interrupt +#define RVMODEL_CLEAR_MSW_INT + +// TODO: specify the routine for clearing machine timer interrupt +#define RVMODEL_CLEAR_MTIMER_INT + +// TODO: specify the routine for clearing machine external interrupt +#define RVMODEL_CLEAR_MEXT_INT + +#endif // _COMPLIANCE_MODEL_H + diff --git a/test/riscv-target/atombones/model_test.h b/test/riscv-target/atombones/model_test.h new file mode 100644 index 00000000..6143ddcb --- /dev/null +++ b/test/riscv-target/atombones/model_test.h @@ -0,0 +1,263 @@ +#ifndef _COMPLIANCE_MODEL_H +#define _COMPLIANCE_MODEL_H + +#define RVMODEL_DATA_SECTION \ + .pushsection .tohost,"aw",@progbits; \ + .align 8; .global tohost; tohost: .dword 0; \ + .align 8; .global fromhost; fromhost: .dword 0; \ + .popsection; \ + .align 8; .global begin_regstate; begin_regstate: \ + .word 128; \ + .align 8; .global end_regstate; end_regstate: \ + .word 4; + +#include "../../../sw/lib/atombones.h" + +//TODO: Add code here to run after all tests have been run +// The .align 4 ensures that the signature begins at a 16-byte boundary +#define RVMODEL_HALT \ + ebreak; \ + +//////////////////////////////////////////////////////////////////////////// +// following code prints the mem signature to stdout, but this functionality +// is now handled by --signature arrgument in atomsim +/* \ +la s3, begin_signature; \ +la s4, end_signature; \ + \ +dump_loop: \ + lw a0, 0(s3); \ + jal print_hex; \ + \ + addi s3, s3, 4; \ + beq s3, s4, hault_me; \ + j dump_loop; \ + \ +hault_me: \ + ebreak; \ + \ + \ +print_hex: \ + mv s0, a0; \ + li s1, 0xf0000000; \ + mv s2, ra; \ + \ + print_hex_loop: \ + and a0, s0, s1; \ + srl a0, a0, 28; \ + srl s1, s1, 4; \ + jal print_hex_digit;\ + \ + and a0, s0, s1; \ + srl a0, a0, 24; \ + srl s1, s1, 4; \ + jal print_hex_digit;\ + \ + and a0, s0, s1; \ + srl a0, a0, 20; \ + srl s1, s1, 4; \ + jal print_hex_digit;\ + \ + and a0, s0, s1; \ + srl a0, a0, 16; \ + srl s1, s1, 4; \ + jal print_hex_digit;\ + \ + and a0, s0, s1; \ + srl a0, a0, 12; \ + srl s1, s1, 4; \ + jal print_hex_digit;\ + \ + and a0, s0, s1; \ + srl a0, a0, 8; \ + srl s1, s1, 4; \ + jal print_hex_digit;\ + \ + and a0, s0, s1; \ + srl a0, a0, 4; \ + srl s1, s1, 4; \ + jal print_hex_digit;\ + \ + and a0, s0, s1; \ + jal print_hex_digit;\ + \ + li a0, -38; \ + jal print_hex_digit;\ + mv ra, s2; \ + ret; \ + \ +print_hex_digit: \ + li t0, IO_UART_TX_ADDRESS; \ + li t1, IO_UART_SREG_ADDRESS; \ + li t2, 1; \ + \ + li t3, 10; \ + bge a0, t3, print_hex_digit_A2F;\ + \ + addi a0, a0, 48; \ + j print_hex_digit_PRINT; \ + print_hex_digit_A2F: \ + addi a0, a0, 87; \ + \ + print_hex_digit_PRINT: \ + sb a0, 0(t0); \ + sb t2, 0(t1); \ + sb x0, 0(t1); \ + \ + ret; \ +*/ + +//TODO: declare the start of your signature region here. Nothing else to be used here. +// The .align 4 ensures that the signature ends at a 16-byte boundary +#define RVMODEL_DATA_BEGIN \ + .align 4; .global begin_signature; begin_signature: + +//TODO: declare the end of the signature region here. Add other target specific contents here. +#define RVMODEL_DATA_END \ + .align 4; .global end_signature; end_signature: \ + RVMODEL_DATA_SECTION + + +//RVMODEL_BOOT +//TODO:Any specific target init code should be put here or the macro can be left empty + +// For code that has a split rom/ram area +// Code below will copy from the rom area to ram the +// data.strings and .data sections to ram. +// Use linksplit.ld +#define RVMODEL_BOOT \ + .section .text.init; \ + .globl _start; \ + _start: \ + li sp, 0x00014000;\ + //RVTEST_IO_INIT + +//RVTEST_IO_INIT +#define RVMODEL_IO_INIT +//RVTEST_IO_WRITE_STR +#define RVMODEL_IO_WRITE_STR(_R, _STR) +//RVTEST_IO_CHECK +#define RVMODEL_IO_CHECK() +//RVTEST_IO_ASSERT_GPR_EQ +#define RVMODEL_IO_ASSERT_GPR_EQ(_S, _R, _I) +//RVTEST_IO_ASSERT_SFPR_EQ +#define RVMODEL_IO_ASSERT_SFPR_EQ(_F, _R, _I) +//RVTEST_IO_ASSERT_DFPR_EQ +#define RVMODEL_IO_ASSERT_DFPR_EQ(_D, _R, _I) + +#define RVMODEL_SET_MSW_INT + +#define RVMODEL_CLEAR_MSW_INT + +#define RVMODEL_CLEAR_MTIMER_INT + +#define RVMODEL_CLEAR_MEXT_INT + +//#endif // _COMPLIANCE_MODEL_H +// +// _SP = (volatile register) +//TODO: Macro to output a string to IO +/*#define LOCAL_IO_WRITE_STR(_STR) RVMODEL_IO_WRITE_STR(x31, _STR) +#define RVMODEL_IO_WRITE_STR(_SP, _STR) \ + .section .data.string; \ +20001: \ + .string _STR; \ + .section .text.init; \ + la a0, 20001b; \ + jal FN_WriteStr; + +#define RSIZE 4 +// _SP = (volatile register) +#define LOCAL_IO_PUSH(_SP) \ + la _SP, begin_regstate; \ + sw ra, (1*RSIZE)(_SP); \ + sw t0, (2*RSIZE)(_SP); \ + sw t1, (3*RSIZE)(_SP); \ + sw t2, (4*RSIZE)(_SP); \ + sw t3, (5*RSIZE)(_SP); \ + sw t4, (6*RSIZE)(_SP); \ + sw s0, (7*RSIZE)(_SP); \ + sw a0, (8*RSIZE)(_SP); + +// _SP = (volatile register) +#define LOCAL_IO_POP(_SP) \ + la _SP, begin_regstate; \ + lw ra, (1*RSIZE)(_SP); \ + lw t0, (2*RSIZE)(_SP); \ + lw t1, (3*RSIZE)(_SP); \ + lw t2, (4*RSIZE)(_SP); \ + lw t3, (5*RSIZE)(_SP); \ + lw t4, (6*RSIZE)(_SP); \ + lw s0, (7*RSIZE)(_SP); \ + lw a0, (8*RSIZE)(_SP); + +//RVMODEL_IO_ASSERT_GPR_EQ +// _SP = (volatile register) +// _R = GPR +// _I = Immediate +// This code will check a test to see if the results +// match the expected value. +// It can also be used to tell if a set of tests is still running or has crashed +#if 0 +// Spinning | = "I am alive" +#define RVMODEL_IO_ASSERT_GPR_EQ(_SP, _R, _I) \ + LOCAL_IO_PUSH(_SP) \ + RVMODEL_IO_WRITE_STR2("|"); \ + RVMODEL_IO_WRITE_STR2("\b=\b"); \ + LOCAL_IO_POP(_SP) + +#else + +// Test to see if a specific test has passed or not. Can assert or not. +#define RVMODEL_IO_ASSERT_GPR_EQ(_SP, _R, _I) \ + LOCAL_IO_PUSH(_SP) \ + mv s0, _R; \ + li t5, _I; \ + beq s0, t5, 20002f; \ + RVMODEL_IO_WRITE_STR("Test Failed "); \ + RVMODEL_IO_WRITE_STR(": "); \ + RVMODEL_IO_WRITE_STR(# _R); \ + RVMODEL_IO_WRITE_STR("( "); \ + mv a0, s0; \ + jal FN_WriteNmbr; \ + RVMODEL_IO_WRITE_STR(" ) != "); \ + mv a0, t5; \ + jal FN_WriteNmbr; \ + j 20003f; \ +20002: \ + RVMODEL_IO_WRITE_STR("Test Passed "); \ +20003: \ + RVMODEL_IO_WRITE_STR("\n"); \ + LOCAL_IO_POP(_SP) + +#endif + +.section .text +// FN_WriteStr: Add code here to write a string to IO +// FN_WriteNmbr: Add code here to write a number (32/64bits) to IO +FN_WriteStr: \ + mv x0, x0; + ret; \ +FN_WriteNmbr: \ + mv x0, x0; + ret; + +//RVTEST_IO_ASSERT_SFPR_EQ +#define RVMODEL_IO_ASSERT_SFPR_EQ(_F, _R, _I) +//RVTEST_IO_ASSERT_DFPR_EQ +#define RVMODEL_IO_ASSERT_DFPR_EQ(_D, _R, _I) + +// TODO: specify the routine for setting machine software interrupt +#define RVMODEL_SET_MSW_INT + +// TODO: specify the routine for clearing machine software interrupt +#define RVMODEL_CLEAR_MSW_INT + +// TODO: specify the routine for clearing machine timer interrupt +#define RVMODEL_CLEAR_MTIMER_INT + +// TODO: specify the routine for clearing machine external interrupt +#define RVMODEL_CLEAR_MEXT_INT*/ + +#endif // _COMPLIANCE_MODEL_H +