diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/makefile b/makefile new file mode 100755 index 0000000..a942fdb --- /dev/null +++ b/makefile @@ -0,0 +1,57 @@ + +CROSS = aarch64-none-elf- + +CC = $(CROSS)gcc +AS = $(CROSS)as +LD = $(CROSS)ld +OBJCOPY = $(CROSS)objcopy + +CFLAGS = -O2 -ffreestanding -nostdlib -Wall -Wextra +LDFLAGS = -T src/linker.ld + +SRC = src +BUILD = build + +# List all C source files here (update as needed) +SOURCES_C = $(SRC)/renderer.c $(SRC)/font_pack.c $(SRC)/main.c + +# List assembler source files +SOURCES_ASM = $(SRC)/boot.s + +# Object files (one per source file) +OBJ_C = $(patsubst $(SRC)/%.c,$(BUILD)/%.o,$(SOURCES_C)) +OBJ_ASM = $(patsubst $(SRC)/%.s,$(BUILD)/%.o,$(SOURCES_ASM)) + +TARGET_ELF = $(BUILD)/kernel.elf +TARGET_IMG = $(BUILD)/kernel8.img + +.PHONY: all clean run + +all: $(TARGET_IMG) + +# Create build directory if it does not exist +$(BUILD): + mkdir -p $(BUILD) + +# Assemble assembly sources +$(BUILD)/%.o: $(SRC)/%.s | $(BUILD) + $(AS) $< -o $@ + +# Compile C sources +$(BUILD)/%.o: $(SRC)/%.c | $(BUILD) + $(CC) $(CFLAGS) -c $< -o $@ + +# Link all object files into ELF kernel +$(TARGET_ELF): $(OBJ_ASM) $(OBJ_C) + $(LD) $(LDFLAGS) $^ -o $@ + +# Convert ELF to raw binary image +$(TARGET_IMG): $(TARGET_ELF) + $(OBJCOPY) $< -O binary $@ + +clean: + rm -rf $(BUILD) + +# Run QEMU emulator for Raspberry Pi 3 with serial output redirected to terminal +run: $(TARGET_IMG) + sudo qemu-system-aarch64 -M raspi3b -serial stdio -kernel $(TARGET_IMG) diff --git a/src/boot.s b/src/boot.s new file mode 100644 index 0000000..2f39892 --- /dev/null +++ b/src/boot.s @@ -0,0 +1,17 @@ + .section .text + .global _start + +_start: + ldr x0, =stack_top + mov sp, x0 + + bl kernel_main + +1: + b 1b + + .section .bss + .align 3 + .global stack_top +stack_top: + .skip 0x8000 // 32 KB stack diff --git a/src/color.h b/src/color.h new file mode 100644 index 0000000..390bc42 --- /dev/null +++ b/src/color.h @@ -0,0 +1,27 @@ +#ifndef COLOR_H +#define COLOR_H + +// Color format: 0xAABBGGRR (BGRA32 - little endian) + +#define COLOR_BLACK 0xFF000000 +#define COLOR_WHITE 0xFFFFFFFF +#define COLOR_RED 0xFF0000FF +#define COLOR_GREEN 0xFF00FF00 +#define COLOR_BLUE 0xFFFF0000 +#define COLOR_YELLOW 0xFF00FFFF +#define COLOR_CYAN 0xFFFFFF00 +#define COLOR_MAGENTA 0xFFFF00FF +#define COLOR_GRAY 0xFF808080 +#define COLOR_ORANGE 0xFF00A5FF +#define COLOR_BROWN 0xFF2A2AA5 +#define COLOR_PURPLE 0xFF800080 +#define COLOR_PINK 0xFFCBC0FF +#define COLOR_LIME 0xFF00FFBF +#define COLOR_NAVY 0xFF800000 +#define COLOR_TEAL 0xFF808000 +#define COLOR_OLIVE 0xFF008080 + +// For custom BGR colors +#define BGR(r, g, b) (0xFF000000 | ((b) << 16) | ((g) << 8) | (r)) + +#endif // COLOR_H diff --git a/src/font_pack.c b/src/font_pack.c new file mode 100644 index 0000000..4a733a3 --- /dev/null +++ b/src/font_pack.c @@ -0,0 +1,544 @@ +#include "font_pack.h" + +// Letter A: Thickened diagonals and vertical legs +static const uint8_t letter_A_16x16[32] = { + 0b00001111, 0b11100000, // ****** + 0b00001111, 0b11100000, // ****** + 0b00011100, 0b01110000, // *** *** + 0b00011100, 0b01110000, // *** *** + 0b00111000, 0b00011100, // ** *** + 0b00111000, 0b00011100, // ** *** + 0b01110000, 0b00001110, //*** *** + 0b01110000, 0b00001110, //*** *** + 0b11111111, 0b11111111, //************ + 0b11111111, 0b11111111, //************ + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b00000000, 0b00000000, // +}; + +// Letter B: Thickened vertical and horizontal strokes +static const uint8_t letter_B_16x16[32] = { + 0b11111111, 0b11100000, //********* + 0b11111111, 0b11100000, //********* + 0b11100000, 0b00111000, //*** *** + 0b11100000, 0b00111000, //*** *** + 0b11100000, 0b00111000, //*** *** + 0b11100000, 0b00111000, //*** *** + 0b11111111, 0b11100000, //********* + 0b11111111, 0b11100000, //********* + 0b11100000, 0b00111000, //*** *** + 0b11100000, 0b00111000, //*** *** + 0b11100000, 0b00111000, //*** *** + 0b11100000, 0b00111000, //*** *** + 0b11111111, 0b11100000, //********* + 0b11111111, 0b11100000, //********* + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter C: Thickened curves +static const uint8_t letter_C_16x16[32] = { + 0b00001111, 0b11100000, // ****** + 0b00001111, 0b11100000, // ****** + 0b00011100, 0b01110000, // *** *** + 0b00011100, 0b01110000, // *** *** + 0b00111000, 0b00000000, // *** + 0b00111000, 0b00000000, // *** + 0b00111000, 0b00000000, // *** + 0b00111000, 0b00000000, // *** + 0b00111000, 0b00000000, // *** + 0b00111000, 0b00000000, // *** + 0b00011100, 0b01110000, // *** *** + 0b00011100, 0b01110000, // *** *** + 0b00001111, 0b11100000, // ****** + 0b00001111, 0b11100000, // ****** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter D: Thickened vertical and curved strokes +static const uint8_t letter_D_16x16[32] = { + 0b11111111, 0b11000000, //******** + 0b11111111, 0b11000000, //******** + 0b11100000, 0b01100000, //*** ** + 0b11100000, 0b01100000, //*** ** + 0b11100000, 0b00110000, //*** ** + 0b11100000, 0b00110000, //*** ** + 0b11100000, 0b00110000, //*** ** + 0b11100000, 0b00110000, //*** ** + 0b11100000, 0b00110000, //*** ** + 0b11100000, 0b00110000, //*** ** + 0b11100000, 0b01100000, //*** ** + 0b11100000, 0b01100000, //*** ** + 0b11111111, 0b11000000, //******** + 0b11111111, 0b11000000, //******** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter E: Thickened horizontal and vertical strokes +static const uint8_t letter_E_16x16[32] = { + 0b11111111, 0b11111000, //*********** + 0b11111111, 0b11111000, //*********** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11111111, 0b11100000, //********* + 0b11111111, 0b11100000, //********* + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11111111, 0b11111000, //*********** + 0b11111111, 0b11111000, //*********** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter F: Thickened horizontal and vertical strokes +static const uint8_t letter_F_16x16[32] = { + 0b11111111, 0b11111000, //*********** + 0b11111111, 0b11111000, //*********** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11111111, 0b11100000, //********* + 0b11111111, 0b11100000, //********* + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter G: Thickened curves and horizontal bar +static const uint8_t letter_G_16x16[32] = { + 0b00001111, 0b11100000, // ****** + 0b00001111, 0b11100000, // ****** + 0b00011100, 0b01110000, // *** *** + 0b00011100, 0b01110000, // *** *** + 0b00111000, 0b00000000, // *** + 0b00111000, 0b00000000, // *** + 0b00111111, 0b11100000, // *** **** + 0b00111111, 0b11100000, // *** **** + 0b00111000, 0b01110000, // *** *** + 0b00111000, 0b01110000, // *** *** + 0b00011100, 0b01110000, // *** *** + 0b00011100, 0b01110000, // *** *** + 0b00001111, 0b11100000, // ****** + 0b00001111, 0b11100000, // ****** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter H: Thickened vertical and horizontal bars +static const uint8_t letter_H_16x16[32] = { + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11111111, 0b11111111, //************ + 0b11111111, 0b11111111, //************ + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter I: Thickened vertical and horizontal bars +static const uint8_t letter_I_16x16[32] = { + 0b00001111, 0b11110000, // ****** + 0b00001111, 0b11110000, // ****** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00001111, 0b11110000, // ****** + 0b00001111, 0b11110000, // ****** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter J: Thickened vertical and curved strokes +static const uint8_t letter_J_16x16[32] = { + 0b00000000, 0b01111000, // **** + 0b00000000, 0b01111000, // **** + 0b00000000, 0b00111000, // *** + 0b00000000, 0b00111000, // *** + 0b00000000, 0b00111000, // *** + 0b00000000, 0b00111000, // *** + 0b00000000, 0b00111000, // *** + 0b00000000, 0b00111000, // *** + 0b11100000, 0b00111000, //*** *** + 0b11100000, 0b00111000, //*** *** + 0b01111111, 0b11110000, // ******** + 0b01111111, 0b11110000, // ******** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter K: Thickened vertical and diagonal strokes +static const uint8_t letter_K_16x16[32] = { + 0b11100000, 0b01100000, //*** ** + 0b11100000, 0b01100000, //*** ** + 0b11100000, 0b11000000, //*** * + 0b11100000, 0b11000000, //*** * + 0b11100111, 0b00000000, //*** *** + 0b11100111, 0b00000000, //*** *** + 0b11111100, 0b00000000, //**** * + 0b11111100, 0b00000000, //**** * + 0b11111000, 0b00000000, //**** * + 0b11111000, 0b00000000, //**** * + 0b11111100, 0b00000000, //**** * + 0b11111100, 0b00000000, //**** * + 0b11101100, 0b00000000, //*** ** + 0b11101100, 0b00000000, //*** ** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter L: Thickened vertical and horizontal strokes +static const uint8_t letter_L_16x16[32] = { + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11111111, 0b11111000, //*********** + 0b11111111, 0b11111000, //*********** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter M: Thickened vertical and diagonal strokes +static const uint8_t letter_M_16x16[32] = { + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11110000, 0b00011110, //**** **** + 0b11110000, 0b00011110, //**** **** + 0b11111000, 0b00111110, //**** ***** + 0b11111000, 0b00111110, //**** ***** + 0b11101100, 0b01101110, //*** ** *** + 0b11101100, 0b01101110, //*** ** *** + 0b11100110, 0b11001110, //*** *** *** + 0b11100110, 0b11001110, //*** *** *** + 0b11100011, 0b10001110, //*** ** *** + 0b11100011, 0b10001110, //*** ** *** + 0b11100001, 0b00001110, //*** *** + 0b11100001, 0b00001110, //*** *** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter N: Thickened vertical and diagonal strokes +static const uint8_t letter_N_16x16[32] = { + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11110000, 0b00001110, //**** *** + 0b11110000, 0b00001110, //**** *** + 0b11111000, 0b00001110, //**** *** + 0b11111000, 0b00001110, //**** *** + 0b11101100, 0b00001110, //*** * *** + 0b11101100, 0b00001110, //*** * *** + 0b11100110, 0b00001110, //*** * *** + 0b11100110, 0b00001110, //*** * *** + 0b11100011, 0b00001110, //*** * *** + 0b11100011, 0b00001110, //*** * *** + 0b11100001, 0b00001110, //*** *** + 0b11100001, 0b00001110, //*** *** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter O: Thickened curves +static const uint8_t letter_O_16x16[32] = { + 0b00001111, 0b11100000, // ****** + 0b00001111, 0b11100000, // ****** + 0b00011100, 0b01110000, // *** *** + 0b00011100, 0b01110000, // *** *** + 0b00111000, 0b00011100, // *** *** + 0b00111000, 0b00011100, // *** *** + 0b00111000, 0b00011100, // *** *** + 0b00111000, 0b00011100, // *** *** + 0b00111000, 0b00011100, // *** *** + 0b00111000, 0b00011100, // *** *** + 0b00011100, 0b01110000, // *** *** + 0b00011100, 0b01110000, // *** *** + 0b00001111, 0b11100000, // ****** + 0b00001111, 0b11100000, // ****** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter P: Thickened vertical and horizontal strokes +static const uint8_t letter_P_16x16[32] = { + 0b11111111, 0b11100000, //********* + 0b11111111, 0b11100000, //********* + 0b11100000, 0b00111000, //*** *** + 0b11100000, 0b00111000, //*** *** + 0b11100000, 0b00111000, //*** *** + 0b11100000, 0b00111000, //*** *** + 0b11111111, 0b11100000, //********* + 0b11111111, 0b11100000, //********* + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b11100000, 0b00000000, //*** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter Q: Thickened curves and diagonal tail +static const uint8_t letter_Q_16x16[32] = { + 0b00001111, 0b11100000, // ****** + 0b00001111, 0b11100000, // ****** + 0b00011100, 0b01110000, // *** *** + 0b00011100, 0b01110000, // *** *** + 0b00111000, 0b00011100, // *** *** + 0b00111000, 0b00011100, // *** *** + 0b00111000, 0b00011100, // *** *** + 0b00111010, 0b00111000, // *** *** + 0b00111001, 0b01110000, // *** *** + 0b00111000, 0b11100000, // *** *** + 0b00011111, 0b11000000, // **** * + 0b00011111, 0b11000000, // **** * + 0b00001111, 0b11100000, // ****** + 0b00001111, 0b11100000, // ****** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter R: Thickened vertical, horizontal, and diagonal strokes +static const uint8_t letter_R_16x16[32] = { + 0b11111111, 0b11100000, //********* + 0b11111111, 0b11100000, //********* + 0b11100000, 0b00111000, //*** *** + 0b11100000, 0b00111000, //*** *** + 0b11100000, 0b00111000, //*** *** + 0b11100000, 0b00111000, //*** *** + 0b11111111, 0b11100000, //********* + 0b11111111, 0b11100000, //********* + 0b11100000, 0b11000000, //*** * + 0b11100000, 0b11000000, //*** * + 0b11100000, 0b01100000, //*** * + 0b11100000, 0b00110000, //*** * + 0b11100000, 0b00011000, //*** * + 0b11100000, 0b00001100, //*** * + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter S: Thickened curves +static const uint8_t letter_S_16x16[32] = { + 0b00001111, 0b11100000, // ****** + 0b00001111, 0b11100000, // ****** + 0b00011100, 0b01110000, // *** *** + 0b00011100, 0b01110000, // *** *** + 0b00111000, 0b00000000, // *** + 0b00111000, 0b00000000, // *** + 0b00001111, 0b11100000, // ****** + 0b00001111, 0b11100000, // ****** + 0b00000000, 0b01110000, // *** + 0b00000000, 0b01110000, // *** + 0b00000000, 0b01110000, // *** + 0b00111000, 0b00011100, // *** *** + 0b00011111, 0b11100000, // ****** + 0b00011111, 0b11100000, // ****** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter T: Thickened horizontal and vertical strokes +static const uint8_t letter_T_16x16[32] = { + 0b11111111, 0b11111000, //*********** + 0b11111111, 0b11111000, //*********** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter U: Thickened vertical and curved strokes +static const uint8_t letter_U_16x16[32] = { + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b01111111, 0b11111000, // ********* + 0b01111111, 0b11111000, // ********* + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter V: Thickened diagonal strokes +static const uint8_t letter_V_16x16[32] = { + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b01110000, 0b00011100, // ** *** + 0b01110000, 0b00011100, // ** *** + 0b00111000, 0b00111000, // ** *** + 0b00111000, 0b00111000, // ** *** + 0b00011100, 0b01110000, // ** *** + 0b00011100, 0b01110000, // ** *** + 0b00001110, 0b11100000, // ** ** + 0b00001110, 0b11100000, // ** ** + 0b00000111, 0b11000000, // *** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter W: Thickened vertical and diagonal strokes +static const uint8_t letter_W_16x16[32] = { + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b11100111, 0b00011100, //*** *** + 0b11100111, 0b00011100, //*** *** + 0b11101110, 0b00111000, //*** *** + 0b11101110, 0b00111000, //*** *** + 0b11111100, 0b01110000, //**** *** + 0b11111100, 0b01110000, //**** *** + 0b11111000, 0b11100000, //**** *** + 0b11111000, 0b11100000, //**** *** + 0b11111100, 0b11000000, //***** ** + 0b11111100, 0b11000000, //***** ** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter X: Thickened diagonal strokes +static const uint8_t letter_X_16x16[32] = { + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b01110000, 0b00011100, // ** *** + 0b01110000, 0b00011100, // ** *** + 0b00111000, 0b00111000, // ** *** + 0b00111000, 0b00111000, // ** *** + 0b00011100, 0b01110000, // ** *** + 0b00011100, 0b01110000, // ** *** + 0b00001110, 0b11100000, // ** ** + 0b00001110, 0b11100000, // ** ** + 0b00011100, 0b01110000, // ** *** + 0b00011100, 0b01110000, // ** *** + 0b01110000, 0b00011100, // ** *** + 0b01110000, 0b00011100, // ** *** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter Y: Thickened diagonal and vertical strokes +static const uint8_t letter_Y_16x16[32] = { + 0b11100000, 0b00001110, //*** *** + 0b11100000, 0b00001110, //*** *** + 0b01110000, 0b00011100, // ** *** + 0b01110000, 0b00011100, // ** *** + 0b00111000, 0b00111000, // ** *** + 0b00111000, 0b00111000, // ** *** + 0b00011100, 0b01110000, // ** *** + 0b00011100, 0b01110000, // ** *** + 0b00001110, 0b11100000, // ** ** + 0b00001110, 0b11100000, // ** ** + 0b00001110, 0b11100000, // ** ** + 0b00001110, 0b11100000, // ** ** + 0b00001110, 0b11100000, // ** ** + 0b00001110, 0b11100000, // ** ** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + +// Letter Z: Thickened horizontal and diagonal strokes +static const uint8_t letter_Z_16x16[32] = { + 0b11111111, 0b11111000, //*********** + 0b11111111, 0b11111000, //*********** + 0b00000000, 0b11100000, // *** + 0b00000000, 0b11100000, // *** + 0b00000001, 0b11000000, // ** + 0b00000001, 0b11000000, // ** + 0b00000011, 0b10000000, // ** + 0b00000011, 0b10000000, // ** + 0b00000111, 0b00000000, // *** + 0b00000111, 0b00000000, // *** + 0b00001110, 0b00000000, // *** + 0b00001110, 0b00000000, // *** + 0b11111111, 0b11111000, //*********** + 0b11111111, 0b11111000, //*********** + 0b00000000, 0b00000000, // + 0b00000000, 0b00000000, // +}; + + +// Font bitmaps array +static const uint8_t *font_bitmaps_16x16[26] = { + letter_A_16x16, letter_B_16x16, letter_C_16x16, letter_D_16x16, letter_E_16x16, + letter_F_16x16, letter_G_16x16, letter_H_16x16, letter_I_16x16, letter_J_16x16, + letter_K_16x16, letter_L_16x16, letter_M_16x16, letter_N_16x16, letter_O_16x16, + letter_P_16x16, letter_Q_16x16, letter_R_16x16, letter_S_16x16, letter_T_16x16, + letter_U_16x16, letter_V_16x16, letter_W_16x16, letter_X_16x16, letter_Y_16x16, + letter_Z_16x16 +}; + +// Font pack structure +const FontPack basic_font_pack = { + .bitmaps = { + letter_A_16x16, letter_B_16x16, letter_C_16x16, letter_D_16x16, letter_E_16x16, + letter_F_16x16, letter_G_16x16, letter_H_16x16, letter_I_16x16, letter_J_16x16, + letter_K_16x16, letter_L_16x16, letter_M_16x16, letter_N_16x16, letter_O_16x16, + letter_P_16x16, letter_Q_16x16, letter_R_16x16, letter_S_16x16, letter_T_16x16, + letter_U_16x16, letter_V_16x16, letter_W_16x16, letter_X_16x16, letter_Y_16x16, + letter_Z_16x16 + } +}; \ No newline at end of file diff --git a/src/font_pack.h b/src/font_pack.h new file mode 100644 index 0000000..8cafa32 --- /dev/null +++ b/src/font_pack.h @@ -0,0 +1,22 @@ +#ifndef FONT_PACK_H +#define FONT_PACK_H +#include + +#define FONT_WIDTH 16 +#define FONT_HEIGHT 16 +#define FONT_BITMAP_SIZE ((FONT_WIDTH * FONT_HEIGHT) / 8) // 32 bytes per character +static const uint8_t empty_char_16x16[32] = {0}; + +typedef struct { + const uint8_t *bitmaps[26]; // Pointers to each 16x16 bitmap +} FontPack; + +extern const FontPack basic_font_pack; + +static inline const uint8_t *font_get_char_bitmap(const FontPack *pack, char c) { + if (c >= 'A' && c <= 'Z') + return pack->bitmaps[c - 'A']; + return empty_char_16x16; // Or point to empty_char_16x16 +} + +#endif // FONT_PACK_H diff --git a/src/io.h b/src/io.h new file mode 100644 index 0000000..72bdcb6 --- /dev/null +++ b/src/io.h @@ -0,0 +1,64 @@ +#ifndef UART_IO_H +#define UART_IO_H + +#include + +#define UART0_BASE 0x3F201000 +#define UART0_DR (*((volatile uint32_t *)(UART0_BASE + 0x00))) +#define UART0_FR (*((volatile uint32_t *)(UART0_BASE + 0x18))) + +typedef struct UART_IO { + void (*putc)(char c); + void (*puts)(const char* str); + char (*getc)(void); + void (*print_int)(unsigned int value); +} UART_IO; + +// Function implementations + +static void uart_putc(char c) +{ + while (UART0_FR & (1 << 5)) { } // Wait while TXFF is set + UART0_DR = c; +} + +static void uart_puts(const char* str) +{ + while (*str) + uart_putc(*str++); +} + +static char uart_getc(void) +{ + while (UART0_FR & (1 << 4)) { } // Wait while RXFE is set + return (char)(UART0_DR & 0xFF); +} + +static void uart_print_int(unsigned int value) +{ + char buffer[10]; + int i = 0; + + if (value == 0) { + uart_putc('0'); + return; + } + + while (value > 0 && i < 10) { + buffer[i++] = (value % 10) + '0'; + value /= 10; + } + + while (i--) + uart_putc(buffer[i]); +} + +// UART_IO instance with function pointers assigned +static const UART_IO uart_io = { + .putc = uart_putc, + .puts = uart_puts, + .getc = uart_getc, + .print_int = uart_print_int, +}; + +#endif // UART_IO_H diff --git a/src/linker.ld b/src/linker.ld new file mode 100644 index 0000000..93727f6 --- /dev/null +++ b/src/linker.ld @@ -0,0 +1,10 @@ +ENTRY(_start) +SECTIONS { + . = 0x80000; + .text : { *(.text*) } + .rodata : { *(.rodata*) } + .data : { *(.data*) } + .bss : { *(.bss*) } + . = ALIGN(8); + stack_top = . + 0x8000; +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..237a6e9 --- /dev/null +++ b/src/main.c @@ -0,0 +1,70 @@ +#include "renderer.h" +#include "color.h" +#include "font_pack.h" +#include "io.h" + +int kernel_main(void) +{ + uart_io.puts("Initializing renderer...\n"); + + Renderer renderer; + if (!renderer_init(&renderer)) + { + uart_io.puts("Failed to allocate framebuffer.\n"); + while (1) + ; + } + + uart_io.puts("Framebuffer allocated.\n"); + uart_io.puts("Width: "); + uart_io.print_int(renderer.width); + uart_io.puts("\nHeight: "); + uart_io.print_int(renderer.height); + uart_io.putc('\n'); + + RenderObject background = {0, 0, renderer.width, renderer.height, COLOR_RED}; + RenderObject blue_rect = {100, 100, 100, 100, COLOR_BLUE}; + + RenderText text = { + .base = { + .x = 20, + .y = 30, + .color = 0xFFFFFFFF}, + .text = "HELLO MARIO", + .font = &basic_font_pack, + }; + uart_io.puts("Use WASD keys to move the rectangle.\n"); + + // Initial draw + renderer.clear_screen(&renderer, background.color); + renderer.draw_rect(&renderer, &blue_rect); + renderer.draw_text(&renderer, &text); + + while (1) + { + char c = uart_io.getc(); + uart_io.putc(c); + + // Movement + if ((c == 'w' || c == 'W') && blue_rect.y > 0) + blue_rect.y = (blue_rect.y > 10) ? blue_rect.y - 10 : 0; + if ((c == 's' || c == 'S') && (blue_rect.y + blue_rect.height) < renderer.height) + blue_rect.y += 10; + if ((c == 'a' || c == 'A') && blue_rect.x > 0) + blue_rect.x = (blue_rect.x > 10) ? blue_rect.x - 10 : 0; + if ((c == 'd' || c == 'D') && (blue_rect.x + blue_rect.width) < renderer.width) + blue_rect.x += 10; + + // Redraw everything + renderer.clear_screen(&renderer, background.color); + renderer.draw_rect(&renderer, &blue_rect); + renderer.draw_text(&renderer, &text); + + // Print updated position + uart_io.puts("\nRect X: "); + uart_io.print_int(blue_rect.x); + uart_io.puts(" Y: "); + uart_io.print_int(blue_rect.y); + uart_io.putc('\n'); + } +} diff --git a/src/renderer.c b/src/renderer.c new file mode 100644 index 0000000..954e3bb --- /dev/null +++ b/src/renderer.c @@ -0,0 +1,174 @@ +#include "renderer.h" +#include "font_pack.h" + +#define MBOX_CH_PROP 8 +#define MBOX_BASE 0x3F00B880 + +volatile unsigned int __attribute__((aligned(16))) mbox[36]; + +// Small delay loop +static inline void delay(int n) +{ + while (n--) + __asm__ volatile("nop"); +} + +// Mailbox call function for communication with GPU +unsigned int mailbox_call(unsigned int channel) +{ + unsigned int r = ((unsigned int)((unsigned long)&mbox) & ~0xF) | (channel & 0xF); + + // Wait until mailbox not full + while (*(volatile unsigned int *)(MBOX_BASE + 0x18) & 0x80000000) + delay(100); + + // Write the channel combined with mailbox address + *(volatile unsigned int *)(MBOX_BASE + 0x20) = r; + + while (1) + { + // Wait for response + while (*(volatile unsigned int *)(MBOX_BASE + 0x18) & 0x40000000) + delay(100); + + // Check if response is for our message + if (*(volatile unsigned int *)(MBOX_BASE + 0x00) == r) + { + // Return true if response is successful + return mbox[1] == 0x80000000; + } + } +} +void draw_text_impl(Renderer *renderer, RenderText *text_obj) { + if (!renderer || !text_obj || !text_obj->text || !text_obj->font) { + return; // Invalid inputs + } + + unsigned int x0 = text_obj->base.x; + unsigned int y0 = text_obj->base.y; + unsigned int color = text_obj->base.color; + const char *str = text_obj->text; + + // For each character in string + for (const char *p = str; *p != '\0'; p++) { + unsigned char c = (unsigned char)*p; // Ensure unsigned char for safety + + // Get bitmap (guaranteed non-NULL due to empty_char_16x16 fallback) + const uint8_t *bitmap = font_get_char_bitmap(text_obj->font, c); + + // Draw this single character (16x16) + for (unsigned int y = 0; y < FONT_HEIGHT; y++) { + // Read two bytes separately to avoid alignment issues + uint16_t row = ((uint16_t)bitmap[y * 2] << 8) | bitmap[y * 2 + 1]; + for (unsigned int bit = 0; bit < FONT_WIDTH; bit++) { + if (row & (1 << (15 - bit))) { // Check 16 bits, MSB first + unsigned int px = x0 + bit; + unsigned int py = y0 + y; + if (px < renderer->width && py < renderer->height) { + // Assume 32-bit pixels; pitch in bytes + unsigned int *pixel = &renderer->fb[py * (renderer->pitch / 4) + px]; + *pixel = color; + } + } + } + } + // Advance x for next char + x0 += FONT_WIDTH + 1; + } +} +// Initialize the framebuffer via mailbox property channel +bool renderer_init(Renderer *renderer) +{ + mbox[0] = 35 * 4; // Buffer size in bytes + mbox[1] = 0; // Request + + // Set physical width and height + mbox[2] = 0x48003; + mbox[3] = 8; + mbox[4] = 8; + mbox[5] = 640; + mbox[6] = 480; + + // Set virtual width and height + mbox[7] = 0x48004; + mbox[8] = 8; + mbox[9] = 8; + mbox[10] = 640; + mbox[11] = 480; + + // Set depth (bits per pixel) + mbox[12] = 0x48005; + mbox[13] = 4; + mbox[14] = 4; + mbox[15] = 32; + + // Allocate framebuffer + mbox[16] = 0x40001; + mbox[17] = 8; + mbox[18] = 8; + mbox[19] = 16; // alignment + mbox[20] = 0; + + // Get pitch + mbox[21] = 0x40008; + mbox[22] = 4; + mbox[23] = 4; + mbox[24] = 0; + + // End tag + mbox[25] = 0; + + if (!mailbox_call(MBOX_CH_PROP)) + return false; + + renderer->width = mbox[5]; + renderer->height = mbox[6]; + renderer->pitch = mbox[24]; + renderer->fb = (volatile unsigned int *)(mbox[19] & 0x3FFFFFFF); + + renderer->clear_screen = clear_screen_impl; + renderer->draw_rect = draw_rect_impl; + renderer->draw_text = draw_text_impl; + renderer->draw_objects = draw_objects_impl; + + return true; +} +// Render function implementations + +void clear_screen_impl(Renderer *renderer, unsigned int color) +{ + for (unsigned int y = 0; y < renderer->height; y++) + { + for (unsigned int x = 0; x < renderer->width; x++) + { + renderer->fb[y * (renderer->pitch / 4) + x] = color; + } + } +} + +void draw_rect_impl(Renderer *renderer, RenderObject *obj) +{ + unsigned int max_y = obj->y + obj->height; + unsigned int max_x = obj->x + obj->width; + + if (max_y > renderer->height) + max_y = renderer->height; + if (max_x > renderer->width) + max_x = renderer->width; + + for (unsigned int y = obj->y; y < max_y; y++) + { + for (unsigned int x = obj->x; x < max_x; x++) + { + renderer->fb[y * (renderer->pitch / 4) + x] = obj->color; + } + } +} + +void draw_objects_impl(Renderer *renderer, RenderObject *objs[], unsigned int count) +{ + for (unsigned int i = 0; i < count; i++) + { + draw_rect_impl(renderer, objs[i]); + } +} diff --git a/src/renderer.h b/src/renderer.h new file mode 100644 index 0000000..91d1971 --- /dev/null +++ b/src/renderer.h @@ -0,0 +1,59 @@ +#ifndef RENDERER_H +#define RENDERER_H + +#include +#include +#include "font_pack.h" + +typedef struct RenderObject { + unsigned int x, y; + unsigned int width, height; + unsigned int color; +} RenderObject; + +typedef struct RenderText { + RenderObject base; // Position, size, color + const char *text; // String to render + const FontPack *font; // Font used for rendering +} RenderText; + +typedef struct Renderer { + volatile unsigned int *fb; + unsigned int width; + unsigned int height; + unsigned int pitch; + + void (*clear_screen)(struct Renderer *renderer, unsigned int color); + void (*draw_rect)(struct Renderer *renderer, RenderObject *obj); + void (*draw_text)(struct Renderer *renderer, RenderText *text); + void (*draw_objects)(struct Renderer *renderer, RenderObject *objs[], unsigned int count); +} Renderer; + +// ===== Window definition ===== +typedef struct Window { + RenderObject frame; // Outer frame of the window + RenderObject content_area; // Area inside window (excluding titlebar) + RenderText title_bar; // Title bar text + unsigned int background_color; // Background fill color for content + bool visible; // Visibility flag +} Window; + +// Function to initialize a Window +void window_init(Window *win, + unsigned int x, unsigned int y, + unsigned int width, unsigned int height, + const char *title, const FontPack *font, + unsigned int title_color, unsigned int bg_color, + unsigned int text_color); + +// Function to render the Window +void window_draw(Renderer *renderer, Window *win); + +// ===== Renderer functions ===== +bool renderer_init(Renderer *renderer); +void clear_screen_impl(Renderer *renderer, unsigned int color); +void draw_rect_impl(Renderer *renderer, RenderObject *obj); +void draw_text_impl(Renderer *renderer, RenderText *text); +void draw_objects_impl(Renderer *renderer, RenderObject *objs[], unsigned int count); + +#endif // RENDERER_H