Speed up framebuffer operation to reach about 200fps fill rate
This commit is contained in:
parent
44b45c58c6
commit
65e5011f7f
7 changed files with 191 additions and 78 deletions
|
@ -6,7 +6,11 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS true)
|
||||||
|
|
||||||
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||||
|
|
||||||
set (CMAKE_CXX_FLAGS "-static-libgcc -static-libstdc++ -Werror -Wall -Wunused-result -Wno-unused-function -Wno-unused-variable -fno-omit-frame-pointer -fsanitize=address -Wno-c99-designator")
|
set (CMAKE_CXX_FLAGS "-static-libgcc -static-libstdc++ -Werror -Wall -Wunused-result -Wno-unused-function -Wno-unused-variable -fno-omit-frame-pointer -Wno-c99-designator")
|
||||||
|
|
||||||
|
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
|
||||||
|
endif()
|
||||||
|
|
||||||
find_package(SDL2 REQUIRED)
|
find_package(SDL2 REQUIRED)
|
||||||
|
|
||||||
|
|
|
@ -35,14 +35,16 @@ int fib(int n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw() {
|
void draw() {
|
||||||
|
for (int k = 0; k < 200; k++) {
|
||||||
for (int i = 0; i< 640; i++) {
|
for (int i = 0; i< 640; i++) {
|
||||||
for (int j = 0; j < 480; j++) {
|
for (int j = 0; j < 480; j++) {
|
||||||
uint32_t color = i*j;
|
uint32_t color = i*(j + k);
|
||||||
uint32_t* addr = (uint32_t*)(FRAMEBUFFER_BASE + ((j*640) + i) *4);
|
uint32_t* addr = (uint32_t*)(FRAMEBUFFER_BASE + ((j*640) + i) *4);
|
||||||
*addr = color;
|
*addr = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
uint64_t start = read_mtime_atomic();
|
uint64_t start = read_mtime_atomic();
|
||||||
|
|
8
rve.nix
8
rve.nix
|
@ -32,7 +32,13 @@ pkgs.gcc13Stdenv.mkDerivation rec {
|
||||||
hardeningDisable = [ "all" ];
|
hardeningDisable = [ "all" ];
|
||||||
cmakeFlags = [
|
cmakeFlags = [
|
||||||
"-DCMAKE_EXPORT_COMPILE_COMMANDS=TRUE"
|
"-DCMAKE_EXPORT_COMPILE_COMMANDS=TRUE"
|
||||||
"-DCMAKE_BUILD_TYPE=Debug"
|
#"-DCMAKE_BUILD_TYPE=Debug"
|
||||||
|
"-DCMAKE_BUILD_TYPE=RelWithDebInfo"
|
||||||
|
|
||||||
|
# For profiling
|
||||||
|
# "-DCMAKE_CXX_FLAGS=-pg"
|
||||||
|
# "-DCMAKE_EXE_LINKER_FLAGS=-pg"
|
||||||
|
# "-DCMAKE_SHARED_LINKER_FLAGS=-pg"
|
||||||
];
|
];
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
export CMAKE_BUILD_TYPE=Debug
|
export CMAKE_BUILD_TYPE=Debug
|
||||||
|
|
|
@ -229,10 +229,10 @@ void GDBStub::handle_packet(const std::string &packet) {
|
||||||
|
|
||||||
if (breakpoints.count(addr) == 0) {
|
if (breakpoints.count(addr) == 0) {
|
||||||
uint32_t original_instr;
|
uint32_t original_instr;
|
||||||
vm.read_mem((uint8_t *)&original_instr, addr, 4);
|
vm.read_mem_u32(&original_instr, addr);
|
||||||
breakpoints[addr] = original_instr;
|
breakpoints[addr] = original_instr;
|
||||||
uint32_t debug_instr = 0x00100073; // 0x00100073 is EBREAK
|
uint32_t debug_instr = 0x00100073; // 0x00100073 is EBREAK
|
||||||
vm.write_mem((uint8_t *)&debug_instr, addr, 4);
|
vm.write_mem_u32(&debug_instr, addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
send_packet("OK");
|
send_packet("OK");
|
||||||
|
@ -246,7 +246,7 @@ void GDBStub::handle_packet(const std::string &packet) {
|
||||||
|
|
||||||
if (breakpoints.count(addr) > 0) {
|
if (breakpoints.count(addr) > 0) {
|
||||||
// Restore the original instruction
|
// Restore the original instruction
|
||||||
vm.write_mem((uint8_t *)&breakpoints[addr], addr, 4);
|
vm.write_mem_u32(&breakpoints[addr], addr);
|
||||||
breakpoints.erase(addr);
|
breakpoints.erase(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,10 +51,28 @@ void Framebuffer::draw() {
|
||||||
SDL_RenderPresent(renderer);
|
SDL_RenderPresent(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Framebuffer::write_mem(uint8_t* src, size_t addr, size_t size) {
|
void Framebuffer::write_mem_u8(uint8_t* src, size_t addr) {
|
||||||
Device::write_mem(src, addr, size);
|
Device::write_mem_u8(src, addr);
|
||||||
|
|
||||||
if (addr + size == base() + (640 * 480) * 4) {
|
if (addr + 1 == base() + (640 * 480) * 4) {
|
||||||
|
// draw to the screen when the last byte is written
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Framebuffer::write_mem_u16(uint16_t* src, size_t addr) {
|
||||||
|
Device::write_mem_u16(src, addr);
|
||||||
|
|
||||||
|
if (addr + 2 == base() + (640 * 480) * 4) {
|
||||||
|
// draw to the screen when the last byte is written
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Framebuffer::write_mem_u32(uint32_t* src, size_t addr) {
|
||||||
|
Device::write_mem_u32(src, addr);
|
||||||
|
|
||||||
|
if (addr + 4 == base() + (640 * 480) * 4) {
|
||||||
// draw to the screen when the last byte is written
|
// draw to the screen when the last byte is written
|
||||||
draw();
|
draw();
|
||||||
}
|
}
|
||||||
|
|
137
src/vm.cpp
137
src/vm.cpp
|
@ -30,76 +30,114 @@ void VM::setreg(size_t regnum, uint32_t value) {
|
||||||
registers[regnum] = value;
|
registers[regnum] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::write_mem(uint8_t* src, size_t addr, size_t size) {
|
void UART::read_mem_u8(uint8_t* dst, size_t addr) {
|
||||||
if (addr < base_addr || addr + size > base_addr + mem_size) {
|
if (addr < UART_ADDR || addr + 1 > UART_ADDR + 8) {
|
||||||
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");
|
throw std::runtime_error("Memory access out of bounds");
|
||||||
}
|
}
|
||||||
addr -= UART_ADDR;
|
addr -= UART_ADDR;
|
||||||
for (size_t i = 0; i < size; i++) {
|
switch (addr) {
|
||||||
switch (addr + i) {
|
|
||||||
case UART_LSR:
|
case UART_LSR:
|
||||||
// Always ready to transmit
|
// Always ready to transmit
|
||||||
dst[i] = LSR_TRANSMITTER_EMPTY;
|
*dst = LSR_TRANSMITTER_EMPTY;
|
||||||
default:
|
default:
|
||||||
dst[i] = 0;
|
*dst = 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UART::write_mem(uint8_t* src, size_t addr, size_t size) {
|
void UART::write_mem_u8(uint8_t* src, size_t addr) {
|
||||||
if (addr < UART_ADDR || addr + size > UART_ADDR + 8) {
|
if (addr < UART_ADDR || addr + 1 > UART_ADDR + 8) {
|
||||||
throw std::runtime_error("Memory access out of bounds");
|
throw std::runtime_error("Memory access out of bounds");
|
||||||
}
|
}
|
||||||
addr -= UART_ADDR;
|
addr -= UART_ADDR;
|
||||||
for (size_t i = 0; i < size; i++) {
|
switch (addr) {
|
||||||
switch (addr + i) {
|
|
||||||
case UART_THR:
|
case UART_THR:
|
||||||
std::cout.put(static_cast<char>(*src));
|
std::cout.put(static_cast<char>(*src));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void Timer::read_mem(uint8_t* dst, size_t addr, size_t size) {
|
void Timer::update() {
|
||||||
using Clock = std::chrono::high_resolution_clock;
|
using Clock = std::chrono::high_resolution_clock;
|
||||||
constexpr auto den = Clock::period::den;
|
constexpr auto den = Clock::period::den;
|
||||||
constexpr auto num = Clock::period::num;
|
constexpr auto num = Clock::period::num;
|
||||||
|
|
||||||
// Let's assume that clock rate is 1MHz for now
|
// Let's assume that clock rate is 1MHz for now
|
||||||
set(Clock::now().time_since_epoch().count() / (den / (1000000 * num)));
|
uint64_t value =
|
||||||
Device::read_mem(dst, addr, size);
|
Clock::now().time_since_epoch().count() / (den / (1000000 * num));
|
||||||
|
|
||||||
|
write_mem_u32((uint32_t*)&value, MTIME_ADDR);
|
||||||
|
write_mem_u32(((uint32_t*)&value) + 1, MTIME_ADDR + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VM::read_mem(uint8_t* dst, size_t addr, size_t size) {
|
void Timer::read_mem_u8(uint8_t* dst, size_t addr) {
|
||||||
|
update();
|
||||||
|
Device::read_mem_u8(dst, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Timer::read_mem_u16(uint16_t* dst, size_t addr) {
|
||||||
|
update();
|
||||||
|
Device::read_mem_u16(dst, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Timer::read_mem_u32(uint32_t* dst, size_t addr) {
|
||||||
|
update();
|
||||||
|
Device::read_mem_u32(dst, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VM::read_mem_u8(uint8_t* dst, size_t addr) {
|
||||||
for (Device* dev : devices) {
|
for (Device* dev : devices) {
|
||||||
if (addr >= dev->base() && addr + size <= dev->base() + dev->size()) {
|
if (addr >= dev->base() && addr + 1 <= dev->base() + dev->size()) {
|
||||||
dev->read_mem(dst, addr, size);
|
dev->read_mem_u8(dst, addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw std::runtime_error("Memory access out of bounds");
|
throw std::runtime_error("Memory access out of bounds");
|
||||||
}
|
}
|
||||||
|
|
||||||
void VM::write_mem(uint8_t* src, size_t addr, size_t size) {
|
void VM::read_mem_u16(uint16_t* dst, size_t addr) {
|
||||||
for (Device* dev : devices) {
|
for (Device* dev : devices) {
|
||||||
if (addr >= dev->base() && addr + size <= dev->base() + dev->size()) {
|
if (addr >= dev->base() && addr + 2 <= dev->base() + dev->size()) {
|
||||||
dev->write_mem(src, addr, size);
|
dev->read_mem_u16(dst, addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::runtime_error("Memory access out of bounds");
|
||||||
|
}
|
||||||
|
|
||||||
|
void VM::read_mem_u32(uint32_t* dst, size_t addr) {
|
||||||
|
for (Device* dev : devices) {
|
||||||
|
if (addr >= dev->base() && addr + 4 <= dev->base() + dev->size()) {
|
||||||
|
dev->read_mem_u32(dst, addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::runtime_error("Memory access out of bounds");
|
||||||
|
}
|
||||||
|
|
||||||
|
void VM::write_mem_u8(uint8_t* src, size_t addr) {
|
||||||
|
for (Device* dev : devices) {
|
||||||
|
if (addr >= dev->base() && addr + 1 <= dev->base() + dev->size()) {
|
||||||
|
dev->write_mem_u8(src, addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::runtime_error("Memory access out of bounds");
|
||||||
|
}
|
||||||
|
|
||||||
|
void VM::write_mem_u16(uint16_t* src, size_t addr) {
|
||||||
|
for (Device* dev : devices) {
|
||||||
|
if (addr >= dev->base() && addr + 2 <= dev->base() + dev->size()) {
|
||||||
|
dev->write_mem_u16(src, addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::runtime_error("Memory access out of bounds");
|
||||||
|
}
|
||||||
|
|
||||||
|
void VM::write_mem_u32(uint32_t* src, size_t addr) {
|
||||||
|
for (Device* dev : devices) {
|
||||||
|
if (addr >= dev->base() && addr + 4 <= dev->base() + dev->size()) {
|
||||||
|
dev->write_mem_u32(src, addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,13 +152,13 @@ std::vector<uint8_t> VM::read_memory(size_t start, size_t size) {
|
||||||
|
|
||||||
while (i < end) {
|
while (i < end) {
|
||||||
if (i % 4 == 0 && end - i >= 4) {
|
if (i % 4 == 0 && end - i >= 4) {
|
||||||
read_mem(&res[i - start], i, 4);
|
read_mem_u32((uint32_t*)&res[i - start], i);
|
||||||
i += 4;
|
i += 4;
|
||||||
} else if (i % 2 == 0 && end - i >= 2) {
|
} else if (i % 2 == 0 && end - i >= 2) {
|
||||||
read_mem(&res[i - start], i, 2);
|
read_mem_u16((uint16_t*)&res[i - start], i);
|
||||||
i += 2;
|
i += 2;
|
||||||
} else {
|
} else {
|
||||||
read_mem(&res[i - start], i, 1);
|
read_mem_u8((uint8_t*)&res[i - start], i);
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,9 +179,8 @@ uint32_t VM::getreg(size_t regnum) {
|
||||||
const std::string& VM::get_file_path() { return file_path; }
|
const std::string& VM::get_file_path() { return file_path; }
|
||||||
|
|
||||||
void VM::step() {
|
void VM::step() {
|
||||||
if (pc < PROGRAM_ADDR) throw std::runtime_error("PC out of range");
|
|
||||||
uint32_t instr;
|
uint32_t instr;
|
||||||
read_mem((uint8_t*)&instr, pc, 4);
|
ram.read_mem_u32(&instr, pc);
|
||||||
// std::cout << "pc: " << std::hex << pc << std::dec << "\n";
|
// std::cout << "pc: " << std::hex << pc << std::dec << "\n";
|
||||||
// std::cout << "instr: " << std::hex << instr << "\n";
|
// std::cout << "instr: " << std::hex << instr << "\n";
|
||||||
pc += 4;
|
pc += 4;
|
||||||
|
@ -339,27 +376,27 @@ void VM::step() {
|
||||||
if (funct3 == 0x00) { // LB
|
if (funct3 == 0x00) { // LB
|
||||||
uint32_t addr = registers[rs1] + imm;
|
uint32_t addr = registers[rs1] + imm;
|
||||||
uint8_t val;
|
uint8_t val;
|
||||||
read_mem(&val, addr, 1);
|
read_mem_u8(&val, addr);
|
||||||
setreg(rd, sign_extend(val, 8));
|
setreg(rd, sign_extend(val, 8));
|
||||||
} else if (funct3 == 0x01) { // LH
|
} else if (funct3 == 0x01) { // LH
|
||||||
uint32_t addr = registers[rs1] + imm;
|
uint32_t addr = registers[rs1] + imm;
|
||||||
uint16_t val;
|
uint16_t val;
|
||||||
read_mem((uint8_t*)&val, addr, 2);
|
read_mem_u16(&val, addr);
|
||||||
setreg(rd, sign_extend(val, 16));
|
setreg(rd, sign_extend(val, 16));
|
||||||
} else if (funct3 == 0x2) { // LW
|
} else if (funct3 == 0x2) { // LW
|
||||||
uint32_t addr = registers[rs1] + imm;
|
uint32_t addr = registers[rs1] + imm;
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
read_mem((uint8_t*)&val, addr, 4);
|
read_mem_u32(&val, addr);
|
||||||
setreg(rd, val);
|
setreg(rd, val);
|
||||||
} else if (funct3 == 0x4) { // LBU
|
} else if (funct3 == 0x4) { // LBU
|
||||||
uint32_t addr = registers[rs1] + imm;
|
uint32_t addr = registers[rs1] + imm;
|
||||||
uint8_t val;
|
uint8_t val;
|
||||||
read_mem(&val, addr, 1);
|
read_mem_u8(&val, addr);
|
||||||
setreg(rd, val);
|
setreg(rd, val);
|
||||||
} else if (funct3 == 0x5) { // LHU
|
} else if (funct3 == 0x5) { // LHU
|
||||||
uint32_t addr = registers[rs1] + imm;
|
uint32_t addr = registers[rs1] + imm;
|
||||||
uint16_t val;
|
uint16_t val;
|
||||||
read_mem((uint8_t*)&val, addr, 2);
|
read_mem_u16(&val, addr);
|
||||||
setreg(rd, val);
|
setreg(rd, val);
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("Unknown load instruction");
|
throw std::runtime_error("Unknown load instruction");
|
||||||
|
@ -371,13 +408,13 @@ void VM::step() {
|
||||||
imm = sign_extend(imm, 12); // Sign-extend 12-bit immediate
|
imm = sign_extend(imm, 12); // Sign-extend 12-bit immediate
|
||||||
if (funct3 == 0x0) { // SB
|
if (funct3 == 0x0) { // SB
|
||||||
uint32_t addr = registers[rs1] + imm;
|
uint32_t addr = registers[rs1] + imm;
|
||||||
write_mem((uint8_t*)®isters[rs2], addr, 1);
|
write_mem_u8((uint8_t*)®isters[rs2], addr);
|
||||||
} else if (funct3 == 0x1) { // SH
|
} else if (funct3 == 0x1) { // SH
|
||||||
uint32_t addr = registers[rs1] + imm;
|
uint32_t addr = registers[rs1] + imm;
|
||||||
write_mem((uint8_t*)®isters[rs2], addr, 2);
|
write_mem_u16((uint16_t*)®isters[rs2], addr);
|
||||||
} else if (funct3 == 0x2) { // SW
|
} else if (funct3 == 0x2) { // SW
|
||||||
uint32_t addr = registers[rs1] + imm;
|
uint32_t addr = registers[rs1] + imm;
|
||||||
write_mem((uint8_t*)®isters[rs2], addr, 4);
|
write_mem_u32((uint32_t*)®isters[rs2], addr);
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("Unknown store instruction");
|
throw std::runtime_error("Unknown store instruction");
|
||||||
}
|
}
|
||||||
|
|
64
src/vm.hpp
64
src/vm.hpp
|
@ -23,8 +23,43 @@ class Device {
|
||||||
|
|
||||||
virtual ~Device() = default;
|
virtual ~Device() = default;
|
||||||
|
|
||||||
virtual void write_mem(uint8_t *src, size_t addr, size_t size);
|
template <class T>
|
||||||
virtual void read_mem(uint8_t *dst, size_t addr, size_t size);
|
inline void write_mem(T *src, size_t addr) {
|
||||||
|
if (addr < base_addr || addr + sizeof(T) > base_addr + mem_size) {
|
||||||
|
throw std::runtime_error("Memory access out of bounds");
|
||||||
|
}
|
||||||
|
addr -= base_addr;
|
||||||
|
*(T *)&mem[addr] = *src;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline void read_mem(T *dst, size_t addr) {
|
||||||
|
if (addr < base_addr || addr + sizeof(T) > base_addr + mem_size) {
|
||||||
|
throw std::runtime_error("Memory access out of bounds");
|
||||||
|
}
|
||||||
|
addr -= base_addr;
|
||||||
|
*dst = *(T *)&mem[addr];
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void write_mem_u8(uint8_t *src, size_t addr) {
|
||||||
|
write_mem<uint8_t>(src, addr);
|
||||||
|
}
|
||||||
|
virtual void write_mem_u16(uint16_t *src, size_t addr) {
|
||||||
|
write_mem<uint16_t>(src, addr);
|
||||||
|
}
|
||||||
|
virtual void write_mem_u32(uint32_t *src, size_t addr) {
|
||||||
|
write_mem<uint32_t>(src, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void read_mem_u8(uint8_t *dst, size_t addr) {
|
||||||
|
read_mem<uint8_t>(dst, addr);
|
||||||
|
}
|
||||||
|
virtual void read_mem_u16(uint16_t *dst, size_t addr) {
|
||||||
|
read_mem<uint16_t>(dst, addr);
|
||||||
|
}
|
||||||
|
virtual void read_mem_u32(uint32_t *dst, size_t addr) {
|
||||||
|
read_mem<uint32_t>(dst, addr);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t base() { return base_addr; }
|
uint32_t base() { return base_addr; }
|
||||||
uint32_t size() { return mem_size; }
|
uint32_t size() { return mem_size; }
|
||||||
|
@ -39,8 +74,9 @@ class UART final : public Device {
|
||||||
public:
|
public:
|
||||||
UART() : Device(UART_ADDR, 8) {}
|
UART() : Device(UART_ADDR, 8) {}
|
||||||
|
|
||||||
virtual void write_mem(uint8_t *src, size_t addr, size_t size);
|
virtual void write_mem_u8(uint8_t *src, size_t addr);
|
||||||
virtual void read_mem(uint8_t *dst, size_t addr, size_t size);
|
|
||||||
|
virtual void read_mem_u8(uint8_t *dst, size_t addr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum Registers {
|
enum Registers {
|
||||||
|
@ -61,14 +97,19 @@ class RAM final : public Device {
|
||||||
class Timer final : public Device {
|
class Timer final : public Device {
|
||||||
public:
|
public:
|
||||||
Timer() : Device(MTIME_ADDR, 8) {}
|
Timer() : Device(MTIME_ADDR, 8) {}
|
||||||
virtual void read_mem(uint8_t *dst, size_t addr, size_t size);
|
virtual void read_mem_u8(uint8_t *dst, size_t addr);
|
||||||
void set(uint64_t value) { write_mem((uint8_t *)&value, MTIME_ADDR, 8); }
|
virtual void read_mem_u16(uint16_t *dst, size_t addr);
|
||||||
|
virtual void read_mem_u32(uint32_t *dst, size_t addr);
|
||||||
|
|
||||||
|
void update();
|
||||||
};
|
};
|
||||||
|
|
||||||
class Framebuffer final : public Device {
|
class Framebuffer final : public Device {
|
||||||
public:
|
public:
|
||||||
Framebuffer();
|
Framebuffer();
|
||||||
virtual void write_mem(uint8_t *src, size_t addr, size_t size);
|
virtual void write_mem_u8(uint8_t *src, size_t addr);
|
||||||
|
virtual void write_mem_u16(uint16_t *src, size_t addr);
|
||||||
|
virtual void write_mem_u32(uint32_t *src, size_t addr);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void draw();
|
void draw();
|
||||||
|
@ -83,8 +124,13 @@ class VM {
|
||||||
|
|
||||||
std::vector<uint8_t> read_memory(size_t start, size_t size);
|
std::vector<uint8_t> read_memory(size_t start, size_t size);
|
||||||
|
|
||||||
void read_mem(uint8_t *dst, size_t addr, size_t size);
|
void read_mem_u8(uint8_t *dst, size_t addr);
|
||||||
void write_mem(uint8_t *src, size_t addr, size_t size);
|
void read_mem_u16(uint16_t *dst, size_t addr);
|
||||||
|
void read_mem_u32(uint32_t *dst, size_t addr);
|
||||||
|
|
||||||
|
void write_mem_u8(uint8_t *src, size_t addr);
|
||||||
|
void write_mem_u16(uint16_t *src, size_t addr);
|
||||||
|
void write_mem_u32(uint32_t *src, size_t addr);
|
||||||
|
|
||||||
const std::string &get_file_path();
|
const std::string &get_file_path();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue