Improve vmem handling a bit
This commit is contained in:
parent
2395b75e4d
commit
dfc9b2824e
4 changed files with 120 additions and 125 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
172
src/vm.cpp
172
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<char>(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<uint8_t>& memory, const std::string& file_path)
|
||||
|
@ -45,96 +27,84 @@ void VM::setreg(int regnum, uint32_t value) {
|
|||
registers[regnum] = value;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> VM::read_memory(size_t start, size_t size) {
|
||||
if (start >= PROGRAM_ADDR) {
|
||||
start -= PROGRAM_ADDR;
|
||||
if (start + size > memory_.size()) {
|
||||
return std::vector<uint8_t>(size, 0);
|
||||
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;
|
||||
}
|
||||
return std::vector<uint8_t>(memory_.begin() + start,
|
||||
memory_.begin() + start + size);
|
||||
} else {
|
||||
return std::vector<uint8_t>(size, 0);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t VM::read_memory_word(size_t pos) {
|
||||
if (pos >= PROGRAM_ADDR) {
|
||||
pos -= PROGRAM_ADDR;
|
||||
if (pos + 3 >= memory_.size()) {
|
||||
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");
|
||||
}
|
||||
return *(uint32_t*)&memory_[pos];
|
||||
} else {
|
||||
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<char>(*src));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t VM::read_memory_half_word(size_t pos) {
|
||||
if (pos >= PROGRAM_ADDR) {
|
||||
pos -= PROGRAM_ADDR;
|
||||
if (pos + 1 >= memory_.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");
|
||||
}
|
||||
|
||||
return *(uint16_t*)&memory_[pos];
|
||||
} else {
|
||||
throw std::runtime_error("Memory access out of bounds");
|
||||
std::memcpy(dst, &memory_[addr], size);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t VM::read_memory_byte(size_t pos) {
|
||||
if (pos >= PROGRAM_ADDR) {
|
||||
pos -= PROGRAM_ADDR;
|
||||
if (pos >= memory_.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;
|
||||
}
|
||||
|
||||
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);
|
||||
if (is_mmap(addr, size)) {
|
||||
if (addr >= UART_ADDR && addr < UART_ADDR + 8) {
|
||||
uart.write_mem(src, addr, size);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> VM::read_memory(size_t start, size_t size) {
|
||||
std::vector<uint8_t> res(size, 0);
|
||||
|
||||
size_t i = start;
|
||||
size_t end = start + size;
|
||||
|
||||
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");
|
||||
}
|
||||
|
|
16
src/vm.hpp
16
src/vm.hpp
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -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<uint8_t> 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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue