From dfc9b2824e2e682721cb2a0e4e0b13b40da612a8 Mon Sep 17 00:00:00 2001 From: Konstantin Nazarov Date: Wed, 18 Dec 2024 23:05:34 +0000 Subject: [PATCH] Improve vmem handling a bit --- example/example.c | 17 ++++ src/debug.cpp | 8 +- src/vm.cpp | 204 +++++++++++++++++++++------------------------- src/vm.hpp | 16 ++-- 4 files changed, 120 insertions(+), 125 deletions(-) diff --git a/example/example.c b/example/example.c index 0de0bb8..91aa3f1 100644 --- a/example/example.c +++ b/example/example.c @@ -1,5 +1,21 @@ #include "printf.h" +typedef unsigned long long uint64_t; +typedef unsigned long uint32_t; +#define MTIME_BASE 0x0200BFF8 + +uint64_t read_mtime_atomic() { + uint32_t upper1, lower, upper2; + + do { + upper1 = *(uint32_t*)(MTIME_BASE + 4); + lower = *(uint32_t*)(MTIME_BASE); + upper2 = *(uint32_t*)(MTIME_BASE + 4); + } while (upper1 != upper2); // Repeat if upper changed during the process + + return ((uint64_t)upper1 << 32) | lower; +} + int fact(int n) { if (n == 0) return 1; @@ -11,6 +27,7 @@ int main() { int n = 8; int res = fact(8); + printf("sizeof(long) = %d\n", sizeof(long long)); printf("%d! = %d\n", n, res); return 0; diff --git a/src/debug.cpp b/src/debug.cpp index 8fda93c..227798c 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -228,9 +228,11 @@ void GDBStub::handle_packet(const std::string &packet) { std::stoul(packet.substr(3, packet.find(',', 3)), nullptr, 16); if (breakpoints.count(addr) == 0) { - uint32_t original_instr = vm.read_memory_word(addr); + uint32_t original_instr; + vm.read_mem((uint8_t *)&original_instr, addr, 4); breakpoints[addr] = original_instr; - vm.write_memory_word(addr, 0x00100073); // 0x00100073 is EBREAK + uint32_t debug_instr = 0x00100073; // 0x00100073 is EBREAK + vm.write_mem((uint8_t *)&debug_instr, addr, 4); } } send_packet("OK"); @@ -244,7 +246,7 @@ void GDBStub::handle_packet(const std::string &packet) { if (breakpoints.count(addr) > 0) { // Restore the original instruction - vm.write_memory_word(addr, breakpoints[addr]); + vm.write_mem((uint8_t *)&breakpoints[addr], addr, 4); breakpoints.erase(addr); } } diff --git a/src/vm.cpp b/src/vm.cpp index ad0d604..7f241ef 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -12,26 +12,8 @@ inline int32_t sign_extend(int32_t value, int bits) { return (value ^ mask) - mask; } -uint8_t UART::read_register(uint32_t address) { - switch (address) { - case UART_LSR: - // Always ready to transmit - return LSR_TRANSMITTER_EMPTY; - default: - return 0; - } -} - -void UART::write_register(uint32_t address, uint8_t value) { - switch (address) { - case UART_THR: - std::cout.put(static_cast(value)); - break; - } -} - bool UART::is_transmitter_ready() { - return read_register(UART_LSR) & LSR_TRANSMITTER_EMPTY; + return registers[UART_LSR] & LSR_TRANSMITTER_EMPTY; } VM::VM(const std::vector& memory, const std::string& file_path) @@ -45,96 +27,84 @@ void VM::setreg(int regnum, uint32_t value) { registers[regnum] = value; } +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"); + } + addr -= UART_ADDR; + for (size_t i = 0; i < size; i++) { + switch (addr + i) { + case UART_LSR: + // Always ready to transmit + dst[i] = LSR_TRANSMITTER_EMPTY; + default: + dst[i] = 0; + } + } +} + +void UART::write_mem(uint8_t* src, size_t addr, size_t size) { + if (addr < UART_ADDR || addr + size > UART_ADDR + 8) { + throw std::runtime_error("Memory access out of bounds"); + } + addr -= UART_ADDR; + for (size_t i = 0; i < size; i++) { + switch (addr + i) { + case UART_THR: + std::cout.put(static_cast(*src)); + break; + } + } +} + +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); + } +} + +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; + } + + if (is_mmap(addr, size)) { + if (addr >= UART_ADDR && addr < UART_ADDR + 8) { + uart.write_mem(src, addr, size); + } + return; + } +} + std::vector VM::read_memory(size_t start, size_t size) { - if (start >= PROGRAM_ADDR) { - start -= PROGRAM_ADDR; - if (start + size > memory_.size()) { - return std::vector(size, 0); - } - return std::vector(memory_.begin() + start, - memory_.begin() + start + size); - } else { - return std::vector(size, 0); - } -} + std::vector res(size, 0); -uint32_t VM::read_memory_word(size_t pos) { - if (pos >= PROGRAM_ADDR) { - pos -= PROGRAM_ADDR; - if (pos + 3 >= memory_.size()) { - throw std::runtime_error("Memory access out of bounds"); - } - return *(uint32_t*)&memory_[pos]; - } else { - throw std::runtime_error("Memory access out of bounds"); - } -} + size_t i = start; + size_t end = start + size; -uint16_t VM::read_memory_half_word(size_t pos) { - if (pos >= PROGRAM_ADDR) { - pos -= PROGRAM_ADDR; - if (pos + 1 >= memory_.size()) { - throw std::runtime_error("Memory access out of bounds"); - } - - return *(uint16_t*)&memory_[pos]; - } else { - throw std::runtime_error("Memory access out of bounds"); - } -} - -uint8_t VM::read_memory_byte(size_t pos) { - if (pos >= PROGRAM_ADDR) { - pos -= PROGRAM_ADDR; - if (pos >= memory_.size()) { - throw std::runtime_error("Memory access out of bounds"); - } - - return memory_[pos]; - } else { - throw std::runtime_error("Memory access out of bounds"); - } -} - -void VM::write_memory_word(size_t pos, uint32_t value) { - if (pos >= PROGRAM_ADDR) { - pos -= PROGRAM_ADDR; - if (pos + 1 >= memory_.size()) { - throw std::runtime_error("Memory access out of bounds"); - } - *(uint32_t*)&memory_[pos] = value; - } else { - throw std::runtime_error("Memory access out of bounds"); - } -} - -void VM::write_memory_half_word(size_t pos, uint16_t value) { - if (pos >= PROGRAM_ADDR) { - pos -= PROGRAM_ADDR; - if (pos + 3 >= memory_.size()) { - throw std::runtime_error("Memory access out of bounds"); - } - *(uint16_t*)&memory_[pos] = value; - } else { - throw std::runtime_error("Memory access out of bounds"); - } -} - -void VM::write_memory_byte(size_t pos, uint8_t value) { - if (pos >= PROGRAM_ADDR) { - pos -= PROGRAM_ADDR; - if (pos >= memory_.size()) { - throw std::runtime_error("Memory access out of bounds"); - } - memory_[pos] = value; - } else { - if (is_mmap(pos, 1)) { - if (pos >= UART_ADDR && pos < UART_ADDR + 8) { - uart.write_register(pos - UART_ADDR, value); - } - return; + while (i < end) { + if (i % 4 == 0 && end - i >= 4) { + read_mem(&res[i - start], i, 4); + i += 4; + } else if (i % 2 == 0 && end - i >= 2) { + read_mem(&res[i - start], i, 2); + i += 2; + } else { + read_mem(&res[i - start], i, 1); + i += 1; } } + + return res; } bool VM::is_mmap(size_t pos, size_t size) { @@ -353,19 +323,29 @@ void VM::step() { imm = sign_extend(instr >> 20, 12); // Extract 12-bit immediate if (funct3 == 0x00) { // LB uint32_t addr = registers[rs1] + imm; - setreg(rd, sign_extend(read_memory_byte(addr), 8)); + uint8_t val; + read_mem(&val, addr, 1); + setreg(rd, sign_extend(val, 8)); } else if (funct3 == 0x01) { // LH uint32_t addr = registers[rs1] + imm; - setreg(rd, sign_extend(read_memory_half_word(addr), 16)); + uint16_t val; + read_mem((uint8_t*)&val, addr, 2); + setreg(rd, sign_extend(val, 16)); } else if (funct3 == 0x2) { // LW uint32_t addr = registers[rs1] + imm; - setreg(rd, read_memory_word(addr)); + uint32_t val; + read_mem((uint8_t*)&val, addr, 4); + setreg(rd, val); } else if (funct3 == 0x4) { // LBU uint32_t addr = registers[rs1] + imm; - setreg(rd, read_memory_byte(addr)); + uint8_t val; + read_mem(&val, addr, 1); + setreg(rd, val); } else if (funct3 == 0x5) { // LHU uint32_t addr = registers[rs1] + imm; - setreg(rd, read_memory_half_word(addr)); + uint16_t val; + read_mem((uint8_t*)&val, addr, 2); + setreg(rd, val); } else { throw std::runtime_error("Unknown load instruction"); } @@ -376,13 +356,13 @@ void VM::step() { imm = sign_extend(imm, 12); // Sign-extend 12-bit immediate if (funct3 == 0x0) { // SB uint32_t addr = registers[rs1] + imm; - write_memory_byte(addr, registers[rs2]); + write_mem((uint8_t*)®isters[rs2], addr, 1); } else if (funct3 == 0x1) { // SH uint32_t addr = registers[rs1] + imm; - write_memory_half_word(addr, registers[rs2]); + write_mem((uint8_t*)®isters[rs2], addr, 2); } else if (funct3 == 0x2) { // SW uint32_t addr = registers[rs1] + imm; - write_memory_word(addr, registers[rs2]); + write_mem((uint8_t*)®isters[rs2], addr, 4); } else { throw std::runtime_error("Unknown store instruction"); } diff --git a/src/vm.hpp b/src/vm.hpp index afc81b7..324192b 100644 --- a/src/vm.hpp +++ b/src/vm.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -13,11 +14,11 @@ const uint32_t PROGRAM_ADDR = 0x80000000; class UART { public: - uint8_t read_register(uint32_t address); - void write_register(uint32_t address, uint8_t value); - bool is_transmitter_ready(); + void write_mem(uint8_t *src, size_t addr, size_t size); + void read_mem(uint8_t *dst, size_t addr, size_t size); + private: enum Registers { UART_RBR = 0x00, // Receiver Buffer Register @@ -40,13 +41,8 @@ class VM { std::vector read_memory(size_t start, size_t size); - uint32_t read_memory_word(size_t pos); - uint16_t read_memory_half_word(size_t pos); - uint8_t read_memory_byte(size_t pos); - - void write_memory_word(size_t pos, uint32_t value); - void write_memory_half_word(size_t pos, uint16_t value); - void write_memory_byte(size_t pos, uint8_t value); + void read_mem(uint8_t *dst, size_t addr, size_t size); + void write_mem(uint8_t *src, size_t addr, size_t size); bool is_mmap(size_t pos, size_t size);