Add framebuffer device
This commit is contained in:
parent
9a4c2508f6
commit
44b45c58c6
7 changed files with 107 additions and 9 deletions
|
@ -8,12 +8,15 @@ 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 -fsanitize=address -Wno-c99-designator")
|
||||||
|
|
||||||
|
find_package(SDL2 REQUIRED)
|
||||||
|
|
||||||
add_library(vm_lib)
|
add_library(vm_lib)
|
||||||
target_sources(vm_lib
|
target_sources(vm_lib
|
||||||
PRIVATE
|
PRIVATE
|
||||||
src/vm.cpp
|
src/vm.cpp
|
||||||
src/debug.cpp
|
src/debug.cpp
|
||||||
src/elf.cpp
|
src/elf.cpp
|
||||||
|
src/framebuffer.cpp
|
||||||
|
|
||||||
PUBLIC
|
PUBLIC
|
||||||
FILE_SET HEADERS
|
FILE_SET HEADERS
|
||||||
|
@ -26,5 +29,6 @@ target_sources(vm_lib
|
||||||
|
|
||||||
add_executable(rve src/rve.cpp)
|
add_executable(rve src/rve.cpp)
|
||||||
target_link_libraries(rve vm_lib)
|
target_link_libraries(rve vm_lib)
|
||||||
|
target_link_libraries(rve ${SDL2_LIBRARIES})
|
||||||
|
|
||||||
install(TARGETS rve)
|
install(TARGETS rve)
|
||||||
|
|
|
@ -2,5 +2,5 @@ example: example.c Makefile boot.s linker.ld printf.h printf.c putchar.c
|
||||||
riscv32-none-elf-as -march=rv32i -mabi=ilp32 boot.s -o boot.o
|
riscv32-none-elf-as -march=rv32i -mabi=ilp32 boot.s -o boot.o
|
||||||
riscv32-none-elf-gcc -fno-builtin -fvisibility=hidden -nostdlib -nostartfiles -march=rv32im -mabi=ilp32 -D PRINTF_DISABLE_SUPPORT_FLOAT=1 -D PRINTF_DISABLE_SUPPORT_LONG_LONG=1 -c printf.c -o printf.o -g
|
riscv32-none-elf-gcc -fno-builtin -fvisibility=hidden -nostdlib -nostartfiles -march=rv32im -mabi=ilp32 -D PRINTF_DISABLE_SUPPORT_FLOAT=1 -D PRINTF_DISABLE_SUPPORT_LONG_LONG=1 -c printf.c -o printf.o -g
|
||||||
riscv32-none-elf-gcc -fno-builtin -fvisibility=hidden -nostdlib -nostartfiles -march=rv32im -mabi=ilp32 -c putchar.c -o putchar.o -g
|
riscv32-none-elf-gcc -fno-builtin -fvisibility=hidden -nostdlib -nostartfiles -march=rv32im -mabi=ilp32 -c putchar.c -o putchar.o -g
|
||||||
riscv32-none-elf-gcc -fno-builtin -fvisibility=hidden -nostdlib -nostartfiles -march=rv32im -mabi=ilp32 -c example.c -o example.o -g
|
riscv32-none-elf-gcc -fno-builtin -fvisibility=hidden -nostdlib -nostartfiles -march=rv32im -mabi=ilp32 -c example.c -o example.o -g -O2
|
||||||
riscv32-none-elf-ld boot.o example.o printf.o putchar.o -T linker.ld -o example -g
|
riscv32-none-elf-ld boot.o example.o printf.o putchar.o -T linker.ld -o example -g -O2
|
||||||
|
|
|
@ -4,13 +4,18 @@ typedef unsigned long long uint64_t;
|
||||||
typedef unsigned long uint32_t;
|
typedef unsigned long uint32_t;
|
||||||
#define MTIME_BASE 0x0200BFF8
|
#define MTIME_BASE 0x0200BFF8
|
||||||
|
|
||||||
|
volatile uint32_t* mtime_upper = (uint32_t*)(MTIME_BASE+4);
|
||||||
|
volatile uint32_t* mtime_lower = (uint32_t*)MTIME_BASE;
|
||||||
|
|
||||||
|
#define FRAMEBUFFER_BASE 0x1D385000
|
||||||
|
|
||||||
uint64_t read_mtime_atomic() {
|
uint64_t read_mtime_atomic() {
|
||||||
uint32_t upper1, lower, upper2;
|
uint32_t upper1, lower, upper2;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
upper1 = *(uint32_t*)(MTIME_BASE + 4);
|
upper1 = *mtime_upper;
|
||||||
lower = *(uint32_t*)(MTIME_BASE);
|
lower = *mtime_lower;
|
||||||
upper2 = *(uint32_t*)(MTIME_BASE + 4);
|
upper2 = *mtime_upper;
|
||||||
} while (upper1 != upper2); // Repeat if upper changed during the process
|
} while (upper1 != upper2); // Repeat if upper changed during the process
|
||||||
|
|
||||||
return ((uint64_t)upper1 << 32) | lower;
|
return ((uint64_t)upper1 << 32) | lower;
|
||||||
|
@ -29,11 +34,26 @@ int fib(int n) {
|
||||||
return fib(n-1) + fib(n-2);
|
return fib(n-1) + fib(n-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
for (int i = 0; i< 640; i++) {
|
||||||
|
for (int j = 0; j < 480; j++) {
|
||||||
|
uint32_t color = i*j;
|
||||||
|
uint32_t* addr = (uint32_t*)(FRAMEBUFFER_BASE + ((j*640) + i) *4);
|
||||||
|
*addr = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
int n = 24;
|
|
||||||
uint64_t start = read_mtime_atomic();
|
uint64_t start = read_mtime_atomic();
|
||||||
int res = fib(n);
|
|
||||||
|
draw();
|
||||||
|
|
||||||
uint64_t end = read_mtime_atomic();
|
uint64_t end = read_mtime_atomic();
|
||||||
|
|
||||||
|
int n = 24;
|
||||||
|
int res = fib(n);
|
||||||
|
|
||||||
uint32_t total_msec = timediff_ms(start, end);
|
uint32_t total_msec = timediff_ms(start, end);
|
||||||
|
|
||||||
printf("fib(%d) = %d\n", n, res);
|
printf("fib(%d) = %d\n", n, res);
|
||||||
|
|
1
rve.nix
1
rve.nix
|
@ -18,6 +18,7 @@ pkgs.gcc13Stdenv.mkDerivation rec {
|
||||||
linuxPackages.perf
|
linuxPackages.perf
|
||||||
jq
|
jq
|
||||||
lcov
|
lcov
|
||||||
|
(SDL2.overrideAttrs {waylandSupport= true;})
|
||||||
#riscv-pkgs.buildPackages.gcc
|
#riscv-pkgs.buildPackages.gcc
|
||||||
pkgsCross.riscv32-embedded.buildPackages.gcc
|
pkgsCross.riscv32-embedded.buildPackages.gcc
|
||||||
pkgsCross.riscv32-embedded.buildPackages.binutils
|
pkgsCross.riscv32-embedded.buildPackages.binutils
|
||||||
|
|
61
src/framebuffer.cpp
Normal file
61
src/framebuffer.cpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <SDL2/SDL_render.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "vm.hpp"
|
||||||
|
|
||||||
|
SDL_Window* window = nullptr;
|
||||||
|
SDL_Renderer* renderer = nullptr;
|
||||||
|
SDL_Texture* texture = nullptr;
|
||||||
|
|
||||||
|
Framebuffer::Framebuffer() : Device(FRAMEBUFFER_ADDR, 640 * 480 * 4) {
|
||||||
|
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||||
|
throw std::runtime_error("Failed to initialize SDL");
|
||||||
|
}
|
||||||
|
window = SDL_CreateWindow("rve Framebuffer", SDL_WINDOWPOS_CENTERED,
|
||||||
|
SDL_WINDOWPOS_CENTERED, 640, 480, 0);
|
||||||
|
if (!window) {
|
||||||
|
throw std::runtime_error("Failed to create SDL window");
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
SDL_Surface* surface = SDL_GetWindowSurface(window);
|
||||||
|
if (!surface) {
|
||||||
|
throw std::runtime_error("Failed to create SDL surface");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// renderer = SDL_CreateSoftwareRenderer(surface);
|
||||||
|
|
||||||
|
// renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
|
||||||
|
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE);
|
||||||
|
if (!renderer) {
|
||||||
|
throw std::runtime_error("Failed to create SDL renderer");
|
||||||
|
}
|
||||||
|
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
|
||||||
|
SDL_TEXTUREACCESS_STREAMING, 640, 480);
|
||||||
|
if (!texture) {
|
||||||
|
throw std::runtime_error("Failed to create SDL texture");
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_ShowWindow(window);
|
||||||
|
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Framebuffer::draw() {
|
||||||
|
SDL_UpdateTexture(texture, nullptr, &mem[0],
|
||||||
|
640 * 4); // Update the SDL texture
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
SDL_RenderCopy(renderer, texture, nullptr, nullptr);
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Framebuffer::write_mem(uint8_t* src, size_t addr, size_t size) {
|
||||||
|
Device::write_mem(src, addr, size);
|
||||||
|
|
||||||
|
if (addr + size == base() + (640 * 480) * 4) {
|
||||||
|
// draw to the screen when the last byte is written
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,10 +15,11 @@ inline int32_t sign_extend(int32_t value, int bits) {
|
||||||
|
|
||||||
VM::VM(const std::vector<uint8_t>& memory, const std::string& file_path)
|
VM::VM(const std::vector<uint8_t>& memory, const std::string& file_path)
|
||||||
: ram(memory), pc(PROGRAM_ADDR), file_path(file_path) {
|
: ram(memory), pc(PROGRAM_ADDR), file_path(file_path) {
|
||||||
devices = std::vector<Device*>(3, 0);
|
devices = std::vector<Device*>(4, 0);
|
||||||
devices[0] = &ram;
|
devices[0] = &ram;
|
||||||
devices[1] = &uart;
|
devices[1] = &uart;
|
||||||
devices[2] = &timer;
|
devices[2] = &timer;
|
||||||
|
devices[3] = &framebuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VM::setreg(size_t regnum, uint32_t value) {
|
void VM::setreg(size_t regnum, uint32_t value) {
|
||||||
|
|
13
src/vm.hpp
13
src/vm.hpp
|
@ -12,6 +12,7 @@ const int NUM_REGISTERS = 32; // Standard RISC-V has 32 registers
|
||||||
const uint32_t UART_ADDR = 0x10000000;
|
const uint32_t UART_ADDR = 0x10000000;
|
||||||
const uint32_t PROGRAM_ADDR = 0x80000000;
|
const uint32_t PROGRAM_ADDR = 0x80000000;
|
||||||
const uint32_t MTIME_ADDR = 0x0200BFF8;
|
const uint32_t MTIME_ADDR = 0x0200BFF8;
|
||||||
|
const uint32_t FRAMEBUFFER_ADDR = 0x1D385000;
|
||||||
|
|
||||||
class Device {
|
class Device {
|
||||||
public:
|
public:
|
||||||
|
@ -28,7 +29,7 @@ class Device {
|
||||||
uint32_t base() { return base_addr; }
|
uint32_t base() { return base_addr; }
|
||||||
uint32_t size() { return mem_size; }
|
uint32_t size() { return mem_size; }
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
uint32_t base_addr = 0;
|
uint32_t base_addr = 0;
|
||||||
uint32_t mem_size = 0;
|
uint32_t mem_size = 0;
|
||||||
std::vector<uint8_t> mem;
|
std::vector<uint8_t> mem;
|
||||||
|
@ -64,6 +65,15 @@ class Timer final : public Device {
|
||||||
void set(uint64_t value) { write_mem((uint8_t *)&value, MTIME_ADDR, 8); }
|
void set(uint64_t value) { write_mem((uint8_t *)&value, MTIME_ADDR, 8); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Framebuffer final : public Device {
|
||||||
|
public:
|
||||||
|
Framebuffer();
|
||||||
|
virtual void write_mem(uint8_t *src, size_t addr, size_t size);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void draw();
|
||||||
|
};
|
||||||
|
|
||||||
class VM {
|
class VM {
|
||||||
public:
|
public:
|
||||||
VM(const std::vector<uint8_t> &memory, const std::string &file_path);
|
VM(const std::vector<uint8_t> &memory, const std::string &file_path);
|
||||||
|
@ -90,5 +100,6 @@ class VM {
|
||||||
|
|
||||||
UART uart;
|
UART uart;
|
||||||
Timer timer;
|
Timer timer;
|
||||||
|
Framebuffer framebuffer;
|
||||||
std::vector<Device *> devices;
|
std::vector<Device *> devices;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue