diff --git a/src/vm.cpp b/src/vm.cpp index 7f241ef..20ab3e8 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -12,12 +12,8 @@ inline int32_t sign_extend(int32_t value, int bits) { return (value ^ mask) - mask; } -bool UART::is_transmitter_ready() { - return registers[UART_LSR] & LSR_TRANSMITTER_EMPTY; -} - VM::VM(const std::vector& memory, const std::string& file_path) - : memory_(memory), pc(PROGRAM_ADDR), file_path(file_path) {} + : ram(memory), pc(PROGRAM_ADDR), file_path(file_path) {} void VM::setreg(int regnum, uint32_t value) { if (regnum == 0) { @@ -27,6 +23,22 @@ void VM::setreg(int regnum, uint32_t value) { registers[regnum] = value; } +void Device::write_mem(uint8_t* src, size_t addr, size_t size) { + if (addr < base_addr || addr + size > base_addr + mem_size) { + throw std::runtime_error("Memory access out of bounds"); + } + addr -= base_addr; + std::memcpy(&mem[addr], src, size); +} + +void Device::read_mem(uint8_t* dst, size_t addr, size_t size) { + if (addr < base_addr || addr + size > base_addr + mem_size) { + throw std::runtime_error("Memory access out of bounds"); + } + addr -= base_addr; + std::memcpy(dst, &mem[addr], size); +} + void UART::read_mem(uint8_t* dst, size_t addr, size_t size) { if (addr < UART_ADDR || addr + size > UART_ADDR + 8) { throw std::runtime_error("Memory access out of bounds"); @@ -59,22 +71,13 @@ void UART::write_mem(uint8_t* src, size_t addr, size_t size) { void VM::read_mem(uint8_t* dst, size_t addr, size_t size) { if (addr >= PROGRAM_ADDR) { - addr -= PROGRAM_ADDR; - if (addr + size > memory_.size()) { - throw std::runtime_error("Memory access out of bounds"); - } - std::memcpy(dst, &memory_[addr], size); + ram.read_mem(dst, addr, size); } } void VM::write_mem(uint8_t* src, size_t addr, size_t size) { if (addr >= PROGRAM_ADDR) { - addr -= PROGRAM_ADDR; - if (addr + size > memory_.size()) { - throw std::runtime_error("Memory access out of bounds"); - } - std::memcpy(&memory_[addr], src, size); - return; + ram.write_mem(src, addr, size); } if (is_mmap(addr, size)) { @@ -128,7 +131,8 @@ const std::string& VM::get_file_path() { return file_path; } void VM::step() { if (pc < PROGRAM_ADDR) throw std::runtime_error("PC out of range"); - uint32_t instr = *(uint32_t*)&memory_[pc - PROGRAM_ADDR]; + uint32_t instr; + read_mem((uint8_t*)&instr, pc, 4); // std::cout << "pc: " << std::hex << pc << std::dec << "\n"; // std::cout << "instr: " << std::hex << instr << "\n"; pc += 4; diff --git a/src/vm.hpp b/src/vm.hpp index 324192b..ede64a0 100644 --- a/src/vm.hpp +++ b/src/vm.hpp @@ -12,12 +12,30 @@ const int NUM_REGISTERS = 32; // Standard RISC-V has 32 registers const uint32_t UART_ADDR = 0x10000000; const uint32_t PROGRAM_ADDR = 0x80000000; -class UART { +class Device { public: - bool is_transmitter_ready(); + Device(uint32_t base_addr, uint32_t mem_size) + : base_addr(base_addr), mem_size(mem_size), mem(mem_size, 0) {} + Device(uint32_t base_addr, const std::vector &memory) + : base_addr(base_addr), mem_size(memory.size()), mem(memory) {} - void write_mem(uint8_t *src, size_t addr, size_t size); - void read_mem(uint8_t *dst, size_t addr, size_t size); + virtual ~Device() = default; + + virtual void write_mem(uint8_t *src, size_t addr, size_t size); + virtual void read_mem(uint8_t *dst, size_t addr, size_t size); + + private: + uint32_t base_addr = 0; + uint32_t mem_size = 0; + std::vector mem; +}; + +class UART : public Device { + public: + UART() : Device(UART_ADDR, 8) {} + + virtual void write_mem(uint8_t *src, size_t addr, size_t size); + virtual void read_mem(uint8_t *dst, size_t addr, size_t size); private: enum Registers { @@ -28,8 +46,11 @@ class UART { // Line Status Register bits enum LSRBits { LSR_TRANSMITTER_EMPTY = 0x20 }; +}; - uint8_t registers[8] = {0}; +class RAM : public Device { + public: + RAM(const std::vector &memory) : Device(PROGRAM_ADDR, memory) {} }; class VM { @@ -53,7 +74,7 @@ class VM { void setreg(int regnum, uint32_t value); private: - std::vector memory_; + RAM ram; uint32_t registers[NUM_REGISTERS] = {0}; uint32_t pc = 0;