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")
|
||||
|
||||
find_package(SDL2 REQUIRED)
|
||||
|
||||
add_library(vm_lib)
|
||||
target_sources(vm_lib
|
||||
PRIVATE
|
||||
src/vm.cpp
|
||||
src/debug.cpp
|
||||
src/elf.cpp
|
||||
src/framebuffer.cpp
|
||||
|
||||
PUBLIC
|
||||
FILE_SET HEADERS
|
||||
|
@ -26,5 +29,6 @@ target_sources(vm_lib
|
|||
|
||||
add_executable(rve src/rve.cpp)
|
||||
target_link_libraries(rve vm_lib)
|
||||
target_link_libraries(rve ${SDL2_LIBRARIES})
|
||||
|
||||
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-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 example.c -o example.o -g
|
||||
riscv32-none-elf-ld boot.o example.o printf.o putchar.o -T linker.ld -o example -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 -O2
|
||||
|
|
|
@ -4,13 +4,18 @@ typedef unsigned long long uint64_t;
|
|||
typedef unsigned long uint32_t;
|
||||
#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() {
|
||||
uint32_t upper1, lower, upper2;
|
||||
|
||||
do {
|
||||
upper1 = *(uint32_t*)(MTIME_BASE + 4);
|
||||
lower = *(uint32_t*)(MTIME_BASE);
|
||||
upper2 = *(uint32_t*)(MTIME_BASE + 4);
|
||||
upper1 = *mtime_upper;
|
||||
lower = *mtime_lower;
|
||||
upper2 = *mtime_upper;
|
||||
} while (upper1 != upper2); // Repeat if upper changed during the process
|
||||
|
||||
return ((uint64_t)upper1 << 32) | lower;
|
||||
|
@ -29,11 +34,26 @@ int fib(int n) {
|
|||
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 n = 24;
|
||||
uint64_t start = read_mtime_atomic();
|
||||
int res = fib(n);
|
||||
|
||||
draw();
|
||||
|
||||
uint64_t end = read_mtime_atomic();
|
||||
|
||||
int n = 24;
|
||||
int res = fib(n);
|
||||
|
||||
uint32_t total_msec = timediff_ms(start, end);
|
||||
|
||||
printf("fib(%d) = %d\n", n, res);
|
||||
|
|
1
rve.nix
1
rve.nix
|
@ -18,6 +18,7 @@ pkgs.gcc13Stdenv.mkDerivation rec {
|
|||
linuxPackages.perf
|
||||
jq
|
||||
lcov
|
||||
(SDL2.overrideAttrs {waylandSupport= true;})
|
||||
#riscv-pkgs.buildPackages.gcc
|
||||
pkgsCross.riscv32-embedded.buildPackages.gcc
|
||||
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)
|
||||
: 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[1] = &uart;
|
||||
devices[2] = &timer;
|
||||
devices[3] = &framebuffer;
|
||||
}
|
||||
|
||||
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 PROGRAM_ADDR = 0x80000000;
|
||||
const uint32_t MTIME_ADDR = 0x0200BFF8;
|
||||
const uint32_t FRAMEBUFFER_ADDR = 0x1D385000;
|
||||
|
||||
class Device {
|
||||
public:
|
||||
|
@ -28,7 +29,7 @@ class Device {
|
|||
uint32_t base() { return base_addr; }
|
||||
uint32_t size() { return mem_size; }
|
||||
|
||||
private:
|
||||
protected:
|
||||
uint32_t base_addr = 0;
|
||||
uint32_t mem_size = 0;
|
||||
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); }
|
||||
};
|
||||
|
||||
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 {
|
||||
public:
|
||||
VM(const std::vector<uint8_t> &memory, const std::string &file_path);
|
||||
|
@ -90,5 +100,6 @@ class VM {
|
|||
|
||||
UART uart;
|
||||
Timer timer;
|
||||
Framebuffer framebuffer;
|
||||
std::vector<Device *> devices;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue