feat: add multiboot2 framebuffer and Forth pixel primitives
Co-authored-by: aider (openrouter/moonshotai/kimi-k2.6) <aider@aider.chat>
This commit is contained in:
+151
-20
@@ -2,27 +2,102 @@
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
// VGA text-mode buffer
|
||||
static uint16_t* vga_buffer = (uint16_t*)0xB8000;
|
||||
static int vga_row = 0;
|
||||
static int vga_col = 0;
|
||||
extern const uint8_t font8x8[96][8];
|
||||
|
||||
static void vga_putchar(char c) {
|
||||
if (c == '\n') {
|
||||
vga_col = 0;
|
||||
vga_row++;
|
||||
} else {
|
||||
int idx = vga_row * 80 + vga_col;
|
||||
vga_buffer[idx] = (uint16_t)((0x0F << 8) | (unsigned char)c);
|
||||
vga_col++;
|
||||
if (vga_col >= 80) {
|
||||
vga_col = 0;
|
||||
vga_row++;
|
||||
struct mboot_tag {
|
||||
uint32_t type;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
struct mboot_tag_framebuffer {
|
||||
uint32_t type;
|
||||
uint32_t size;
|
||||
uint64_t framebuffer_addr;
|
||||
uint32_t framebuffer_pitch;
|
||||
uint32_t framebuffer_width;
|
||||
uint32_t framebuffer_height;
|
||||
uint8_t framebuffer_bpp;
|
||||
uint8_t framebuffer_type;
|
||||
uint16_t reserved;
|
||||
};
|
||||
|
||||
static uint64_t fb_addr = 0;
|
||||
static uint32_t fb_pitch = 0;
|
||||
static uint32_t fb_width = 0;
|
||||
static uint32_t fb_height = 0;
|
||||
static uint8_t fb_bpp = 0;
|
||||
static int fb_cols = 0;
|
||||
static int fb_rows = 0;
|
||||
static int fb_col = 0;
|
||||
static int fb_row = 0;
|
||||
|
||||
static void fb_draw_pixel(int x, int y, uint32_t color) {
|
||||
if (x < 0 || y < 0 || (uint32_t)x >= fb_width || (uint32_t)y >= fb_height) return;
|
||||
if (!fb_addr) return;
|
||||
if (fb_bpp == 32) {
|
||||
uint32_t* p = (uint32_t*)(fb_addr + y * fb_pitch + x * 4);
|
||||
*p = color;
|
||||
} else if (fb_bpp == 24) {
|
||||
uint8_t* p = (uint8_t*)(fb_addr + y * fb_pitch + x * 3);
|
||||
p[0] = color & 0xFF;
|
||||
p[1] = (color >> 8) & 0xFF;
|
||||
p[2] = (color >> 16) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
static void fb_scroll(void) {
|
||||
int line_height = 8;
|
||||
uint32_t bytes_per_pixel = (fb_bpp + 7) / 8;
|
||||
uint32_t copy_bytes = fb_width * bytes_per_pixel;
|
||||
for (uint32_t y = 0; y < fb_height - line_height; y++) {
|
||||
uint8_t* dst = (uint8_t*)(fb_addr + y * fb_pitch);
|
||||
uint8_t* src = (uint8_t*)(fb_addr + (y + line_height) * fb_pitch);
|
||||
for (uint32_t i = 0; i < copy_bytes; i++) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
}
|
||||
if (vga_row >= 25) {
|
||||
vga_row = 0;
|
||||
vga_col = 0;
|
||||
for (uint32_t y = fb_height - line_height; y < fb_height; y++) {
|
||||
uint8_t* row = (uint8_t*)(fb_addr + y * fb_pitch);
|
||||
for (uint32_t i = 0; i < copy_bytes; i++) {
|
||||
row[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fb_draw_char(char c) {
|
||||
if (!fb_addr || fb_cols == 0) return;
|
||||
if (c == '\n') {
|
||||
fb_col = 0;
|
||||
fb_row++;
|
||||
} else if (c == '\r') {
|
||||
fb_col = 0;
|
||||
} else if (c == '\b') {
|
||||
if (fb_col > 0) fb_col--;
|
||||
} else {
|
||||
unsigned char ch = (unsigned char)c;
|
||||
if (ch < 32 || ch > 126) ch = '?';
|
||||
const uint8_t* glyph = font8x8[ch - 32];
|
||||
int start_x = fb_col * 8;
|
||||
int start_y = fb_row * 8;
|
||||
for (int dy = 0; dy < 8; dy++) {
|
||||
uint8_t row = glyph[dy];
|
||||
for (int dx = 0; dx < 8; dx++) {
|
||||
if (row & (0x80 >> dx)) {
|
||||
fb_draw_pixel(start_x + dx, start_y + dy, 0xFFFFFF);
|
||||
} else {
|
||||
fb_draw_pixel(start_x + dx, start_y + dy, 0x000000);
|
||||
}
|
||||
}
|
||||
}
|
||||
fb_col++;
|
||||
}
|
||||
if (fb_col >= fb_cols) {
|
||||
fb_col = 0;
|
||||
fb_row++;
|
||||
}
|
||||
if (fb_row >= fb_rows) {
|
||||
fb_scroll();
|
||||
fb_row = fb_rows - 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +224,7 @@ void keyboard_handler(void) {
|
||||
}
|
||||
|
||||
void forth_putchar(char c) {
|
||||
vga_putchar(c);
|
||||
fb_draw_char(c);
|
||||
while ((inb(0x3F8 + 5) & 0x20) == 0) { }
|
||||
outb(0x3F8, (uint8_t)c);
|
||||
}
|
||||
@@ -239,9 +314,32 @@ void forth_printf(const char* fmt, ...) {
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void kernel_main(void) {
|
||||
void kernel_main(uint64_t mboot_ptr) {
|
||||
extern void isr_keyboard(void);
|
||||
|
||||
struct mboot_tag* tag = (struct mboot_tag*)(mboot_ptr + 8);
|
||||
while (tag->type != 0) {
|
||||
if (tag->type == 5) {
|
||||
struct mboot_tag_framebuffer* fb = (struct mboot_tag_framebuffer*)tag;
|
||||
fb_addr = fb->framebuffer_addr;
|
||||
fb_pitch = fb->framebuffer_pitch;
|
||||
fb_width = fb->framebuffer_width;
|
||||
fb_height = fb->framebuffer_height;
|
||||
fb_bpp = fb->framebuffer_bpp;
|
||||
}
|
||||
tag = (struct mboot_tag*)((uint8_t*)tag + ((tag->size + 7) & ~7));
|
||||
}
|
||||
|
||||
if (fb_addr && fb_bpp >= 24) {
|
||||
fb_cols = fb_width / 8;
|
||||
fb_rows = fb_height / 8;
|
||||
for (uint32_t y = 0; y < fb_height; y++) {
|
||||
for (uint32_t x = 0; x < fb_width; x++) {
|
||||
fb_draw_pixel(x, y, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
serial_init();
|
||||
|
||||
idt_set_gate(0x21, (uint64_t)isr_keyboard, 0x08, 0x8E);
|
||||
@@ -260,3 +358,36 @@ void kernel_main(void) {
|
||||
forth_run();
|
||||
forth_panic();
|
||||
}
|
||||
|
||||
void do_fb_addr(Word* w) {
|
||||
(void)w;
|
||||
data_push((int64_t)fb_addr);
|
||||
}
|
||||
|
||||
void do_fb_width(Word* w) {
|
||||
(void)w;
|
||||
data_push((int64_t)fb_width);
|
||||
}
|
||||
|
||||
void do_fb_height(Word* w) {
|
||||
(void)w;
|
||||
data_push((int64_t)fb_height);
|
||||
}
|
||||
|
||||
void do_fb_pitch(Word* w) {
|
||||
(void)w;
|
||||
data_push((int64_t)fb_pitch);
|
||||
}
|
||||
|
||||
void do_fb_bpp(Word* w) {
|
||||
(void)w;
|
||||
data_push((int64_t)fb_bpp);
|
||||
}
|
||||
|
||||
void do_fb_plot(Word* w) {
|
||||
(void)w;
|
||||
int64_t color = data_pop();
|
||||
int64_t y = data_pop();
|
||||
int64_t x = data_pop();
|
||||
fb_draw_pixel((int)x, (int)y, (uint32_t)color);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user