├── LICENSE ├── Makefile ├── README.md ├── bin └── Makefile ├── simulator ├── Makefile ├── addressSpaceInterface.h ├── binary.hex ├── bus.cpp ├── bus.h ├── cpu.cpp ├── cpu.h ├── cpuInterface.h ├── executor.cpp ├── executor.h ├── executorInterface.h ├── instructionDecoder.cpp ├── instructionDecoder.h ├── instructionDecoderInterface.h ├── main.cpp ├── memory.cpp ├── memory.h ├── register.cpp ├── register.h └── registerInterface.h └── test ├── Makefile └── hello.c /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, hsufit 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | run: test/binary.hex simulator/simulator 2 | cp test/binary.hex ./bin 3 | cp simulator/simulator ./bin 4 | make -C bin/ 5 | 6 | test/binary.hex: 7 | make -C test/ 8 | 9 | simulator/simulator: 10 | make -C simulator/ 11 | 12 | clean: 13 | make -C test/ -f Makefile clean 14 | make -C bin/ -f Makefile clean 15 | make -C simulator/ -f Makefile clean 16 | 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RISCV-SIM 2 | A risc-v simulator based on SystrmC. 3 | Support RV32I instruction set, and will add more extension in future. 4 | 5 | ## Prerequisites 6 | SystemC Library, C++ Compiler, RISC-V Cross Compiler 7 | 8 | ## How to Use 9 | To Run the simple hello world. 10 | ``` 11 | //cpu.cpp 12 | void CPU::cpu_thread(void) 13 | { 14 | register_file->set_pc(0x10b8); <---add this line to set program counter 15 | register_file->set_value_integer(REGISTER_INTERFACE::x2, 0x40000); <---add this line to set stack pointer 16 | while(true) { 17 | step(); 18 | wait(delay); 19 | } 20 | } 21 | ``` 22 | ``` 23 | $ make run 24 | //compile 25 | ... 26 | 00 address: 0x10f7 value: 0x21 27 | 00 address: 0x10f8 value: 0x0 28 | 03 program counter should be: 0x10b8 29 | current_pc: 0x10b8 target_pc: 0x10bc ADDI 2 16 2 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x3fff0 immValue: 0xfffffff0 30 | current_pc: 0x10bc target_pc: 0x10c0 SW 2 1 12 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x0 immValue: 0xc 31 | ... 32 | console: h 33 | ... 34 | console: e 35 | ... 36 | console: l 37 | ... 38 | console: l 39 | ... 40 | console: o 41 | ... 42 | console: 43 | ... 44 | console: w 45 | ... 46 | console: o 47 | ... 48 | console: r 49 | ... 50 | console: l 51 | ... 52 | console: d 53 | ... 54 | console: ! 55 | ... 56 | current_pc: 0x10dc target_pc: 0x10e0 LW 2 12 1 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x0 immValue: 0xc 57 | current_pc: 0x10e0 target_pc: 0x10e4 LW 2 8 8 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x0 immValue: 0x8 58 | current_pc: 0x10e4 target_pc: 0x10e8 ADDI 2 16 2 rs1Value: 0x40000 rs2Value: 0x0 rdValue: 0x40000 immValue: 0x10 59 | current_pc: 0x10e8 target_pc: 0x0 JALR 1 0 0 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x0 immValue: 0x0 60 | INVALID: Opcode :0 61 | Illegal Instruction, end simulation! 62 | exception! 63 | 64 | Info: /OSCI/SystemC: Simulation stopped by user. 65 | ``` 66 | 67 | or run your hex file by replace `binary.hex` in RISCV-SIM folder. 68 | 69 | ## Set Up Cross Compiler 70 | Read the README in https://github.com/riscv/riscv-gnu-toolchain 71 | User can decide where to install, use /home/user/Desktop/code/rv32i-ilp32-gnu-toolchain in thins example. 72 | This project support RV32i instrucetion set only, so sonfigure with --with-arch=rv32i (I instruction set) and 73 | --with-abi=ilp32 (soft floating point) options 74 | ``` 75 | $sudo apt-get install autoconf automake autotools-dev curl python3 libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev 76 | $git clone https://github.com/riscv/riscv-gnu-toolchain 77 | $cd riscv-gnu-toolchain && git submodule update -i -r 78 | $./configure --prefix=/home/user/Desktop/code/rv32i-ilp32-gnu-toolchain --with-arch=rv32i --with-abi=ilp32 79 | $make 80 | ``` 81 | 82 | ## How to Generate binary.hex and Run Simulation With It 83 | If you change the install path, please remember to modify the Makefile. 84 | ``` 85 | $ cd test 86 | //modify hello.c 87 | $ make 88 | $ cd .. 89 | $ make run 90 | ... 91 | 03 program counter should be: 0x10b8 92 | ... 93 | //modify program counter to 0x10b8 94 | $ make run 95 | ``` 96 | ## TODO 97 | - Simplify simulation run step 98 | - Build and simulate specified binary file from source file automatically 99 | - Get program counter autometically from program loader 100 | - Add more example 101 | - Fix Logger message bug cause by same source and target register 102 | - Refine Logger by replace unused rs1, rs2, rd with x0 103 | - Add unittest 104 | - Add branch prediction analyzer 105 | - Add memory access analyzer 106 | - Extend external device 107 | - More generalized console 108 | - External timer 109 | - Deep learning acclerator 110 | - support more standard instruction set extension 111 | - M, A, F, D Extensions 112 | - Compress Extension 113 | - Vector Extension 114 | 115 | ### Advanced Topics 116 | - Extend Logger to support Out Of Order Execution analysis. 117 | -------------------------------------------------------------------------------- /bin/Makefile: -------------------------------------------------------------------------------- 1 | export SYSTEMC_HOME=/usr/local/systemc-2.3.3 2 | export LD_LIBRARY_PATH=$(SYSTEMC_HOME)/lib-linux64 3 | 4 | run: simulator binary.hex 5 | ./simulator 6 | 7 | clean: 8 | rm -rf ./simulator ./binary.hex 9 | -------------------------------------------------------------------------------- /simulator/Makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | CXXFLAGS = -std=c++14 3 | 4 | LIB_DIR=-L/usr/local/systemc-2.3.3/lib-linux64 5 | INC_DIR=-I/usr/local/systemc-2.3.3/include 6 | LIB=-lsystemc 7 | 8 | export SYSTEMC_HOME=/usr/local/systemc-2.3.3 9 | export LD_LIBRARY_PATH=$(SYSTEMC_HOME)/lib-linux64 10 | 11 | INC_INTERFACE=addressSpaceInterface registerInterface instructionDecoderInterface executorInterface cpuInterface 12 | SRC=main cpu memory register bus instructionDecoder executor 13 | APP=simulator 14 | 15 | $(APP): $(addsuffix .o, $(SRC)) 16 | $(CXX) -o $(APP) $(^) $(LIB_DIR) $(INC_DIR) $(LIB) $(CXXFLAGS) 17 | 18 | clean: 19 | rm -rf ./*.o 20 | rm -rf $(APP) 21 | 22 | main.o: main.cpp 23 | $(CXX) -c $(CXXFLAGS) $(<) $(INC_DIR) -o $@ 24 | 25 | %.o: %.cpp %.h $(addsuffix .h,$(INC_INTERFACE)) 26 | $(CXX) -c $(CXXFLAGS) $(<) $(INC_DIR) -o $@ 27 | 28 | format: 29 | astyle --style=linux --indent=tab --indent-switches --suffix=none *.cpp *.h 30 | 31 | run: $(APP) 32 | ./$(APP) 33 | -------------------------------------------------------------------------------- /simulator/addressSpaceInterface.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef INC_ADDRESS_SPACE_INTERFACE_H_ 4 | #define INC_ADDRESS_SPACE_INTERFACE_H_ 5 | class ADDRESS_SPACE_INTERFACE 6 | { 7 | public: 8 | virtual int32_t read(uint32_t addr, uint32_t size) =0; 9 | virtual void write(uint32_t addr, uint32_t data, uint32_t size)=0; 10 | }; 11 | #endif //INC_ADDRESS_SPACE_INTERFACE_H_ 12 | -------------------------------------------------------------------------------- /simulator/binary.hex: -------------------------------------------------------------------------------- 1 | :020000021000EC 2 | :10005400130101FD2326810213040103232EA4FCB2 3 | :10006400232604FE6F0080028327C4FE0327C4FDF9 4 | :100074003307F700B7074000034707002380E70072 5 | :100084008327C4FE938717002326F4FE8327C4FE28 6 | :100094000327C4FDB307F70083C70700E39607FCF3 7 | :1000A40013000000138507000324C1021301010398 8 | :1000B40067800000130101FF23261100232481001F 9 | :1000C40013040101B70701001385C70EEFF05FF8B1 10 | :1000D40093070000138507008320C10003248100D7 11 | :0800E400130101016780000017 12 | :0D00EC0068656C6C6F20776F726C6421008A 13 | :04000003100000B831 14 | :00000001FF 15 | -------------------------------------------------------------------------------- /simulator/bus.cpp: -------------------------------------------------------------------------------- 1 | #include "bus.h" 2 | 3 | BUS::BUS(sc_module_name name): sc_module(name), memory("memory") 4 | { 5 | this->memory_socket.bind(memory.memory_socket); 6 | } 7 | 8 | int32_t BUS::read(uint32_t addr, uint32_t size) 9 | { 10 | uint32_t data = 0; 11 | tlm::tlm_generic_payload trans; 12 | trans.set_command(tlm::TLM_READ_COMMAND); 13 | trans.set_data_ptr(reinterpret_cast(&data)); 14 | trans.set_data_length(size); 15 | trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); 16 | trans.set_address(addr); 17 | sc_core::sc_time delay = sc_core::SC_ZERO_TIME; 18 | 19 | memory_socket->b_transport(trans, delay); 20 | return data; 21 | } 22 | 23 | void BUS::write(uint32_t addr, uint32_t data, uint32_t size) 24 | 25 | { 26 | tlm::tlm_generic_payload trans; 27 | trans.set_command(tlm::TLM_WRITE_COMMAND); 28 | trans.set_data_ptr(reinterpret_cast(&data)); 29 | trans.set_data_length(size); 30 | trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); 31 | trans.set_address(addr); 32 | sc_core::sc_time delay = sc_core::SC_ZERO_TIME; 33 | switch (addr) { 34 | case CONSOLE_BASE: 35 | std::cout << "console: \'" << *reinterpret_cast(&data) << "\'" << std::endl; 36 | break; 37 | default: 38 | memory_socket->b_transport(trans, delay); 39 | break; 40 | } 41 | } 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /simulator/bus.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "tlm_utils/simple_initiator_socket.h" 4 | #include "tlm_utils/simple_target_socket.h" 5 | 6 | #include "addressSpaceInterface.h" 7 | #include "memory.h" 8 | 9 | #ifndef INC_BUS_H_ 10 | #define INC_BUS_H_ 11 | class BUS: public ADDRESS_SPACE_INTERFACE, public sc_module 12 | { 13 | enum memoryMapp { 14 | MEMORY_BASE = 0x000000, 15 | CONSOLE_BASE = 0x400000, 16 | }; 17 | public: 18 | BUS(sc_module_name name); 19 | 20 | virtual int32_t read(uint32_t addr, uint32_t size) override; 21 | virtual void write(uint32_t addr, uint32_t data, uint32_t size) override; 22 | private: 23 | MEMORY memory; 24 | tlm_utils::simple_initiator_socket memory_socket; 25 | }; 26 | 27 | #endif //INC_BUS_H_ 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /simulator/cpu.cpp: -------------------------------------------------------------------------------- 1 | #include "cpu.h" 2 | 3 | CPU::CPU(sc_module_name name) : sc_module(name) 4 | { 5 | SC_HAS_PROCESS(CPU); 6 | SC_THREAD(cpu_thread); 7 | } 8 | 9 | void CPU::cpu_thread(void) 10 | { 11 | while(true) { 12 | step(); 13 | wait(delay); 14 | } 15 | } 16 | 17 | void CPU::step() 18 | { 19 | uint32_t instruction = address_space->read(register_file->get_pc(), 4); 20 | 21 | instruction_decoder->set_instruction(instruction); 22 | executor->execute(); 23 | } 24 | 25 | void CPU::set_register_file(const std::shared_ptr &instance) 26 | { 27 | register_file = instance; 28 | if(executor != nullptr) { 29 | executor->set_register_file(register_file); 30 | } 31 | } 32 | 33 | void CPU::set_address_space(const std::shared_ptr &instance) 34 | { 35 | address_space = instance; 36 | if(executor != nullptr) { 37 | executor->set_address_space(address_space); 38 | } 39 | } 40 | 41 | void CPU::set_instruction_decoder(const std::shared_ptr &instance) 42 | { 43 | instruction_decoder = instance; 44 | if(executor != nullptr) { 45 | executor->set_instruction_decoder(instruction_decoder); 46 | } 47 | } 48 | 49 | void CPU::set_executor(const std::shared_ptr &instance) 50 | { 51 | executor = instance; 52 | 53 | executor->set_cpu(std::shared_ptr(this, [](CPU *p) {})); 54 | 55 | if(instruction_decoder != nullptr) { 56 | executor->set_instruction_decoder(instruction_decoder); 57 | } 58 | 59 | if(register_file != nullptr) { 60 | executor->set_register_file(register_file); 61 | } 62 | 63 | if(address_space != nullptr) { 64 | executor->set_address_space(address_space); 65 | } 66 | 67 | } 68 | 69 | void CPU::raise_exception(uint32_t cause) 70 | { 71 | switch(cause) { 72 | case CPU_INTERFACE::INSTRUCTION_ADDRESS_MISALIGNED_EXCEPTION_CAUSE: 73 | std::cout << "Address Misalignment, end simulation!" << std::endl; 74 | break; 75 | case CPU_INTERFACE::INSTRUCTION_ACCESS_FAULT_EXCEPTION_CAUSE: 76 | break; 77 | case CPU_INTERFACE::ILLEGAL_INSTRUCTION_EXCEPTION_CAUSE: 78 | std::cout << "Illegal Instruction, end simulation!" << std::endl; 79 | break; 80 | case CPU_INTERFACE::BREAKPOINT_EXCEPTION_CAUSE: 81 | std::cout << "EBREAK, end simulation!" << std::endl; 82 | break; 83 | case CPU_INTERFACE::LOAD_ADDRESS_MISALIGNED_EXCEPTION_CAUSE: 84 | std::cout << "Load Address Misalignment, end simulation!" << std::endl; 85 | break; 86 | case CPU_INTERFACE::LOAD_ACCESS_FAULT_EXCEPTION_CAUSE: 87 | std::cout << "Access Fault, end simulation!" << std::endl; 88 | break; 89 | case CPU_INTERFACE::STORE_AMO_ADDRESS_MISALIGNED_EXCEPTION_CAUSE: 90 | std::cout << "Store and AMO Address Misalignment, end simulation!" << std::endl; 91 | break; 92 | case CPU_INTERFACE::STORE_AMO_ACCESS_FAULT_EXCEPTION_CAUSE: 93 | std::cout << "Store and AMO Access Fault, end simulation!" << std::endl; 94 | break; 95 | case CPU_INTERFACE::ENVIRONMENT_CALL_FROM_U_MODE_EXCEPTION_CAUSE: 96 | break; 97 | case CPU_INTERFACE::ENVIRONMENT_CALL_FROM_S_MODE_EXCEPTION_CAUSE: 98 | break; 99 | case CPU_INTERFACE::RESERVED_EXCEPTION_CAUSE: 100 | break; 101 | case CPU_INTERFACE::ENVIRONMENT_CALL_FROM_M_MODE_EXCEPTION_CAUSE: 102 | std::cout << "ECALL, end simulation!" << std::endl; 103 | break; 104 | case CPU_INTERFACE::INSTRUCTION_PAGE_FAULT_EXCEPTION_CAUSE: 105 | break; 106 | case CPU_INTERFACE::LOAD_PAGE_FAULT_EXCEPTION_CAUSE: 107 | break; 108 | case CPU_INTERFACE::RESERVED_FOR_FUTURE_STANDARD_USE_EXCEPTION_CAUSE: 109 | break; 110 | case CPU_INTERFACE::STORE_AMO_PAGE_FAULT_EXCEPTION_CAUSE: 111 | break; 112 | default: 113 | std::cout << "unsupported exception cause: " << cause << std::endl; 114 | break; 115 | } 116 | 117 | std::cout << "exception!" << std::endl; 118 | sc_core::sc_stop(); 119 | } 120 | 121 | void CPU::raise_interrupt(uint32_t cause) 122 | { 123 | switch (cause) { 124 | case CPU_INTERFACE::USER_SOFTWARE_INTERRUPT_INTERRUPT_CAUSE: 125 | break; 126 | case CPU_INTERFACE::SUPERVISOR_SOFTWARE_INTERRUPT_INTERRUPT_CAUSE: 127 | break; 128 | //case CPU_INTERFACE::RESERVED_FOR_FUTURE_STANDARD_USE_INTERRUPT_CAUSE: 129 | // break; 130 | case CPU_INTERFACE::MACHINE_SOFTWARE_INTERRUPT_INTERRUPT_CAUSE: 131 | break; 132 | case CPU_INTERFACE::USER_TIMER_INTERRUPT_INTERRUPT_CAUSE: 133 | break; 134 | case CPU_INTERFACE::SUPERVISOR_TIMER_INTERRUPT_INTERRUPT_CAUSE: 135 | break; 136 | //case CPU_INTERFACE::RESERVED_FOR_FUTURE_STANDARD_USE_INTERRUPT_CAUSE: 137 | // break; 138 | case CPU_INTERFACE::MACHINE_TIMER_INTERRUPT_INTERRUPT_CAUSE: 139 | break; 140 | case CPU_INTERFACE::USER_EXTERNAL_INTERRUPT_INTERRUPT_CAUSE: 141 | break; 142 | case CPU_INTERFACE::SUPERVISOR_EXTERNAL_INTERRUPT_INTERRUPT_CAUSE: 143 | break; 144 | //case CPU_INTERFACE::RESERVED_FOR_FUTURE_STANDARD_USE_INTERRUPT_CAUSE: 145 | // break; 146 | case CPU_INTERFACE::MACHINE_EXTERNAL_INTERRUPT_INTERRUPT_CAUSE: 147 | break; 148 | default: 149 | std::cout << "unsupported interrupt cause: " << cause << std::endl; 150 | break; 151 | } 152 | std::cout << "interrupt!" << std::endl; 153 | sc_core::sc_stop(); 154 | } 155 | 156 | -------------------------------------------------------------------------------- /simulator/cpu.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "systemc.h" 4 | 5 | #include "tlm_utils/simple_initiator_socket.h" 6 | #include "tlm_utils/simple_target_socket.h" 7 | 8 | #include "cpuInterface.h" 9 | #include "registerInterface.h" 10 | #include "addressSpaceInterface.h" 11 | #include "instructionDecoderInterface.h" 12 | #include "executorInterface.h" 13 | 14 | #ifndef INC_CPU_H_ 15 | #define INC_CPU_H_ 16 | class CPU :public CPU_INTERFACE, public sc_module 17 | { 18 | public: 19 | CPU(sc_module_name name); 20 | void set_register_file(const std::shared_ptr &instance); 21 | void set_address_space(const std::shared_ptr &instance); 22 | void set_instruction_decoder(const std::shared_ptr &instance); 23 | void set_executor(const std::shared_ptr &instance); 24 | 25 | virtual void raise_exception(uint32_t cause) override; 26 | virtual void raise_interrupt(uint32_t cause) override; 27 | private: 28 | void cpu_thread(void); 29 | void step(); 30 | 31 | sc_core::sc_time delay = sc_core::sc_time(1, sc_core::SC_NS); 32 | uint32_t pc = 0; 33 | 34 | std::shared_ptr register_file; 35 | std::shared_ptr address_space; 36 | std::shared_ptr instruction_decoder; 37 | std::shared_ptr executor; 38 | }; 39 | #endif //INC_CPU_H_ 40 | -------------------------------------------------------------------------------- /simulator/cpuInterface.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef INC_CPU_INTERFACE_H_ 4 | #define INC_CPU_INTERFACE_H_ 5 | class CPU_INTERFACE 6 | { 7 | public: 8 | enum Interrupt { 9 | USER_SOFTWARE_INTERRUPT_INTERRUPT_CAUSE, 10 | SUPERVISOR_SOFTWARE_INTERRUPT_INTERRUPT_CAUSE, 11 | //RESERVED_FOR_FUTURE_STANDARD_USE_INTERRUPT_CAUSE, 12 | MACHINE_SOFTWARE_INTERRUPT_INTERRUPT_CAUSE = 3, 13 | USER_TIMER_INTERRUPT_INTERRUPT_CAUSE, 14 | SUPERVISOR_TIMER_INTERRUPT_INTERRUPT_CAUSE, 15 | //RESERVED_FOR_FUTURE_STANDARD_USE_INTERRUPT_CAUSE, 16 | MACHINE_TIMER_INTERRUPT_INTERRUPT_CAUSE = 7, 17 | USER_EXTERNAL_INTERRUPT_INTERRUPT_CAUSE, 18 | SUPERVISOR_EXTERNAL_INTERRUPT_INTERRUPT_CAUSE, 19 | //RESERVED_FOR_FUTURE_STANDARD_USE_INTERRUPT_CAUSE, 20 | MACHINE_EXTERNAL_INTERRUPT_INTERRUPT_CAUSE = 11, 21 | //RESERVED_FOR_FUTURE_STANDARD_USE_INTERRUPT_CAUSE, 22 | //RESERVED_FOR_PLATFORM_USE_INTERRUPT_CAUSE, 23 | }; 24 | 25 | enum Exception { 26 | INSTRUCTION_ADDRESS_MISALIGNED_EXCEPTION_CAUSE, 27 | INSTRUCTION_ACCESS_FAULT_EXCEPTION_CAUSE, 28 | ILLEGAL_INSTRUCTION_EXCEPTION_CAUSE, 29 | BREAKPOINT_EXCEPTION_CAUSE, 30 | LOAD_ADDRESS_MISALIGNED_EXCEPTION_CAUSE, 31 | LOAD_ACCESS_FAULT_EXCEPTION_CAUSE, 32 | STORE_AMO_ADDRESS_MISALIGNED_EXCEPTION_CAUSE, 33 | STORE_AMO_ACCESS_FAULT_EXCEPTION_CAUSE, 34 | ENVIRONMENT_CALL_FROM_U_MODE_EXCEPTION_CAUSE, 35 | ENVIRONMENT_CALL_FROM_S_MODE_EXCEPTION_CAUSE, 36 | RESERVED_EXCEPTION_CAUSE = 10, 37 | ENVIRONMENT_CALL_FROM_M_MODE_EXCEPTION_CAUSE, 38 | INSTRUCTION_PAGE_FAULT_EXCEPTION_CAUSE, 39 | LOAD_PAGE_FAULT_EXCEPTION_CAUSE, 40 | RESERVED_FOR_FUTURE_STANDARD_USE_EXCEPTION_CAUSE = 14, 41 | STORE_AMO_PAGE_FAULT_EXCEPTION_CAUSE, 42 | //RESERVED_FOR_FUTURE_STANDARD_USE_EXCEPTION_CAUSE_BASE = 16, 43 | //RESERVED_FOR_CUSTOM_USE_EXCEPTION_CAUSE_BASE = 24, 44 | //RESERVED_FOR_FUTURE_STANDARD_USE_EXCEPTION_CAUSE_BASE = 32, 45 | //RESERVED_FOR_CUSTOM_USE_EXCEPTION_CAUSE_BASE = 48, 46 | //RESERVED_FOR_FUTURE_STANDARD_USE_EXCEPTION_CAUSE_BASE = 64, 47 | }; 48 | 49 | virtual void raise_exception(uint32_t cause) = 0; 50 | virtual void raise_interrupt(uint32_t cause) = 0; 51 | }; 52 | #endif //INC_CPU_INTERFACE_H_ 53 | -------------------------------------------------------------------------------- /simulator/executor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "executor.h" 4 | 5 | #define INSTRUCTION_ALIGNMENT 4 6 | #define LOAD_STORE_ALIGNMENT_W 4 7 | #define LOAD_STORE_ALIGNMENT_HW 4 8 | 9 | bool isAlignment(uint32_t address, unsigned int baseNumber) 10 | { 11 | if(0 == address % baseNumber) { 12 | return true; 13 | } else { 14 | return false; 15 | } 16 | } 17 | 18 | 19 | void EXECUTOR::execute() 20 | { 21 | new_pc = register_file->get_pc() + 4; 22 | command_dispatch(); 23 | register_file->set_pc(new_pc); 24 | } 25 | 26 | void EXECUTOR::command_dispatch() 27 | { 28 | switch (instruction_decoder->get_instruction()) { 29 | case INSTRUCTION_DECODER_INTERFACE::ADDI_INSTRUCTION_ENUM: 30 | ADDI_E(); 31 | break; 32 | case INSTRUCTION_DECODER_INTERFACE::ANDI_INSTRUCTION_ENUM: 33 | ANDI_E(); 34 | break; 35 | case INSTRUCTION_DECODER_INTERFACE::ORI_INSTRUCTION_ENUM: 36 | ORI_E(); 37 | break; 38 | case INSTRUCTION_DECODER_INTERFACE::XORI_INSTRUCTION_ENUM: 39 | XORI_E(); 40 | break; 41 | case INSTRUCTION_DECODER_INTERFACE::SLTI_INSTRUCTION_ENUM: 42 | SLTI_E(); 43 | break; 44 | case INSTRUCTION_DECODER_INTERFACE::SLTIU_INSTRUCTION_ENUM: 45 | SLTIU_E(); 46 | break; 47 | case INSTRUCTION_DECODER_INTERFACE::SLLI_INSTRUCTION_ENUM: 48 | SLLI_E(); 49 | break; 50 | case INSTRUCTION_DECODER_INTERFACE::SRLI_INSTRUCTION_ENUM: 51 | SRLI_E(); 52 | break; 53 | case INSTRUCTION_DECODER_INTERFACE::SRAI_INSTRUCTION_ENUM: 54 | SRAI_E(); 55 | break; 56 | case INSTRUCTION_DECODER_INTERFACE::LUI_INSTRUCTION_ENUM: 57 | LUI_E(); 58 | break; 59 | case INSTRUCTION_DECODER_INTERFACE::AUIPC_INSTRUCTION_ENUM: 60 | AUIPC_E(); 61 | break; 62 | case INSTRUCTION_DECODER_INTERFACE::LB_INSTRUCTION_ENUM: 63 | LB_E(); 64 | break; 65 | case INSTRUCTION_DECODER_INTERFACE::LH_INSTRUCTION_ENUM: 66 | LH_E(); 67 | break; 68 | case INSTRUCTION_DECODER_INTERFACE::LW_INSTRUCTION_ENUM: 69 | LW_E(); 70 | break; 71 | case INSTRUCTION_DECODER_INTERFACE::LBU_INSTRUCTION_ENUM: 72 | LBU_E(); 73 | break; 74 | case INSTRUCTION_DECODER_INTERFACE::LHU_INSTRUCTION_ENUM: 75 | LHU_E(); 76 | break; 77 | case INSTRUCTION_DECODER_INTERFACE::SB_INSTRUCTION_ENUM: 78 | SB_E(); 79 | break; 80 | case INSTRUCTION_DECODER_INTERFACE::SH_INSTRUCTION_ENUM: 81 | SH_E(); 82 | break; 83 | case INSTRUCTION_DECODER_INTERFACE::SW_INSTRUCTION_ENUM: 84 | SW_E(); 85 | break; 86 | case INSTRUCTION_DECODER_INTERFACE::JAL_INSTRUCTION_ENUM: 87 | JAL_E(); 88 | break; 89 | case INSTRUCTION_DECODER_INTERFACE::JALR_INSTRUCTION_ENUM: 90 | JALR_E(); 91 | break; 92 | case INSTRUCTION_DECODER_INTERFACE::BEQ_INSTRUCTION_ENUM: 93 | BEQ_E(); 94 | break; 95 | case INSTRUCTION_DECODER_INTERFACE::BNE_INSTRUCTION_ENUM: 96 | BNE_E(); 97 | break; 98 | case INSTRUCTION_DECODER_INTERFACE::BLT_INSTRUCTION_ENUM: 99 | BLT_E(); 100 | break; 101 | case INSTRUCTION_DECODER_INTERFACE::BGE_INSTRUCTION_ENUM: 102 | BGE_E(); 103 | break; 104 | case INSTRUCTION_DECODER_INTERFACE::BLTU_INSTRUCTION_ENUM: 105 | BLTU_E(); 106 | break; 107 | case INSTRUCTION_DECODER_INTERFACE::BGEU_INSTRUCTION_ENUM: 108 | BGEU_E(); 109 | break; 110 | case INSTRUCTION_DECODER_INTERFACE::FENCE_INSTRUCTION_ENUM: 111 | FENCE_E(); 112 | break; 113 | case INSTRUCTION_DECODER_INTERFACE::FENCE_TSO_INSTRUCTION_ENUM: 114 | FENCE_TSO_E(); 115 | break; 116 | case INSTRUCTION_DECODER_INTERFACE::ECALL_INSTRUCTION_ENUM: 117 | ECALL_E(); 118 | break; 119 | case INSTRUCTION_DECODER_INTERFACE::EBREAK_INSTRUCTION_ENUM: 120 | EBREAK_E(); 121 | break; 122 | case INSTRUCTION_DECODER_INTERFACE::ADD_INSTRUCTION_ENUM: 123 | ADD_E(); 124 | break; 125 | case INSTRUCTION_DECODER_INTERFACE::SUB_INSTRUCTION_ENUM: 126 | SUB_E(); 127 | break; 128 | case INSTRUCTION_DECODER_INTERFACE::AND_INSTRUCTION_ENUM: 129 | AND_E(); 130 | break; 131 | case INSTRUCTION_DECODER_INTERFACE::OR_INSTRUCTION_ENUM: 132 | OR_E(); 133 | break; 134 | case INSTRUCTION_DECODER_INTERFACE::XOR_INSTRUCTION_ENUM: 135 | XOR_E(); 136 | break; 137 | case INSTRUCTION_DECODER_INTERFACE::SLT_INSTRUCTION_ENUM: 138 | SLT_E(); 139 | break; 140 | case INSTRUCTION_DECODER_INTERFACE::SLTU_INSTRUCTION_ENUM: 141 | SLTU_E(); 142 | break; 143 | case INSTRUCTION_DECODER_INTERFACE::SLL_INSTRUCTION_ENUM: 144 | SLL_E(); 145 | break; 146 | case INSTRUCTION_DECODER_INTERFACE::SRL_INSTRUCTION_ENUM: 147 | SRL_E(); 148 | break; 149 | case INSTRUCTION_DECODER_INTERFACE::SRA_INSTRUCTION_ENUM: 150 | SRA_E(); 151 | break; 152 | default: 153 | cpu->raise_exception(CPU_INTERFACE::ILLEGAL_INSTRUCTION_EXCEPTION_CAUSE); 154 | break; 155 | } 156 | } 157 | 158 | void EXECUTOR::ADDI_E() 159 | { 160 | auto rs1 = instruction_decoder->get_rs1(); 161 | auto rd = instruction_decoder->get_rd(); 162 | auto imm = instruction_decoder->get_imm(31, 20); 163 | 164 | auto value = register_file->get_value_integer(rs1) + imm; 165 | register_file->set_value_integer(rd, value); 166 | 167 | instruction_decoder->log_instruction( 168 | register_file->get_pc(), 169 | new_pc, 170 | register_file->get_value_integer(rs1), 171 | 0, 172 | register_file->get_value_integer(rd), 173 | imm); 174 | } 175 | 176 | void EXECUTOR::ANDI_E() 177 | { 178 | auto rs1 = instruction_decoder->get_rs1(); 179 | auto rd = instruction_decoder->get_rd(); 180 | auto imm = instruction_decoder->get_imm(31, 20); 181 | 182 | auto value = register_file->get_value_integer(rs1) & imm; 183 | register_file->set_value_integer(rd, value); 184 | 185 | instruction_decoder->log_instruction( 186 | register_file->get_pc(), 187 | new_pc, 188 | register_file->get_value_integer(rs1), 189 | 0, 190 | register_file->get_value_integer(rd), 191 | imm); 192 | } 193 | 194 | void EXECUTOR::ORI_E() 195 | { 196 | auto rs1 = instruction_decoder->get_rs1(); 197 | auto rd = instruction_decoder->get_rd(); 198 | auto imm = instruction_decoder->get_imm(31, 20); 199 | 200 | auto value = register_file->get_value_integer(rs1) | imm; 201 | register_file->set_value_integer(rd, value); 202 | 203 | instruction_decoder->log_instruction( 204 | register_file->get_pc(), 205 | new_pc, 206 | register_file->get_value_integer(rs1), 207 | 0, 208 | register_file->get_value_integer(rd), 209 | imm); 210 | } 211 | 212 | void EXECUTOR::XORI_E() 213 | { 214 | auto rs1 = instruction_decoder->get_rs1(); 215 | auto rd = instruction_decoder->get_rd(); 216 | auto imm = instruction_decoder->get_imm(31, 20); 217 | 218 | auto value = register_file->get_value_integer(rs1) ^ imm; 219 | register_file->set_value_integer(rd, value); 220 | 221 | instruction_decoder->log_instruction( 222 | register_file->get_pc(), 223 | new_pc, 224 | register_file->get_value_integer(rs1), 225 | 0, 226 | register_file->get_value_integer(rd), 227 | imm); 228 | } 229 | 230 | void EXECUTOR::SLTI_E() 231 | { 232 | auto rs1 = instruction_decoder->get_rs1(); 233 | auto rd = instruction_decoder->get_rd(); 234 | auto imm = instruction_decoder->get_imm(31, 20); 235 | 236 | auto value = register_file->get_value_integer(rs1) < imm; 237 | register_file->set_value_integer(rd, value); 238 | 239 | instruction_decoder->log_instruction( 240 | register_file->get_pc(), 241 | new_pc, 242 | register_file->get_value_integer(rs1), 243 | 0, 244 | register_file->get_value_integer(rd), 245 | imm); 246 | } 247 | 248 | void EXECUTOR::SLTIU_E() 249 | { 250 | auto rs1 = instruction_decoder->get_rs1(); 251 | auto rd = instruction_decoder->get_rd(); 252 | auto imm = (uint32_t) instruction_decoder->get_imm(31, 20); 253 | 254 | auto value = register_file->get_value_integer(rs1) < imm; 255 | register_file->set_value_integer(rd, value); 256 | 257 | instruction_decoder->log_instruction( 258 | register_file->get_pc(), 259 | new_pc, 260 | register_file->get_value_integer(rs1), 261 | 0, 262 | register_file->get_value_integer(rd), 263 | imm); 264 | } 265 | 266 | void EXECUTOR::SLLI_E() 267 | { 268 | auto rs1 = instruction_decoder->get_rs1(); 269 | auto rd = instruction_decoder->get_rd(); 270 | auto imm = (uint32_t) instruction_decoder->get_imm(24, 20); 271 | 272 | auto value = register_file->get_value_integer(rs1) << imm; 273 | register_file->set_value_integer(rd, value); 274 | 275 | instruction_decoder->log_instruction( 276 | register_file->get_pc(), 277 | new_pc, 278 | register_file->get_value_integer(rs1), 279 | 0, 280 | register_file->get_value_integer(rd), 281 | imm); 282 | } 283 | 284 | void EXECUTOR::SRLI_E() 285 | { 286 | auto rs1 = instruction_decoder->get_rs1(); 287 | auto rd = instruction_decoder->get_rd(); 288 | auto imm = (uint32_t) instruction_decoder->get_imm(24, 20); 289 | 290 | auto value = (uint32_t) register_file->get_value_integer(rs1) >> imm; 291 | register_file->set_value_integer(rd, value); 292 | 293 | instruction_decoder->log_instruction( 294 | register_file->get_pc(), 295 | new_pc, 296 | register_file->get_value_integer(rs1), 297 | 0, 298 | register_file->get_value_integer(rd), 299 | imm); 300 | } 301 | 302 | void EXECUTOR::SRAI_E() 303 | { 304 | auto rs1 = instruction_decoder->get_rs1(); 305 | auto rd = instruction_decoder->get_rd(); 306 | auto imm = (uint32_t) instruction_decoder->get_imm(24, 20); 307 | 308 | auto value = register_file->get_value_integer(rs1) >> imm; 309 | register_file->set_value_integer(rd, value); 310 | 311 | instruction_decoder->log_instruction( 312 | register_file->get_pc(), 313 | new_pc, 314 | register_file->get_value_integer(rs1), 315 | 0, 316 | register_file->get_value_integer(rd), 317 | imm); 318 | } 319 | 320 | void EXECUTOR::LUI_E() 321 | { 322 | auto rd = instruction_decoder->get_rd(); 323 | auto imm = instruction_decoder->get_imm(31, 12); 324 | 325 | auto value = (imm << 12); 326 | register_file->set_value_integer(rd, value); 327 | 328 | instruction_decoder->log_instruction( 329 | register_file->get_pc(), 330 | new_pc, 331 | 0, 332 | 0, 333 | register_file->get_value_integer(rd), 334 | imm); 335 | } 336 | 337 | void EXECUTOR::AUIPC_E() 338 | { 339 | auto rd = instruction_decoder->get_rd(); 340 | auto imm = instruction_decoder->get_imm(31, 12); 341 | 342 | auto value = register_file->get_pc() + (imm << 12); 343 | register_file->set_value_integer(rd, value); 344 | 345 | instruction_decoder->log_instruction( 346 | register_file->get_pc(), 347 | new_pc, 348 | 0, 349 | 0, 350 | register_file->get_value_integer(rd), 351 | imm); 352 | } 353 | 354 | 355 | void EXECUTOR::LB_E() 356 | { 357 | auto rs1 = instruction_decoder->get_rs1(); 358 | auto rd = instruction_decoder->get_rd(); 359 | auto imm = (uint32_t) instruction_decoder->get_imm(31, 20); 360 | 361 | auto addr = register_file->get_value_integer(rs1) + imm; 362 | auto value = address_space->read(addr, 1) << 24 >> 24; 363 | register_file->set_value_integer(rd, value); 364 | 365 | instruction_decoder->log_instruction( 366 | register_file->get_pc(), 367 | new_pc, 368 | register_file->get_value_integer(rs1), 369 | 0, 370 | register_file->get_value_integer(rd), 371 | imm); 372 | } 373 | 374 | void EXECUTOR::LH_E() 375 | { 376 | auto rs1 = instruction_decoder->get_rs1(); 377 | auto rd = instruction_decoder->get_rd(); 378 | auto imm = (uint32_t) instruction_decoder->get_imm(31, 20); 379 | 380 | auto addr = register_file->get_value_integer(rs1) + imm; 381 | if(!isAlignment(addr, LOAD_STORE_ALIGNMENT_HW)) { 382 | cpu->raise_exception(CPU_INTERFACE::LOAD_ADDRESS_MISALIGNED_EXCEPTION_CAUSE); 383 | } 384 | auto value = address_space->read(addr, 2) << 16 >> 16; 385 | register_file->set_value_integer(rd, value); 386 | 387 | instruction_decoder->log_instruction( 388 | register_file->get_pc(), 389 | new_pc, 390 | register_file->get_value_integer(rs1), 391 | 0, 392 | register_file->get_value_integer(rd), 393 | imm); 394 | } 395 | 396 | void EXECUTOR::LW_E() 397 | { 398 | auto rs1 = instruction_decoder->get_rs1(); 399 | auto rd = instruction_decoder->get_rd(); 400 | auto imm = (uint32_t) instruction_decoder->get_imm(31, 20); 401 | 402 | auto addr = register_file->get_value_integer(rs1) + imm; 403 | if(!isAlignment(addr, LOAD_STORE_ALIGNMENT_W)) { 404 | cpu->raise_exception(CPU_INTERFACE::LOAD_ADDRESS_MISALIGNED_EXCEPTION_CAUSE); 405 | } 406 | auto value = address_space->read(addr, 4); 407 | register_file->set_value_integer(rd, value); 408 | 409 | instruction_decoder->log_instruction( 410 | register_file->get_pc(), 411 | new_pc, 412 | register_file->get_value_integer(rs1), 413 | 0, 414 | register_file->get_value_integer(rd), 415 | imm); 416 | } 417 | 418 | void EXECUTOR::LBU_E() 419 | { 420 | auto rs1 = instruction_decoder->get_rs1(); 421 | auto rd = instruction_decoder->get_rd(); 422 | auto imm = (uint32_t) instruction_decoder->get_imm(31, 20); 423 | 424 | auto addr = register_file->get_value_integer(rs1) + imm; 425 | auto value = address_space->read(addr, 1); 426 | register_file->set_value_integer(rd, value); 427 | 428 | instruction_decoder->log_instruction( 429 | register_file->get_pc(), 430 | new_pc, 431 | register_file->get_value_integer(rs1), 432 | 0, 433 | register_file->get_value_integer(rd), 434 | imm); 435 | } 436 | 437 | void EXECUTOR::LHU_E() 438 | { 439 | auto rs1 = instruction_decoder->get_rs1(); 440 | auto rd = instruction_decoder->get_rd(); 441 | auto imm = (uint32_t) instruction_decoder->get_imm(31, 20); 442 | 443 | auto addr = register_file->get_value_integer(rs1) + imm; 444 | if(!isAlignment(addr, LOAD_STORE_ALIGNMENT_HW)) { 445 | cpu->raise_exception(CPU_INTERFACE::LOAD_ADDRESS_MISALIGNED_EXCEPTION_CAUSE); 446 | } 447 | auto value = address_space->read(addr, 2); 448 | register_file->set_value_integer(rd, value); 449 | 450 | instruction_decoder->log_instruction( 451 | register_file->get_pc(), 452 | new_pc, 453 | register_file->get_value_integer(rs1), 454 | 0, 455 | register_file->get_value_integer(rd), 456 | imm); 457 | } 458 | 459 | void EXECUTOR::SB_E() 460 | { 461 | auto rs1 = instruction_decoder->get_rs1(); 462 | auto rs2 = instruction_decoder->get_rs2(); 463 | auto offset = (instruction_decoder->get_imm(31, 25) << 5) | 464 | (instruction_decoder->get_imm(11, 7) & 0x1F); 465 | 466 | auto addr = register_file->get_value_integer(rs1) + offset; 467 | address_space->write(addr, register_file->get_value_integer(rs2), 1); 468 | 469 | instruction_decoder->log_instruction( 470 | register_file->get_pc(), 471 | new_pc, 472 | register_file->get_value_integer(rs1), 473 | register_file->get_value_integer(rs2), 474 | 0, 475 | offset); 476 | } 477 | 478 | void EXECUTOR::SH_E() 479 | { 480 | auto rs1 = instruction_decoder->get_rs1(); 481 | auto rs2 = instruction_decoder->get_rs2(); 482 | auto offset = (instruction_decoder->get_imm(31, 25) << 5) | 483 | (instruction_decoder->get_imm(11, 7) & 0x1F); 484 | 485 | auto addr = register_file->get_value_integer(rs1) + offset; 486 | if(!isAlignment(addr, LOAD_STORE_ALIGNMENT_HW)) { 487 | cpu->raise_exception(CPU_INTERFACE::STORE_AMO_ADDRESS_MISALIGNED_EXCEPTION_CAUSE); 488 | } 489 | address_space->write(addr, register_file->get_value_integer(rs2), 2); 490 | 491 | instruction_decoder->log_instruction( 492 | register_file->get_pc(), 493 | new_pc, 494 | register_file->get_value_integer(rs1), 495 | register_file->get_value_integer(rs2), 496 | 0, 497 | offset); 498 | } 499 | 500 | void EXECUTOR::SW_E() 501 | { 502 | auto rs1 = instruction_decoder->get_rs1(); 503 | auto rs2 = instruction_decoder->get_rs2(); 504 | auto offset = (instruction_decoder->get_imm(31, 25) << 5) | 505 | (instruction_decoder->get_imm(11, 7) & 0x1F); 506 | 507 | auto addr = register_file->get_value_integer(rs1) + offset; 508 | if(!isAlignment(addr, LOAD_STORE_ALIGNMENT_W)) { 509 | cpu->raise_exception(CPU_INTERFACE::STORE_AMO_ADDRESS_MISALIGNED_EXCEPTION_CAUSE); 510 | } 511 | address_space->write(addr, register_file->get_value_integer(rs2), 4); 512 | 513 | instruction_decoder->log_instruction( 514 | register_file->get_pc(), 515 | new_pc, 516 | register_file->get_value_integer(rs1), 517 | register_file->get_value_integer(rs2), 518 | 0, 519 | offset); 520 | } 521 | 522 | void EXECUTOR::JAL_E() 523 | { 524 | auto rd = instruction_decoder->get_rd(); 525 | auto offset = instruction_decoder->get_imm_j(); 526 | 527 | auto addr = register_file->get_pc() + offset; 528 | if(!isAlignment(addr, INSTRUCTION_ALIGNMENT)) { 529 | cpu->raise_exception(CPU_INTERFACE::INSTRUCTION_ADDRESS_MISALIGNED_EXCEPTION_CAUSE); 530 | } 531 | register_file->set_value_integer(rd, new_pc); 532 | new_pc = addr; 533 | 534 | instruction_decoder->log_instruction( 535 | register_file->get_pc(), 536 | new_pc, 537 | 0, 538 | 0, 539 | register_file->get_value_integer(rd), 540 | offset); 541 | } 542 | 543 | void EXECUTOR::JALR_E() 544 | { 545 | auto rs1 = instruction_decoder->get_rs1(); 546 | auto rd = instruction_decoder->get_rd(); 547 | auto offset = instruction_decoder->get_imm(31, 20); 548 | 549 | auto addr = (register_file->get_value_integer(rs1) + offset) & ~0x1; 550 | if(!isAlignment(addr, INSTRUCTION_ALIGNMENT)) { 551 | cpu->raise_exception(CPU_INTERFACE::INSTRUCTION_ADDRESS_MISALIGNED_EXCEPTION_CAUSE); 552 | } 553 | register_file->set_value_integer(rd, new_pc); 554 | new_pc = addr; 555 | 556 | instruction_decoder->log_instruction( 557 | register_file->get_pc(), 558 | new_pc, 559 | register_file->get_value_integer(rs1), 560 | 0, 561 | register_file->get_value_integer(rd), 562 | offset); 563 | } 564 | 565 | void EXECUTOR::BEQ_E() 566 | { 567 | auto rs1 = instruction_decoder->get_rs1(); 568 | auto rs2 = instruction_decoder->get_rs2(); 569 | auto offset = instruction_decoder->get_imm_b(); 570 | 571 | auto addr = register_file->get_pc() + 572 | (register_file->get_value_integer(rs1) == register_file->get_value_integer(rs2) ? 573 | offset : 4); 574 | if(!isAlignment(addr, INSTRUCTION_ALIGNMENT)) { 575 | cpu->raise_exception(CPU_INTERFACE::INSTRUCTION_ADDRESS_MISALIGNED_EXCEPTION_CAUSE); 576 | } 577 | new_pc = addr; 578 | 579 | instruction_decoder->log_instruction( 580 | register_file->get_pc(), 581 | new_pc, 582 | register_file->get_value_integer(rs1), 583 | register_file->get_value_integer(rs2), 584 | 0, 585 | offset); 586 | } 587 | 588 | void EXECUTOR::BNE_E() 589 | { 590 | auto rs1 = instruction_decoder->get_rs1(); 591 | auto rs2 = instruction_decoder->get_rs2(); 592 | auto offset = instruction_decoder->get_imm_b(); 593 | 594 | auto addr = register_file->get_pc() + 595 | (register_file->get_value_integer(rs1) != register_file->get_value_integer(rs2) ? 596 | offset : 4); 597 | if(!isAlignment(addr, INSTRUCTION_ALIGNMENT)) { 598 | cpu->raise_exception(CPU_INTERFACE::INSTRUCTION_ADDRESS_MISALIGNED_EXCEPTION_CAUSE); 599 | } 600 | new_pc = addr; 601 | 602 | instruction_decoder->log_instruction( 603 | register_file->get_pc(), 604 | new_pc, 605 | register_file->get_value_integer(rs1), 606 | register_file->get_value_integer(rs2), 607 | 0, 608 | offset); 609 | } 610 | 611 | void EXECUTOR::BLT_E() 612 | { 613 | auto rs1 = instruction_decoder->get_rs1(); 614 | auto rs2 = instruction_decoder->get_rs2(); 615 | auto offset = instruction_decoder->get_imm_b(); 616 | 617 | auto addr = register_file->get_pc() + 618 | (register_file->get_value_integer(rs1) < register_file->get_value_integer(rs2) ? 619 | offset : 4); 620 | if(!isAlignment(addr, INSTRUCTION_ALIGNMENT)) { 621 | cpu->raise_exception(CPU_INTERFACE::INSTRUCTION_ADDRESS_MISALIGNED_EXCEPTION_CAUSE); 622 | } 623 | new_pc = addr; 624 | 625 | instruction_decoder->log_instruction( 626 | register_file->get_pc(), 627 | new_pc, 628 | register_file->get_value_integer(rs1), 629 | register_file->get_value_integer(rs2), 630 | 0, 631 | offset); 632 | } 633 | 634 | void EXECUTOR::BGE_E() 635 | { 636 | auto rs1 = instruction_decoder->get_rs1(); 637 | auto rs2 = instruction_decoder->get_rs2(); 638 | auto offset = instruction_decoder->get_imm_b(); 639 | 640 | auto addr = register_file->get_pc() + 641 | (register_file->get_value_integer(rs1) >= register_file->get_value_integer(rs2) ? 642 | offset : 4); 643 | if(!isAlignment(addr, INSTRUCTION_ALIGNMENT)) { 644 | cpu->raise_exception(CPU_INTERFACE::INSTRUCTION_ADDRESS_MISALIGNED_EXCEPTION_CAUSE); 645 | } 646 | new_pc = addr; 647 | 648 | instruction_decoder->log_instruction( 649 | register_file->get_pc(), 650 | new_pc, 651 | register_file->get_value_integer(rs1), 652 | register_file->get_value_integer(rs2), 653 | 0, 654 | offset); 655 | } 656 | 657 | void EXECUTOR::BLTU_E() 658 | { 659 | auto rs1 = instruction_decoder->get_rs1(); 660 | auto rs2 = instruction_decoder->get_rs2(); 661 | auto offset = instruction_decoder->get_imm_b(); 662 | 663 | auto addr = register_file->get_pc() + 664 | ((uint32_t) register_file->get_value_integer(rs1) < (uint32_t) register_file->get_value_integer(rs2) ? 665 | offset : 4); 666 | if(!isAlignment(addr, INSTRUCTION_ALIGNMENT)) { 667 | cpu->raise_exception(CPU_INTERFACE::INSTRUCTION_ADDRESS_MISALIGNED_EXCEPTION_CAUSE); 668 | } 669 | new_pc = addr; 670 | 671 | instruction_decoder->log_instruction( 672 | register_file->get_pc(), 673 | new_pc, 674 | register_file->get_value_integer(rs1), 675 | register_file->get_value_integer(rs2), 676 | 0, 677 | offset); 678 | } 679 | 680 | void EXECUTOR::BGEU_E() 681 | { 682 | auto rs1 = instruction_decoder->get_rs1(); 683 | auto rs2 = instruction_decoder->get_rs2(); 684 | auto offset = instruction_decoder->get_imm_b(); 685 | 686 | auto addr = register_file->get_pc() + 687 | ((uint32_t) register_file->get_value_integer(rs1) >= (uint32_t) register_file->get_value_integer(rs2) ? 688 | offset : 4); 689 | if(!isAlignment(addr, INSTRUCTION_ALIGNMENT)) { 690 | cpu->raise_exception(CPU_INTERFACE::INSTRUCTION_ADDRESS_MISALIGNED_EXCEPTION_CAUSE); 691 | } 692 | new_pc = addr; 693 | 694 | instruction_decoder->log_instruction( 695 | register_file->get_pc(), 696 | new_pc, 697 | register_file->get_value_integer(rs1), 698 | register_file->get_value_integer(rs2), 699 | 0, 700 | offset); 701 | } 702 | 703 | void EXECUTOR::FENCE_E() 704 | { 705 | instruction_decoder->log_instruction( 706 | register_file->get_pc(), 707 | new_pc, 708 | 0, 709 | 0, 710 | 0, 711 | 0); 712 | } 713 | 714 | void EXECUTOR::FENCE_TSO_E() 715 | { 716 | instruction_decoder->log_instruction( 717 | register_file->get_pc(), 718 | new_pc, 719 | 0, 720 | 0, 721 | 0, 722 | 0); 723 | } 724 | 725 | void EXECUTOR::ECALL_E() 726 | { 727 | cpu->raise_exception(CPU_INTERFACE::ENVIRONMENT_CALL_FROM_M_MODE_EXCEPTION_CAUSE); 728 | 729 | instruction_decoder->log_instruction( 730 | register_file->get_pc(), 731 | new_pc, 732 | 0, 733 | 0, 734 | 0, 735 | 0); 736 | } 737 | 738 | void EXECUTOR::EBREAK_E() 739 | { 740 | cpu->raise_exception(CPU_INTERFACE::BREAKPOINT_EXCEPTION_CAUSE); 741 | 742 | instruction_decoder->log_instruction( 743 | register_file->get_pc(), 744 | new_pc, 745 | 0, 746 | 0, 747 | 0, 748 | 0); 749 | } 750 | void EXECUTOR::ADD_E() 751 | { 752 | auto rs1 = instruction_decoder->get_rs1(); 753 | auto rs2 = instruction_decoder->get_rs2(); 754 | auto rd = instruction_decoder->get_rd(); 755 | 756 | auto value = register_file->get_value_integer(rs1) + register_file->get_value_integer(rs2); 757 | register_file->set_value_integer(rd, value); 758 | 759 | instruction_decoder->log_instruction( 760 | register_file->get_pc(), 761 | new_pc, 762 | register_file->get_value_integer(rs1), 763 | register_file->get_value_integer(rs2), 764 | register_file->get_value_integer(rd), 765 | 0); 766 | } 767 | 768 | void EXECUTOR::SUB_E() 769 | { 770 | auto rs1 = instruction_decoder->get_rs1(); 771 | auto rs2 = instruction_decoder->get_rs2(); 772 | auto rd = instruction_decoder->get_rd(); 773 | 774 | auto value = register_file->get_value_integer(rs1) - register_file->get_value_integer(rs2); 775 | register_file->set_value_integer(rd, value); 776 | 777 | instruction_decoder->log_instruction( 778 | register_file->get_pc(), 779 | new_pc, 780 | register_file->get_value_integer(rs1), 781 | register_file->get_value_integer(rs2), 782 | register_file->get_value_integer(rd), 783 | 0); 784 | } 785 | 786 | void EXECUTOR::AND_E() 787 | { 788 | auto rs1 = instruction_decoder->get_rs1(); 789 | auto rs2 = instruction_decoder->get_rs2(); 790 | auto rd = instruction_decoder->get_rd(); 791 | 792 | auto value = register_file->get_value_integer(rs1) & register_file->get_value_integer(rs2); 793 | register_file->set_value_integer(rd, value); 794 | 795 | instruction_decoder->log_instruction( 796 | register_file->get_pc(), 797 | new_pc, 798 | register_file->get_value_integer(rs1), 799 | register_file->get_value_integer(rs2), 800 | register_file->get_value_integer(rd), 801 | 0); 802 | } 803 | 804 | void EXECUTOR::OR_E() 805 | { 806 | auto rs1 = instruction_decoder->get_rs1(); 807 | auto rs2 = instruction_decoder->get_rs2(); 808 | auto rd = instruction_decoder->get_rd(); 809 | 810 | auto value = register_file->get_value_integer(rs1) | register_file->get_value_integer(rs2); 811 | register_file->set_value_integer(rd, value); 812 | 813 | instruction_decoder->log_instruction( 814 | register_file->get_pc(), 815 | new_pc, 816 | register_file->get_value_integer(rs1), 817 | register_file->get_value_integer(rs2), 818 | register_file->get_value_integer(rd), 819 | 0); 820 | } 821 | 822 | void EXECUTOR::XOR_E() 823 | { 824 | auto rs1 = instruction_decoder->get_rs1(); 825 | auto rs2 = instruction_decoder->get_rs2(); 826 | auto rd = instruction_decoder->get_rd(); 827 | 828 | auto value = register_file->get_value_integer(rs1) ^ register_file->get_value_integer(rs2); 829 | register_file->set_value_integer(rd, value); 830 | 831 | instruction_decoder->log_instruction( 832 | register_file->get_pc(), 833 | new_pc, 834 | register_file->get_value_integer(rs1), 835 | register_file->get_value_integer(rs2), 836 | register_file->get_value_integer(rd), 837 | 0); 838 | } 839 | 840 | void EXECUTOR::SLT_E() 841 | { 842 | auto rs1 = instruction_decoder->get_rs1(); 843 | auto rs2 = instruction_decoder->get_rs2(); 844 | auto rd = instruction_decoder->get_rd(); 845 | 846 | auto value = register_file->get_value_integer(rs1) < register_file->get_value_integer(rs2) ? 1 : 0; 847 | register_file->set_value_integer(rd, value); 848 | 849 | instruction_decoder->log_instruction( 850 | register_file->get_pc(), 851 | new_pc, 852 | register_file->get_value_integer(rs1), 853 | register_file->get_value_integer(rs2), 854 | register_file->get_value_integer(rd), 855 | 0); 856 | } 857 | 858 | void EXECUTOR::SLTU_E() 859 | { 860 | auto rs1 = instruction_decoder->get_rs1(); 861 | auto rs2 = instruction_decoder->get_rs2(); 862 | auto rd = instruction_decoder->get_rd(); 863 | 864 | auto value = (uint32_t)register_file->get_value_integer(rs1) < (uint32_t)register_file->get_value_integer(rs2) ? 1 : 0; 865 | register_file->set_value_integer(rd, value); 866 | 867 | instruction_decoder->log_instruction( 868 | register_file->get_pc(), 869 | new_pc, 870 | register_file->get_value_integer(rs1), 871 | register_file->get_value_integer(rs2), 872 | register_file->get_value_integer(rd), 873 | 0); 874 | } 875 | 876 | void EXECUTOR::SLL_E() 877 | { 878 | auto rs1 = instruction_decoder->get_rs1(); 879 | auto rs2 = instruction_decoder->get_rs2(); 880 | auto rd = instruction_decoder->get_rd(); 881 | 882 | auto value = register_file->get_value_integer(rs1) << register_file->get_value_integer(rs2); 883 | register_file->set_value_integer(rd, value); 884 | 885 | instruction_decoder->log_instruction( 886 | register_file->get_pc(), 887 | new_pc, 888 | register_file->get_value_integer(rs1), 889 | register_file->get_value_integer(rs2), 890 | register_file->get_value_integer(rd), 891 | 0); 892 | } 893 | 894 | void EXECUTOR::SRL_E() 895 | { 896 | auto rs1 = instruction_decoder->get_rs1(); 897 | auto rs2 = instruction_decoder->get_rs2(); 898 | auto rd = instruction_decoder->get_rd(); 899 | 900 | auto value = (uint32_t)register_file->get_value_integer(rs1) >> register_file->get_value_integer(rs2); 901 | register_file->set_value_integer(rd, value); 902 | 903 | instruction_decoder->log_instruction( 904 | register_file->get_pc(), 905 | new_pc, 906 | register_file->get_value_integer(rs1), 907 | register_file->get_value_integer(rs2), 908 | register_file->get_value_integer(rd), 909 | 0); 910 | } 911 | 912 | void EXECUTOR::SRA_E() 913 | { 914 | auto rs1 = instruction_decoder->get_rs1(); 915 | auto rs2 = instruction_decoder->get_rs2(); 916 | auto rd = instruction_decoder->get_rd(); 917 | 918 | auto value = register_file->get_value_integer(rs1) >> register_file->get_value_integer(rs2); 919 | register_file->set_value_integer(rd, value); 920 | 921 | instruction_decoder->log_instruction( 922 | register_file->get_pc(), 923 | new_pc, 924 | register_file->get_value_integer(rs1), 925 | register_file->get_value_integer(rs2), 926 | register_file->get_value_integer(rd), 927 | 0); 928 | } 929 | 930 | -------------------------------------------------------------------------------- /simulator/executor.h: -------------------------------------------------------------------------------- 1 | #include "executorInterface.h" 2 | 3 | #ifndef INC_EXECUTOR_H_ 4 | #define INC_EXECUTOR_H_ 5 | class EXECUTOR: public EXECUTOR_INTERFACE 6 | { 7 | public: 8 | virtual void execute() override; 9 | private: 10 | void command_dispatch(); 11 | 12 | void ADDI_E(); 13 | void ANDI_E(); 14 | void ORI_E(); 15 | void XORI_E(); 16 | void SLTI_E(); 17 | void SLTIU_E(); 18 | void SLLI_E(); 19 | void SRLI_E(); 20 | void SRAI_E(); 21 | void LUI_E(); 22 | void AUIPC_E(); 23 | void LB_E(); 24 | void LH_E(); 25 | void LW_E(); 26 | void LBU_E(); 27 | void LHU_E(); 28 | void SB_E(); 29 | void SH_E(); 30 | void SW_E(); 31 | void JAL_E(); 32 | void JALR_E(); 33 | void BEQ_E(); 34 | void BNE_E(); 35 | void BLT_E(); 36 | void BGE_E(); 37 | void BLTU_E(); 38 | void BGEU_E(); 39 | void FENCE_E(); 40 | void FENCE_TSO_E(); 41 | void ECALL_E(); 42 | void EBREAK_E(); 43 | void ADD_E(); 44 | void SUB_E(); 45 | void AND_E(); 46 | void OR_E(); 47 | void XOR_E(); 48 | void SLT_E(); 49 | void SLTU_E(); 50 | void SLL_E(); 51 | void SRL_E(); 52 | void SRA_E(); 53 | 54 | uint32_t new_pc; //write back to register when execute finished 55 | }; 56 | #endif //INC_EXECUTOR_H_ 57 | -------------------------------------------------------------------------------- /simulator/executorInterface.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "instructionDecoderInterface.h" 4 | #include "registerInterface.h" 5 | #include "addressSpaceInterface.h" 6 | #include "cpuInterface.h" 7 | 8 | #ifndef INC_EXECUTOR_INTERFACE_H_ 9 | #define INC_EXECUTOR_INTERFACE_H_ 10 | class EXECUTOR_INTERFACE 11 | { 12 | public: 13 | virtual void execute() = 0; 14 | void set_instruction_decoder(const std::shared_ptr &instance) 15 | { 16 | 17 | instruction_decoder = instance; 18 | } 19 | 20 | void set_register_file(const std::shared_ptr &instance) 21 | { 22 | register_file = instance; 23 | } 24 | 25 | void set_address_space(const std::shared_ptr &instance) 26 | { 27 | address_space = instance; 28 | } 29 | 30 | void set_cpu(const std::shared_ptr &instance) 31 | { 32 | cpu = instance; 33 | } 34 | 35 | protected: 36 | std::shared_ptr instruction_decoder; 37 | std::shared_ptr register_file; 38 | std::shared_ptr address_space; 39 | std::shared_ptr cpu; 40 | }; 41 | #endif //INC_EXECUTOR_INTERFACE_H_ 42 | -------------------------------------------------------------------------------- /simulator/instructionDecoder.cpp: -------------------------------------------------------------------------------- 1 | #include "instructionDecoder.h" 2 | 3 | INSTRUCTION_DECODER_INTERFACE::Instruction INSTRUCTION_DECODER::get_instruction() 4 | { 5 | return cmmand_dispatch(); 6 | } 7 | 8 | INSTRUCTION_DECODER_INTERFACE::Instruction INSTRUCTION_DECODER::cmmand_dispatch() 9 | { 10 | switch (get_opcode()) { 11 | case INSTRUCTION_DECODER_INTERFACE::IMM_OP: 12 | return imm_dispatch(); 13 | 14 | case INSTRUCTION_DECODER_INTERFACE::LUI_OP: 15 | return LUI_INSTRUCTION_ENUM; 16 | 17 | case INSTRUCTION_DECODER_INTERFACE::AUIPC_OP: 18 | return AUIPC_INSTRUCTION_ENUM; 19 | 20 | case INSTRUCTION_DECODER_INTERFACE::LOAD_OP: 21 | return load_dispatch(); 22 | 23 | case INSTRUCTION_DECODER_INTERFACE::STORE_OP: 24 | return store_dispatch(); 25 | 26 | case INSTRUCTION_DECODER_INTERFACE::JAL_OP: 27 | return JAL_INSTRUCTION_ENUM; 28 | 29 | case INSTRUCTION_DECODER_INTERFACE::JALR_OP: 30 | return jalr_dispatch(); 31 | 32 | case INSTRUCTION_DECODER_INTERFACE::BRANCH_OP: 33 | return branch_dispatch(); 34 | 35 | case INSTRUCTION_DECODER_INTERFACE::MISC_MEM_OP: 36 | return fence_dispatch(); 37 | 38 | case INSTRUCTION_DECODER_INTERFACE::SYSTEM_OP: 39 | return system_dispatch(); 40 | 41 | case INSTRUCTION_DECODER_INTERFACE::REG_OP: 42 | return reg_dispatch(); 43 | 44 | default: 45 | std::cout << "INVALID: Opcode :" << get_opcode() << std::endl; 46 | return INVALID_INSTRUCTION_ENUM; 47 | 48 | } 49 | } 50 | 51 | INSTRUCTION_DECODER_INTERFACE::Instruction INSTRUCTION_DECODER::imm_dispatch() 52 | { 53 | switch (get_func3()) { 54 | case INSTRUCTION_DECODER_INTERFACE::ADDI_FN3: 55 | return ADDI_INSTRUCTION_ENUM; 56 | 57 | case INSTRUCTION_DECODER_INTERFACE::ANDI_FN3: 58 | return ANDI_INSTRUCTION_ENUM; 59 | 60 | case INSTRUCTION_DECODER_INTERFACE::XORI_FN3: 61 | return ORI_INSTRUCTION_ENUM; 62 | 63 | case INSTRUCTION_DECODER_INTERFACE::ORI_FN3: 64 | return XORI_INSTRUCTION_ENUM; 65 | 66 | case INSTRUCTION_DECODER_INTERFACE::SLTI_FN3: 67 | return SLTI_INSTRUCTION_ENUM; 68 | 69 | case INSTRUCTION_DECODER_INTERFACE::SLTIU_FN3: 70 | return SLTIU_INSTRUCTION_ENUM; 71 | 72 | case INSTRUCTION_DECODER_INTERFACE::SLLI_FN3: 73 | return SLLI_INSTRUCTION_ENUM; 74 | 75 | case INSTRUCTION_DECODER_INTERFACE::SRLI_FN3://same as INSTRUCTION_DECODER_INTERFACE::SRAI_FN3 76 | if(get_imm(30, 30) == 0) { 77 | return SRLI_INSTRUCTION_ENUM; 78 | } else { 79 | return SRAI_INSTRUCTION_ENUM; 80 | } 81 | 82 | default: 83 | std::cout << "INVALID: Func3 in IMM_OP :" << get_func3() << std::endl; 84 | return INVALID_INSTRUCTION_ENUM; 85 | 86 | } 87 | } 88 | 89 | INSTRUCTION_DECODER_INTERFACE::Instruction INSTRUCTION_DECODER::load_dispatch() 90 | { 91 | switch (get_func3()) { 92 | case INSTRUCTION_DECODER_INTERFACE::LB_FN3: 93 | return LB_INSTRUCTION_ENUM; 94 | 95 | case INSTRUCTION_DECODER_INTERFACE::LH_FN3: 96 | return LH_INSTRUCTION_ENUM; 97 | 98 | case INSTRUCTION_DECODER_INTERFACE::LW_FN3: 99 | return LW_INSTRUCTION_ENUM; 100 | 101 | case INSTRUCTION_DECODER_INTERFACE::LBU_FN3: 102 | return LBU_INSTRUCTION_ENUM; 103 | 104 | case INSTRUCTION_DECODER_INTERFACE::LHU_FN3: 105 | return LHU_INSTRUCTION_ENUM; 106 | 107 | default: 108 | std::cout << "INVALID: Func3 in LOAD_OP :" << get_func3() << std::endl; 109 | return INVALID_INSTRUCTION_ENUM; 110 | 111 | } 112 | } 113 | 114 | INSTRUCTION_DECODER_INTERFACE::Instruction INSTRUCTION_DECODER::store_dispatch() 115 | { 116 | switch (get_func3()) { 117 | case INSTRUCTION_DECODER_INTERFACE::SB_FN3: 118 | return SB_INSTRUCTION_ENUM; 119 | 120 | case INSTRUCTION_DECODER_INTERFACE::SH_FN3: 121 | return SH_INSTRUCTION_ENUM; 122 | 123 | case INSTRUCTION_DECODER_INTERFACE::SW_FN3: 124 | return SW_INSTRUCTION_ENUM; 125 | 126 | default: 127 | std::cout << "INVALID: Func3 in STORE_OP :" << get_func3() << std::endl; 128 | return INVALID_INSTRUCTION_ENUM; 129 | 130 | } 131 | } 132 | 133 | INSTRUCTION_DECODER_INTERFACE::Instruction INSTRUCTION_DECODER::jalr_dispatch() 134 | { 135 | switch (get_func3()) { 136 | case INSTRUCTION_DECODER_INTERFACE::JALR_FN3: 137 | return JALR_INSTRUCTION_ENUM; 138 | 139 | default: 140 | std::cout << "INVALID: Func3 in JALR_OP :" << get_func3() << std::endl; 141 | return INVALID_INSTRUCTION_ENUM; 142 | 143 | } 144 | } 145 | 146 | INSTRUCTION_DECODER_INTERFACE::Instruction INSTRUCTION_DECODER::branch_dispatch() 147 | { 148 | switch (get_func3()) { 149 | case INSTRUCTION_DECODER_INTERFACE::BEQ_FN3: 150 | return BEQ_INSTRUCTION_ENUM; 151 | 152 | case INSTRUCTION_DECODER_INTERFACE::BNE_FN3: 153 | return BNE_INSTRUCTION_ENUM; 154 | 155 | case INSTRUCTION_DECODER_INTERFACE::BLT_FN3: 156 | return BLT_INSTRUCTION_ENUM; 157 | 158 | case INSTRUCTION_DECODER_INTERFACE::BGE_FN3: 159 | return BGE_INSTRUCTION_ENUM; 160 | 161 | case INSTRUCTION_DECODER_INTERFACE::BLTU_FN3: 162 | return BLTU_INSTRUCTION_ENUM; 163 | 164 | case INSTRUCTION_DECODER_INTERFACE::BGEU_FN3: 165 | return BGEU_INSTRUCTION_ENUM; 166 | 167 | default: 168 | std::cout << "INVALID: Func3 in BRANCH_OP :" << get_func3() << std::endl; 169 | return INVALID_INSTRUCTION_ENUM; 170 | 171 | } 172 | } 173 | 174 | INSTRUCTION_DECODER_INTERFACE::Instruction INSTRUCTION_DECODER::fence_dispatch() 175 | { 176 | switch (get_func3()) { 177 | case INSTRUCTION_DECODER_INTERFACE::FENCE_FN3: 178 | if(0b000 == get_imm_fence_fm()) { 179 | return FENCE_INSTRUCTION_ENUM; 180 | } else if(0b100 == get_imm_fence_fm()) { 181 | return FENCE_TSO_INSTRUCTION_ENUM; 182 | } else { 183 | std::cout << "INVALID: fm in MISC_MEM_OP :" << get_func3() << std::endl; 184 | return INVALID_INSTRUCTION_ENUM; 185 | } 186 | 187 | default: 188 | std::cout << "INVALID: Func3 in MISC_MEM_OP :" << get_func3() << std::endl; 189 | return INVALID_INSTRUCTION_ENUM; 190 | 191 | } 192 | } 193 | 194 | INSTRUCTION_DECODER_INTERFACE::Instruction INSTRUCTION_DECODER::system_dispatch() 195 | { 196 | switch (get_func12()) { 197 | case INSTRUCTION_DECODER_INTERFACE::ECALL_FN12: 198 | return ECALL_INSTRUCTION_ENUM; 199 | 200 | case INSTRUCTION_DECODER_INTERFACE::EBREAK_FN12: 201 | return EBREAK_INSTRUCTION_ENUM; 202 | 203 | default: 204 | std::cout << "INVALID: Func3 in MISC_MEM_OP :" << get_func3() << std::endl; 205 | return INVALID_INSTRUCTION_ENUM; 206 | 207 | } 208 | } 209 | 210 | INSTRUCTION_DECODER_INTERFACE::Instruction INSTRUCTION_DECODER::reg_dispatch() 211 | { 212 | switch (get_func3()) { 213 | case INSTRUCTION_DECODER_INTERFACE::ADDI_FN3: //SUB_FN3 is the same 214 | switch (get_func7()) { 215 | case INSTRUCTION_DECODER_INTERFACE::ADD_FN7: 216 | return ADD_INSTRUCTION_ENUM; 217 | 218 | case INSTRUCTION_DECODER_INTERFACE::SUB_FN7: 219 | return SUB_INSTRUCTION_ENUM; 220 | 221 | default: 222 | std::cout << "INVALID: Func7 in REG_OP :" << get_func3() << std::endl; 223 | return INVALID_INSTRUCTION_ENUM; 224 | 225 | } 226 | 227 | case INSTRUCTION_DECODER_INTERFACE::AND_FN3: 228 | return AND_INSTRUCTION_ENUM; 229 | //do not check FN7 for readibility, refactor in future 230 | 231 | case INSTRUCTION_DECODER_INTERFACE::OR_FN3: 232 | return OR_INSTRUCTION_ENUM; 233 | //do not check FN7 for readibility, refactor in future 234 | 235 | case INSTRUCTION_DECODER_INTERFACE::XOR_FN3: 236 | return XOR_INSTRUCTION_ENUM; 237 | //do not check FN7 for readibility, refactor in future 238 | 239 | case INSTRUCTION_DECODER_INTERFACE::SLT_FN3: 240 | return SLT_INSTRUCTION_ENUM; 241 | //do not check FN7 for readibility, refactor in future 242 | 243 | case INSTRUCTION_DECODER_INTERFACE::SLTU_FN3: 244 | return SLTU_INSTRUCTION_ENUM; 245 | //do not check FN7 for readibility, refactor in future 246 | 247 | case INSTRUCTION_DECODER_INTERFACE::SLL_FN3: 248 | return SLL_INSTRUCTION_ENUM; 249 | //do not check FN7 for readibility, refactor in future 250 | 251 | case INSTRUCTION_DECODER_INTERFACE::SRL_FN3: 252 | switch (get_func7()) { 253 | case INSTRUCTION_DECODER_INTERFACE::SRL_FN7: 254 | return SRL_INSTRUCTION_ENUM; 255 | 256 | case INSTRUCTION_DECODER_INTERFACE::SRA_FN7: 257 | return SRA_INSTRUCTION_ENUM; 258 | 259 | default: 260 | std::cout << "INVALID: Func7 in REG_OP :" << get_func3() << std::endl; 261 | return INVALID_INSTRUCTION_ENUM; 262 | 263 | } 264 | 265 | default: 266 | std::cout << "INVALID: Func3 in REG_OP :" << get_func3() << std::endl; 267 | return INVALID_INSTRUCTION_ENUM; 268 | 269 | } 270 | 271 | } 272 | 273 | void INSTRUCTION_DECODER::log_instruction(uint32_t current_pc, uint32_t target_pc, uint32_t rs1Value, uint32_t rs2Value, uint32_t rdValue,int32_t immValue) 274 | { 275 | 276 | auto instructionName = instruction_name_map[get_instruction()]; 277 | auto rd = get_rd(); 278 | auto rs1 = get_rs1(); 279 | auto rs2 = get_rs2(); 280 | 281 | std::cout << "current_pc: 0x" << std::hex << current_pc 282 | << " target_pc: 0x" << std::hex << target_pc 283 | << " " << instructionName 284 | << " " << std::dec << rs1 285 | << " " << std::dec << rs2 286 | << " " << std::dec << rd 287 | << " rs1Value: 0x" << std::hex << rs1Value 288 | << " rs2Value: 0x" << std::hex << rs2Value 289 | << " rdValue: 0x" << std::hex << rdValue 290 | << " immValue: 0x" << std::hex << immValue 291 | << std::endl; 292 | } 293 | 294 | uint32_t INSTRUCTION_DECODER::get_opcode() 295 | { 296 | return instruction_value.range(6, 0); 297 | } 298 | 299 | uint32_t INSTRUCTION_DECODER::get_func3() 300 | { 301 | return instruction_value.range(14, 12); 302 | } 303 | 304 | uint32_t INSTRUCTION_DECODER::get_func7() 305 | { 306 | return instruction_value.range(31,25); 307 | } 308 | uint32_t INSTRUCTION_DECODER::get_func12() 309 | { 310 | return instruction_value.range(31, 20); 311 | } 312 | 313 | uint32_t INSTRUCTION_DECODER::get_rs1() 314 | { 315 | return instruction_value.range(19,15); 316 | } 317 | 318 | uint32_t INSTRUCTION_DECODER::get_rs2() 319 | { 320 | return instruction_value.range(24, 20); 321 | } 322 | 323 | uint32_t INSTRUCTION_DECODER::get_rd() 324 | { 325 | return instruction_value.range(11, 7); 326 | } 327 | 328 | int32_t INSTRUCTION_DECODER::get_imm(uint32_t end, uint32_t start) 329 | { 330 | auto value = sc_dt::sc_int<32>(instruction_value); 331 | value <<= (31 - end); 332 | value >>= (31 - end + start); 333 | return value; 334 | } 335 | 336 | int32_t INSTRUCTION_DECODER::get_imm_j() 337 | { 338 | auto value = sc_dt::sc_int<32>(); 339 | value(20, 20) = instruction_value(31, 31); 340 | value(19, 12) = instruction_value(19, 12); 341 | value(11, 11) = instruction_value(20, 20); 342 | value(10, 1) = instruction_value(30, 21); 343 | value <<= 11; 344 | value >>= 11; 345 | return value; 346 | } 347 | 348 | int32_t INSTRUCTION_DECODER::get_imm_b() 349 | { 350 | auto value = sc_dt::sc_int<32>(); 351 | value(12, 12) = instruction_value(31, 31); 352 | value(11, 11) = instruction_value(7, 7); 353 | value(10, 5) = instruction_value(30, 25); 354 | value(4, 1) = instruction_value(11, 8); 355 | value <<= 19; 356 | value >>= 19; 357 | return value; 358 | } 359 | 360 | uint32_t INSTRUCTION_DECODER::get_imm_fence_fm() 361 | { 362 | return instruction_value.range(31, 28); 363 | } 364 | -------------------------------------------------------------------------------- /simulator/instructionDecoder.h: -------------------------------------------------------------------------------- 1 | #include "instructionDecoderInterface.h" 2 | 3 | #ifndef INC_INSTRUCTION_H_ 4 | #define INC_INSTRUCTION_H_ 5 | class INSTRUCTION_DECODER: public INSTRUCTION_DECODER_INTERFACE 6 | { 7 | public: 8 | virtual INSTRUCTION_DECODER_INTERFACE::Instruction get_instruction() override; 9 | INSTRUCTION_DECODER_INTERFACE::Instruction cmmand_dispatch(); 10 | INSTRUCTION_DECODER_INTERFACE::Instruction imm_dispatch(); 11 | INSTRUCTION_DECODER_INTERFACE::Instruction load_dispatch(); 12 | INSTRUCTION_DECODER_INTERFACE::Instruction store_dispatch(); 13 | INSTRUCTION_DECODER_INTERFACE::Instruction jalr_dispatch(); 14 | INSTRUCTION_DECODER_INTERFACE::Instruction branch_dispatch(); 15 | INSTRUCTION_DECODER_INTERFACE::Instruction fence_dispatch(); 16 | INSTRUCTION_DECODER_INTERFACE::Instruction system_dispatch(); 17 | INSTRUCTION_DECODER_INTERFACE::Instruction reg_dispatch(); 18 | virtual void log_instruction(uint32_t current_pc, uint32_t target_pc, uint32_t rs1Value, uint32_t rs2Value, uint32_t rdValue,int32_t immValue) override; 19 | virtual uint32_t get_opcode() override; 20 | virtual uint32_t get_func3() override; 21 | virtual uint32_t get_func7() override; 22 | virtual uint32_t get_func12() override; 23 | 24 | virtual uint32_t get_rs1() override; 25 | virtual uint32_t get_rs2() override; 26 | virtual uint32_t get_rd() override; 27 | 28 | virtual int32_t get_imm(uint32_t start, uint32_t end) override; 29 | virtual int32_t get_imm_j() override; 30 | virtual int32_t get_imm_b() override; 31 | virtual uint32_t get_imm_fence_fm() override; 32 | }; 33 | #endif //INSTRUCTION_INTERFAC 34 | -------------------------------------------------------------------------------- /simulator/instructionDecoderInterface.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "systemc.h" 5 | 6 | #ifndef INC_INSTRUCTION_DECODER_INTERFACE_H_ 7 | #define INC_INSTRUCTION_DECODER_INTERFACE_H_ 8 | class INSTRUCTION_DECODER_INTERFACE 9 | { 10 | public: 11 | enum ExtensionType { 12 | BASE_RV32I, 13 | UNSUPPORTED, 14 | }; 15 | 16 | enum Opcode { 17 | IMM_OP = 0b0010011, 18 | LUI_OP = 0b0110111, 19 | AUIPC_OP = 0b0010111, 20 | LOAD_OP = 0b0000011, 21 | STORE_OP = 0b0100011, 22 | JAL_OP = 0b1101111, 23 | JALR_OP = 0b1100111, 24 | BRANCH_OP = 0b1100011, 25 | MISC_MEM_OP = 0b0001111, 26 | SYSTEM_OP = 0b1110011, 27 | REG_OP = 0b0110011, 28 | }; 29 | 30 | enum Func3 { 31 | //IMM_OP 32 | ADDI_FN3 = 0b000, 33 | ANDI_FN3 = 0b111, 34 | ORI_FN3 = 0b110, 35 | XORI_FN3 = 0b100, 36 | SLTI_FN3 = 0b010, 37 | SLTIU_FN3 = 0b011, 38 | SLLI_FN3 = 0b001, 39 | SRLI_FN3 = 0b101, 40 | SRAI_FN3 = 0b101, 41 | LB_FN3 = 0b000, 42 | LH_FN3 = 0b001, 43 | LW_FN3 = 0b010, 44 | LBU_FN3 = 0b100, 45 | LHU_FN3 = 0b101, 46 | SB_FN3 = 0b000, 47 | SH_FN3 = 0b001, 48 | SW_FN3 = 0b010, 49 | JALR_FN3 = 0b000, 50 | BEQ_FN3 = 0b000, 51 | BNE_FN3 = 0b001, 52 | BLT_FN3 = 0b100, 53 | BGE_FN3 = 0b101, 54 | BLTU_FN3 = 0b110, 55 | BGEU_FN3 = 0b111, 56 | FENCE_FN3 = 0b000, 57 | ADD_FN3 = 0b000, 58 | SUB_FN3 = 0b000, 59 | AND_FN3 = 0b111, 60 | OR_FN3 = 0b110, 61 | XOR_FN3 = 0b100, 62 | SLT_FN3 = 0b010, 63 | SLTU_FN3 = 0b011, 64 | SLL_FN3 = 0b001, 65 | SRL_FN3 = 0b101, 66 | SRA_FN3 = 0b101, 67 | }; 68 | 69 | enum Func7 { 70 | ADD_FN7 = 0b0000000, 71 | SUB_FN7 = 0b0100000, 72 | AND_FN7 = 0b0000000, 73 | OR_FN7 = 0b0000000, 74 | XOR_FN7 = 0b0000000, 75 | SLT_FN7 = 0b0000000, 76 | SLTU_FN7 = 0b0000000, 77 | SLL_FN7 = 0b0000000, 78 | SRL_FN7 = 0b0000000, 79 | SRA_FN7 = 0b0100000, 80 | }; 81 | 82 | enum Func12 { 83 | ECALL_FN12 = 0b0, 84 | EBREAK_FN12 = 0b1, 85 | }; 86 | 87 | enum Instruction { 88 | ADDI_INSTRUCTION_ENUM, 89 | ANDI_INSTRUCTION_ENUM, 90 | ORI_INSTRUCTION_ENUM, 91 | XORI_INSTRUCTION_ENUM, 92 | SLTI_INSTRUCTION_ENUM, 93 | SLTIU_INSTRUCTION_ENUM, 94 | SLLI_INSTRUCTION_ENUM, 95 | SRLI_INSTRUCTION_ENUM, 96 | SRAI_INSTRUCTION_ENUM, 97 | LUI_INSTRUCTION_ENUM, 98 | AUIPC_INSTRUCTION_ENUM, 99 | LB_INSTRUCTION_ENUM, 100 | LH_INSTRUCTION_ENUM, 101 | LW_INSTRUCTION_ENUM, 102 | LBU_INSTRUCTION_ENUM, 103 | LHU_INSTRUCTION_ENUM, 104 | SB_INSTRUCTION_ENUM, 105 | SH_INSTRUCTION_ENUM, 106 | SW_INSTRUCTION_ENUM, 107 | JAL_INSTRUCTION_ENUM, 108 | JALR_INSTRUCTION_ENUM, 109 | BEQ_INSTRUCTION_ENUM, 110 | BNE_INSTRUCTION_ENUM, 111 | BLT_INSTRUCTION_ENUM, 112 | BGE_INSTRUCTION_ENUM, 113 | BLTU_INSTRUCTION_ENUM, 114 | BGEU_INSTRUCTION_ENUM, 115 | FENCE_INSTRUCTION_ENUM, 116 | FENCE_TSO_INSTRUCTION_ENUM, 117 | ECALL_INSTRUCTION_ENUM, 118 | EBREAK_INSTRUCTION_ENUM, 119 | ADD_INSTRUCTION_ENUM, 120 | SUB_INSTRUCTION_ENUM, 121 | AND_INSTRUCTION_ENUM, 122 | OR_INSTRUCTION_ENUM, 123 | XOR_INSTRUCTION_ENUM, 124 | SLT_INSTRUCTION_ENUM, 125 | SLTU_INSTRUCTION_ENUM, 126 | SLL_INSTRUCTION_ENUM, 127 | SRL_INSTRUCTION_ENUM, 128 | SRA_INSTRUCTION_ENUM, 129 | INVALID_INSTRUCTION_ENUM, 130 | }; 131 | 132 | std::map instruction_name_map = { 133 | {ADDI_INSTRUCTION_ENUM,"ADDI"}, 134 | {ANDI_INSTRUCTION_ENUM,"ANDI"}, 135 | {ORI_INSTRUCTION_ENUM,"ORI"}, 136 | {XORI_INSTRUCTION_ENUM,"XORI"}, 137 | {SLTI_INSTRUCTION_ENUM,"SLTI"}, 138 | {SLTIU_INSTRUCTION_ENUM,"SLTIU"}, 139 | {SLLI_INSTRUCTION_ENUM,"SLLI"}, 140 | {SRLI_INSTRUCTION_ENUM,"SRLI"}, 141 | {SRAI_INSTRUCTION_ENUM,"SRAI"}, 142 | {LUI_INSTRUCTION_ENUM,"LUI"}, 143 | {AUIPC_INSTRUCTION_ENUM,"AUIPC"}, 144 | {LB_INSTRUCTION_ENUM,"LB"}, 145 | {LH_INSTRUCTION_ENUM,"LH"}, 146 | {LW_INSTRUCTION_ENUM,"LW"}, 147 | {LBU_INSTRUCTION_ENUM,"LBU"}, 148 | {LHU_INSTRUCTION_ENUM,"LHU"}, 149 | {SB_INSTRUCTION_ENUM,"SB"}, 150 | {SH_INSTRUCTION_ENUM,"SH"}, 151 | {SW_INSTRUCTION_ENUM,"SW"}, 152 | {JAL_INSTRUCTION_ENUM,"JAL"}, 153 | {JALR_INSTRUCTION_ENUM,"JALR"}, 154 | {BEQ_INSTRUCTION_ENUM,"BEQ"}, 155 | {BNE_INSTRUCTION_ENUM,"BNE"}, 156 | {BLT_INSTRUCTION_ENUM,"BLT"}, 157 | {BGE_INSTRUCTION_ENUM,"BGE"}, 158 | {BLTU_INSTRUCTION_ENUM,"BLTU"}, 159 | {BGEU_INSTRUCTION_ENUM,"BGEU"}, 160 | {FENCE_INSTRUCTION_ENUM,"FENCE"}, 161 | {FENCE_TSO_INSTRUCTION_ENUM,"FENCE_TSO"}, 162 | {ECALL_INSTRUCTION_ENUM,"ECALL"}, 163 | {EBREAK_INSTRUCTION_ENUM,"EBREAK"}, 164 | {ADD_INSTRUCTION_ENUM,"ADD"}, 165 | {SUB_INSTRUCTION_ENUM,"SUB"}, 166 | {AND_INSTRUCTION_ENUM,"AND"}, 167 | {OR_INSTRUCTION_ENUM,"OR"}, 168 | {XOR_INSTRUCTION_ENUM,"XOR"}, 169 | {SLT_INSTRUCTION_ENUM,"SLT"}, 170 | {SLTU_INSTRUCTION_ENUM,"SLTU"}, 171 | {SLL_INSTRUCTION_ENUM,"SLL"}, 172 | {SRL_INSTRUCTION_ENUM,"SRL"}, 173 | {SRA_INSTRUCTION_ENUM,"SRA"}, 174 | 175 | }; 176 | 177 | void set_instruction(uint32_t value) 178 | { 179 | instruction_value = sc_dt::sc_uint<32>(value); 180 | } 181 | 182 | INSTRUCTION_DECODER_INTERFACE::ExtensionType extension() 183 | { 184 | if ((instruction_value & 0x00000003) == 0b11) { 185 | return INSTRUCTION_DECODER_INTERFACE::BASE_RV32I; 186 | } 187 | return INSTRUCTION_DECODER_INTERFACE::UNSUPPORTED; 188 | } 189 | 190 | virtual Instruction get_instruction() = 0; 191 | virtual void log_instruction(uint32_t current_pc, uint32_t target_pc, uint32_t rs1Value, uint32_t rs2Value, uint32_t rdValue,int32_t immValue) = 0; 192 | virtual uint32_t get_opcode() = 0; 193 | virtual uint32_t get_func3() = 0; 194 | virtual uint32_t get_func7() = 0; 195 | virtual uint32_t get_func12() = 0; 196 | 197 | virtual uint32_t get_rs1() = 0; 198 | virtual uint32_t get_rs2() = 0; 199 | virtual uint32_t get_rd() = 0; 200 | 201 | virtual int32_t get_imm(uint32_t start, uint32_t end) = 0; 202 | virtual int32_t get_imm_j() = 0; 203 | virtual int32_t get_imm_b() = 0; 204 | virtual uint32_t get_imm_fence_fm() = 0; 205 | 206 | protected: 207 | sc_dt::sc_uint<32> instruction_value; 208 | }; 209 | 210 | #endif //INC_INSTRUCTION_DECODER_INTERFACE_H_ 211 | 212 | -------------------------------------------------------------------------------- /simulator/main.cpp: -------------------------------------------------------------------------------- 1 | #include "systemc.h" 2 | 3 | #include "cpu.h" 4 | #include "register.h" 5 | #include "bus.h" 6 | #include "instructionDecoder.h" 7 | #include "executor.h" 8 | 9 | int sc_main(int argc,char** argv) 10 | { 11 | CPU cpu("cpu"); 12 | cpu.set_register_file(std::make_shared()); 13 | cpu.set_address_space(std::make_shared("bus")); 14 | cpu.set_instruction_decoder(std::make_shared()); 15 | cpu.set_executor(std::make_shared()); 16 | sc_core::sc_start(); 17 | return 0; 18 | } 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /simulator/memory.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "memory.h" 5 | 6 | MEMORY::MEMORY(sc_module_name name) : sc_module(name) 7 | { 8 | auto binary = std::array { 9 | 0b000000000001'00000'000'00001'0010011, //ADDI x1 = x0 + 1 10 | 0b111111111111'00001'000'00010'0010011, //ADDI x2 = x1 + (-1) 11 | 0b000000000000'00000'000'00000'0010011, //NOP 12 | 0b100000000000'00001'010'00000'0010011, //SLTI x1 = x0 < negativeNum 13 | 0b100000000000'00010'011'00010'0010011, //SLTU x2 = x0 < PositiveNum 14 | 0b0000000'11111'00010'001'00011'0010011, //SLLI x3 = x2 << 31 15 | 0b0000000'00001'00011'101'00100'0010011, //SRLI x4 = x2 >> 1 16 | 0b0100000'00001'00011'101'00101'0010011, //SRAI x5 = x2 >> 1 17 | 0b00000000000000000001'00110'0110111, //LUI x6 = 1 << 12 18 | 0b00000000000000000001'00110'0010111, //AUIPC x6 = pc + (1 << 12) 19 | 0b000000000100'00000'001'00111'0000011, //LH x7 = sign_ext(read(4, 2)) 20 | 0b000000000100'00000'101'01000'0000011, //LHU x8 = read(4, 2) 21 | 0b0100000'00111'00000'001'00000'0100011, //SH write( 1024, x7, 2)) 22 | 0b00000000100000000000'01001'1101111, //JAL x9 = pc + 4; pc = pc + 8 23 | 0b0000000'00000'00000'000'01000'1100011, //BEQ pc = current_pc + (x0 == x0 ? imm : 4) <--bad guy that ISA manual talk about 24 | 0b000000000000'01001'000'00000'1100111, //JALR x0 = pc + 4; pc = x9 + 0 25 | 0b000000000000'00000'000'00000'1110011, //ECALL 26 | 27 | }; 28 | //programLoader(binary); 29 | loadBinaeyFromHex(); 30 | memory_socket.register_b_transport(this, &MEMORY::b_transport); 31 | 32 | } 33 | 34 | void MEMORY::programLoader(std::array &binary) 35 | { 36 | for(auto instruction: binary) { 37 | dataMemory.push_back(instruction & 0xFF); 38 | dataMemory.push_back(instruction >> 8 & 0xFF); 39 | dataMemory.push_back(instruction >> 16 & 0xFF); 40 | dataMemory.push_back(instruction >> 24 & 0xFF); 41 | 42 | if(instruction != 0) 43 | std::cout << "inst: " << instruction << std::endl; 44 | } 45 | } 46 | 47 | void MEMORY::loadBinaeyFromHex(std::string filePath) 48 | { 49 | std::ifstream hexFile(filePath); 50 | std::string line = ""; 51 | 52 | if(!hexFile.is_open()) { 53 | std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; 54 | std::cout << "Binary File Open Failed!!" << std::endl; 55 | std::cout << "Cause: " << std::strerror(errno) << std::endl; 56 | std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; 57 | return; 58 | } 59 | 60 | uint32_t extended_address = 0; 61 | uint32_t memory_offset = 0; 62 | uint32_t program_counter = 0; 63 | dataMemory.assign(0x100000, 0); 64 | while(std::getline(hexFile, line)) { 65 | if(line[0] != ':') { 66 | continue; //skip this line 67 | } 68 | 69 | switch (std::stoul(line.substr(7, 2))) { 70 | case 0: { //Data 71 | auto byteCount = std::stol(line.substr(1, 2), nullptr, 16); 72 | auto address = extended_address + std::stoul(line.substr(3, 4), nullptr, 16); 73 | for(int i=0; i < byteCount; i++) { 74 | auto value = std::stoul(line.substr(9 + (i*2), 2), nullptr, 16); 75 | dataMemory[address + i] = value; 76 | std::cout << "00" << " address: 0x" << address + i << " value: 0x" << std::hex << value << std::endl; 77 | } 78 | } 79 | break; 80 | case 2: { //Extended segment address 81 | extended_address = std::stoul(line.substr(9, 4), nullptr, 16) * 16; 82 | } 83 | break; 84 | case 3: { //Start segment address 85 | uint32_t code_segment = stoul(line.substr(9, 4), nullptr, 16) * 16; 86 | program_counter = code_segment + stoul(line.substr(13, 4), nullptr, 16); 87 | std::cout << "03 " << "program counter should be: 0x" << std::hex << program_counter << std::endl; 88 | } 89 | break; 90 | case 4: { //Start srgmant address 91 | memory_offset = stoul(line.substr(9, 4), nullptr, 16) << 16; 92 | extended_address = 0; 93 | } 94 | break; 95 | case 5: { //Get start program counter 96 | program_counter = stol(line.substr(9, 8), nullptr, 16); 97 | std::cout << "05 " << "program counter should be: 0x" << std::hex << program_counter << std::endl; 98 | } 99 | break; 100 | default: 101 | break; 102 | } 103 | 104 | } 105 | } 106 | 107 | void MEMORY::b_transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) 108 | { 109 | delay = sc_core::SC_ZERO_TIME; 110 | tlm::tlm_command cmd = trans.get_command(); 111 | sc_dt::uint64 adr = trans.get_address(); 112 | unsigned char *ptr = trans.get_data_ptr(); 113 | unsigned int len = trans.get_data_length(); 114 | 115 | trans.set_response_status(tlm::TLM_OK_RESPONSE); 116 | 117 | for(int i = 0; i < len; i++) { 118 | if(adr < dataMemory.size()) { 119 | if(cmd == tlm::TLM_READ_COMMAND) { 120 | ((char *)ptr)[i] = dataMemory[adr + i]; 121 | //std::cout << "addr: 0x" << std::hex << adr + i << "--" << std::hex << (int)dataMemory[adr + i] << std::endl; 122 | } else if(cmd == tlm::TLM_WRITE_COMMAND) { 123 | dataMemory[adr + i] = ((char *)ptr)[i]; 124 | //std::cout << "addr: 0x" << std::hex << adr + i << "--" << std::hex << (int)dataMemory[adr + i] << std::endl; 125 | } else { 126 | std::cout << "unsupported operation at: 0x" << std::hex << adr << "!!" << std::endl; 127 | } 128 | } else { 129 | trans.set_response_status(tlm::TLM_BURST_ERROR_RESPONSE); 130 | std::cout << "error at address: 0x" << std::hex << adr << "!!" << std::endl; 131 | return; 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /simulator/memory.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "systemc.h" 4 | 5 | #include "tlm_utils/simple_initiator_socket.h" 6 | #include "tlm_utils/simple_target_socket.h" 7 | 8 | #ifndef INC_MEMORY_H_ 9 | #define INC_MEMORY_H_ 10 | class MEMORY : public sc_module 11 | { 12 | public: 13 | MEMORY(sc_module_name name); 14 | 15 | tlm_utils::simple_target_socket memory_socket; 16 | private: 17 | void b_transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay); 18 | 19 | 20 | std::vector dataMemory; 21 | void programLoader(std::array &binary); 22 | void loadBinaeyFromHex(std::string filePath = "./binary.hex"); 23 | }; 24 | #endif //INC_MEMORY_H_ 25 | -------------------------------------------------------------------------------- /simulator/register.cpp: -------------------------------------------------------------------------------- 1 | #include "register.h" 2 | 3 | void REGISTER::set_pc(uint32_t value) 4 | { 5 | register_pc=value; 6 | } 7 | 8 | uint32_t REGISTER::get_pc() 9 | { 10 | return register_pc; 11 | } 12 | 13 | void REGISTER::set_value_integer(unsigned int register_index, int32_t value) 14 | { 15 | if(register_index == 0) 16 | return; 17 | 18 | register_bank_integer[register_index] = value; 19 | } 20 | 21 | int32_t REGISTER::get_value_integer(unsigned int register_index) 22 | { 23 | if(register_index == 0) 24 | return 0; 25 | return register_bank_integer[register_index]; 26 | } 27 | -------------------------------------------------------------------------------- /simulator/register.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "registerInterface.h" 5 | 6 | #ifndef INC_REGISTER_H_ 7 | #define INC_REGISTER_H_ 8 | class REGISTER: public REGISTER_INTERFACE 9 | { 10 | public: 11 | virtual void set_value_integer(unsigned int register_index, int32_t value) override; 12 | virtual int32_t get_value_integer(unsigned int register_index) override; 13 | 14 | virtual void set_pc(uint32_t value) override; 15 | virtual uint32_t get_pc() override; 16 | 17 | private: 18 | std::array register_bank_integer; 19 | uint32_t register_pc; 20 | }; 21 | #endif //INC_REGISTER_H_ 22 | -------------------------------------------------------------------------------- /simulator/registerInterface.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef INC_REGISTER_INTERFACE_H_ 4 | #define INC_REGISTER_INTERFACE_H_ 5 | class REGISTER_INTERFACE 6 | { 7 | public: 8 | enum { 9 | x0 = 0, 10 | x1 = 1, 11 | x2, 12 | x3, 13 | x4, 14 | x5, 15 | x6, 16 | x7, 17 | x8, 18 | x9, 19 | x10, 20 | x11, 21 | x12, 22 | x13, 23 | x14, 24 | x15, 25 | x16, 26 | x17, 27 | x18, 28 | x19, 29 | x20, 30 | x21, 31 | x22, 32 | x23, 33 | x24, 34 | x25, 35 | x26, 36 | x27, 37 | x28, 38 | x29, 39 | x30, 40 | x31, 41 | zero = x0, 42 | ra = x1, 43 | sp = x2, 44 | gp = x3, 45 | tp = x4, 46 | t0 = x5, 47 | t1 = x6, 48 | t2 = x7, 49 | s0 = x8, 50 | fp = x8, 51 | s1 = x9, 52 | a0 = x10, 53 | a1 = x11, 54 | a2 = x12, 55 | a3 = x13, 56 | a4 = x14, 57 | a5 = x15, 58 | a6 = x16, 59 | a7 = x17, 60 | s2 = x18, 61 | s3 = x19, 62 | s4 = x20, 63 | s5 = x21, 64 | s6 = x22, 65 | s7 = x23, 66 | s8 = x24, 67 | s9 = x25, 68 | s10 = x26, 69 | s11 = x27, 70 | t3 = x28, 71 | t4 = x29, 72 | t5 = x30, 73 | t6 = x31 74 | }; 75 | 76 | virtual void set_value_integer(unsigned int register_index, int32_t value) = 0; 77 | virtual int32_t get_value_integer(unsigned int register_index) = 0; 78 | 79 | virtual void set_pc(uint32_t value) = 0; 80 | virtual uint32_t get_pc() = 0; 81 | }; 82 | #endif //INC_REGISTER_INTERFACE_H_ 83 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE ?= riscv32-unknown-elf- 2 | CC= $(CROSS_COMPILE)gcc 3 | CFLAGS = -Wall -I. -O0 -nostdlib -march=rv32i -mabi=ilp32 --entry main 4 | 5 | SRC= hello 6 | TARGET= binary 7 | 8 | export PATH:=/home/user/Desktop/code/rv32i-ilp32-gnu-toolchain/bin:${PATH} 9 | 10 | all: $(addsuffix .o, $(SRC)) 11 | $(CROSS_COMPILE)objcopy -Oihex $< $(TARGET).hex 12 | readelf -a $< 13 | 14 | dump: $(addsuffix .o, $(SRC)) 15 | $(CROSS_COMPILE)objdump -Slz $< 16 | 17 | 18 | %.o: %.c 19 | $(CC) $(CFLAGS) $< -o $@ 20 | 21 | clean: 22 | -rm *.o *.hex 23 | 24 | -------------------------------------------------------------------------------- /test/hello.c: -------------------------------------------------------------------------------- 1 | #define CONSOLE (*(unsigned char *)0x400000) 2 | 3 | int printToTrace(char* input) 4 | { 5 | int i=0; 6 | while(input[i] != '\0') { 7 | CONSOLE = input[i]; 8 | i++; 9 | } 10 | } 11 | 12 | int main() 13 | { 14 | printToTrace("hello world!"); 15 | return 0; 16 | } 17 | 18 | --------------------------------------------------------------------------------