Add framebuffer device

This commit is contained in:
Konstantin Nazarov 2024-12-19 02:30:53 +00:00
parent 9a4c2508f6
commit 44b45c58c6
Signed by: knazarov
GPG key ID: 4CFE0A42FA409C22
7 changed files with 107 additions and 9 deletions

View file

@ -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)

View file

@ -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

View file

@ -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);

View file

@ -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
View 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();
}
}

View file

@ -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) {

View file

@ -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;
}; };