From 335822afc603e7f7dd4fc3d5eac3024f55a13d91 Mon Sep 17 00:00:00 2001 From: sfja Date: Mon, 31 Mar 2025 19:49:36 +0200 Subject: [PATCH] seperate out asm and kern --- Makefile | 14 +- {vm => asm}/asm.c | 5 +- {vm => asm}/asm.h | 2 +- common/arch.h | 69 ++++++++++ common/op_str.h | 74 +++++++++++ common/video_character_display.h | 13 ++ kern/main.c | 215 +++++++++++++++++++++++++++++++ vm/main.c | 45 +++---- vm/vm.c | 72 +---------- vm/vm.h | 70 ---------- 10 files changed, 408 insertions(+), 171 deletions(-) rename {vm => asm}/asm.c (99%) rename {vm => asm}/asm.h (99%) create mode 100644 common/arch.h create mode 100644 common/op_str.h create mode 100644 common/video_character_display.h create mode 100644 kern/main.c diff --git a/Makefile b/Makefile index 6652838..5ec4fa9 100644 --- a/Makefile +++ b/Makefile @@ -34,12 +34,22 @@ endif HEADERS = $(shell find . -name *.h) +ASM_SOURCES = $(shell find asm/ -name *.c) +ASM_OBJECTS = $(patsubst %.c,build/%.o,$(ASM_SOURCES)) + VM_SOURCES = $(shell find vm/ -name *.c) VM_OBJECTS = $(patsubst %.c,build/%.o,$(VM_SOURCES)) -all: bin/vm +KERN_SOURCES = $(shell find kern/ -name *.c) +KERN_OBJECTS = $(patsubst %.c,build/%.o,$(KERN_SOURCES)) -bin/vm: $(VM_OBJECTS) +all: bin/vm bin/build_disk_image + +bin/vm: $(VM_OBJECTS) $(ASM_OBJECTS) + @mkdir -p $(dir $@) + $(CC) $^ -o $@ $(F_FLAGS) $(OPTIMIZATION) $(L_FLAGS) + +bin/build_disk_image: $(KERN_OBJECTS) $(ASM_OBJECTS) @mkdir -p $(dir $@) $(CC) $^ -o $@ $(F_FLAGS) $(OPTIMIZATION) $(L_FLAGS) diff --git a/vm/asm.c b/asm/asm.c similarity index 99% rename from vm/asm.c rename to asm/asm.c index 68c8642..d19c45b 100644 --- a/vm/asm.c +++ b/asm/asm.c @@ -1,5 +1,5 @@ #include "asm.h" -#include "vm.h" +#include "common/op_str.h" #include #include #include @@ -633,6 +633,9 @@ uint16_t assemble_to_binary(uint16_t* out, const Line* lines, size_t lines_size) printf("done!\n"); } + free(unres_labels); + free(res_labels); + return ip * 2; } diff --git a/vm/asm.h b/asm/asm.h similarity index 99% rename from vm/asm.h rename to asm/asm.h index c706b5b..64a999f 100644 --- a/vm/asm.h +++ b/asm/asm.h @@ -1,6 +1,6 @@ #pragma once -#include "vm.h" +#include "common/arch.h" #include #include diff --git a/common/arch.h b/common/arch.h new file mode 100644 index 0000000..32c9f91 --- /dev/null +++ b/common/arch.h @@ -0,0 +1,69 @@ +#pragma once + +typedef enum { + R0 = 0, + R1 = 1, + R2 = 2, + R3 = 3, + R4 = 4, + Rbp = 5, + Rsp = 6, + Rfl = 7, + Rcs = 8, + Rip = 9, +} Reg; + +typedef enum { + Fl_Zero, + Fl_Eq, + Fl_Be, + Fl_Lt, + Fl_Err, + Fl_Int, + Fl_Vcd, +} Flag; + +typedef enum { + Op_Nop, + Op_Hlt, + Op_Jmp, + Op_Jnz, + Op_Test, + Op_Cmp, + Op_Mov8, + Op_Mov16, + Op_In, + Op_Out, + Op_Call, + Op_Ret, + Op_Lit, + Op_Int, + Op_Or, + Op_Xor, + Op_And, + Op_Shl, + Op_RShl, + Op_Shr, + Op_RShr, + Op_Add, + Op_Sub, + Op_RSub, + Op_Mul, + Op_IMul, + Op_Div, + Op_IDiv, + Op_RDiv, + Op_RIDiv, + Op_Mod, + Op_RMod, +} Op; + +typedef enum { + Int_DiskRead = 0, + Int_DiskWrite = 1, + Int_Key = 32, +} VM_Int; + +typedef enum { + Device_Keyboard, +} VM_Device; diff --git a/common/op_str.h b/common/op_str.h new file mode 100644 index 0000000..a22dde3 --- /dev/null +++ b/common/op_str.h @@ -0,0 +1,74 @@ +#pragma once + +#include "arch.h" + +static inline const char* op_str(Op op) +{ + switch (op) { + case Op_Nop: + return "nop"; + case Op_Hlt: + return "hlt"; + case Op_Jmp: + return "jmp"; + case Op_Jnz: + return "jnz"; + case Op_Test: + return "test"; + case Op_Cmp: + return "cmp"; + case Op_Mov8: + return "mov8"; + case Op_Mov16: + return "mov16"; + case Op_In: + return "in"; + case Op_Out: + return "out"; + case Op_Call: + return "call"; + case Op_Ret: + return "ret"; + case Op_Lit: + return "lit"; + case Op_Int: + return "int"; + case Op_Or: + return "or"; + case Op_Xor: + return "xor"; + case Op_And: + return "and"; + case Op_Shl: + return "shl"; + case Op_RShl: + return "rshl"; + case Op_Shr: + return "shr"; + case Op_RShr: + return "rshr"; + case Op_Add: + return "add"; + case Op_Sub: + return "sub"; + case Op_RSub: + return "rsub"; + case Op_Mul: + return "mul"; + case Op_IMul: + return "imul"; + case Op_Div: + return "div"; + case Op_IDiv: + return "idiv"; + case Op_RDiv: + return "rdiv"; + case Op_RIDiv: + return "ridiv"; + case Op_Mod: + return "mod"; + case Op_RMod: + return "rmod"; + } + return "---"; +} diff --git a/common/video_character_display.h b/common/video_character_display.h new file mode 100644 index 0000000..bf9059b --- /dev/null +++ b/common/video_character_display.h @@ -0,0 +1,13 @@ +#pragma once + +#define vcd_ch_width 8 +#define vcd_ch_height 8 +static const int vcd_width_in_ch = 40; +static const int vcd_height_in_ch = 12; + +static const int vcd_px_width = 4; +static const int vcd_px_height = 8; +static const int vcd_width_in_px + = vcd_width_in_ch * vcd_ch_width * vcd_px_width; +static const int vcd_height_in_px + = vcd_height_in_ch * vcd_ch_height * vcd_px_height; diff --git a/kern/main.c b/kern/main.c new file mode 100644 index 0000000..e0eb8bc --- /dev/null +++ b/kern/main.c @@ -0,0 +1,215 @@ +#include "asm/asm.h" +#include "common/video_character_display.h" +#include +#include +#include +#include + +const size_t block_size = 512; +const size_t block_amount = 32; + +void write_program(FILE* fp); + +int main(void) +{ + FILE* fp = fopen("build/image", "wb"); + if (!fp) { + fprintf( + stderr, "error: could not open build/image: %s\n", strerror(errno)); + return -1; + } + + printf("clearing disk...\n"); + uint8_t* data = calloc(block_size, 1); + for (size_t i = 0; i < block_amount; ++i) { + fwrite(data, 1, block_size, fp); + } + free(data); + fseek(fp, 0, SEEK_SET); + printf("done!\n"); + + write_program(fp); + + fclose(fp); +} + +void write_program(FILE* fp) +{ + int label_ids = 0; + + int main_loop = label_ids++; + int interrupt_table = label_ids++; + int keyboard_interrupt = label_ids++; + int keyboard_interrupt_0 = label_ids++; + int keyboard_interrupt_1 = label_ids++; + int keyboard_interrupt_2 = label_ids++; + int keyboard_interrupt_3 = label_ids++; + int keyboard_interrupt_4 = label_ids++; + int put_char = label_ids++; + int put_char_0 = label_ids++; + int put_char_1 = label_ids++; + int screen_x = label_ids++; + int screen_y = label_ids++; + +#define L(LABEL) s_label(LABEL) + + Line program_asm[] = { + // clang-format off + + // rsp points *at* the top element + s_mov16_r_i(Rbp, 2048), + s_mov16_r_i(Rsp, 2048 - 2), + + s_lit_l(interrupt_table), + s_or_i(Rfl, Rfl, 1 << Fl_Int), + + s_or_i(Rfl, Rfl, 1 << Fl_Vcd), + + s_mov16_r_i(R0, 512), + s_mov16_r_i(R1, 1), + s_int(Int_DiskRead), + + L(main_loop), + s_hlt(), + s_jmp_l(main_loop), + + L(interrupt_table), + // size + s_data_i(1), + s_data_l(keyboard_interrupt), + s_nop(), + + L(keyboard_interrupt), + s_and_i(Rfl, Rfl, (uint16_t)~(1 << Fl_Int)), + s_push_r(Rbp), + s_mov16_r_r(Rbp, Rsp), + s_push_r(R0), + s_push_r(R1), + s_push_r(R2), + s_push_r(R3), + + s_in_i(R0, Device_Keyboard), + + s_cmp_i(R0, 44), + s_mov16_r_r(R1, Rfl), + s_and_i(R1, R1, 1 << Fl_Eq), + s_jnz_l(R1, keyboard_interrupt_0), + + s_cmp_i(R0, 42), + s_mov16_r_r(R1, Rfl), + s_and_i(R1, R1, 1 << Fl_Eq), + s_jnz_l(R1, keyboard_interrupt_1), + + s_cmp_i(R0, 40), + s_mov16_r_r(R1, Rfl), + s_and_i(R1, R1, 1 << Fl_Eq), + s_jnz_l(R1, keyboard_interrupt_2), + + s_jmp_l(keyboard_interrupt_3), + + L(keyboard_interrupt_0), + s_mov16_r_i(R0, ' '), + s_call_l(put_char), + s_jmp_l(keyboard_interrupt_4), + + L(keyboard_interrupt_1), + s_mov16_r_ml(R1, screen_x), + s_cmp_i(R1, 0), + s_mov16_r_r(R2, Rfl), + s_and_i(R2, R2, 1 << Fl_Eq), + s_jnz_l(R2, keyboard_interrupt_4), + s_sub_i(R1, R1, 1), + s_mov16_ml_r(screen_x, R1), + s_mov16_r_i(R0, ' '), + s_call_l(put_char), + s_mov16_r_ml(R1, screen_x), + s_sub_i(R1, R1, 1), + s_mov16_ml_r(screen_x, R1), + s_jmp_l(keyboard_interrupt_4), + + L(keyboard_interrupt_2), + s_mov16_r_ml(R1, screen_y), + s_add_i(R1, R1, 1), + s_mov16_ml_r(screen_y, R1), + s_mov16_r_i(R1, 0), + s_mov16_ml_r(screen_x, R1), + s_jmp_l(keyboard_interrupt_4), + + L(keyboard_interrupt_3), + s_add_i(R0, R0, 'A' - 4), + s_call_l(put_char), + s_jmp_l(keyboard_interrupt_4), + + L(keyboard_interrupt_4), + + s_pop_r(R3), + s_pop_r(R2), + s_pop_r(R1), + s_pop_r(R0), + s_mov16_r_r(Rsp, Rbp), + s_pop_r(Rbp), + s_or_i(Rfl, Rfl, 1 << Fl_Int), + s_iret(), + + L(put_char), + s_push_r(Rbp), + s_mov16_r_r(Rbp, Rsp), + s_push_r(R1), + s_push_r(R2), + + s_mov16_r_ml(R2, screen_y), + s_mul_i(R2, R2, vcd_width_in_ch), + s_mov16_r_ml(R1, screen_x), + s_add_i(R1, R1, 0x0c00), + s_add_r(R1, R1, R2), + s_mov8_mr_r(R1, R0), + + s_mov16_r_ml(R1, screen_x), + s_add_i(R1, R1, 1), + s_mov16_ml_r(screen_x, R1), + + s_cmp_i(R1, vcd_width_in_ch), + s_mov16_r_r(R2, Rfl), + s_and_i(R2, R2, 1 << Fl_Eq), + s_jnz_l(R2, put_char_0), + s_jmp_l(put_char_1), + + L(put_char_0), + s_mov16_r_ml(R1, screen_y), + s_add_i(R1, R1, 1), + s_mov16_ml_r(screen_y, R1), + s_mov16_r_i(R1, 0), + s_mov16_ml_r(screen_x, R1), + + L(put_char_1), + + s_pop_r(R1), + s_pop_r(R2), + s_mov16_r_r(Rsp, Rbp), + s_pop_r(Rbp), + s_ret(), + + L(screen_x), + s_data_i(0), + L(screen_y), + s_data_i(0), + + // clang-format on + }; + + size_t program_asm_size = sizeof(program_asm) / sizeof(program_asm[0]); + + uint16_t* program = calloc(512 * 2, sizeof(uint16_t)); + + printf("assembling program...\n"); + uint16_t program_size + = assemble_to_binary(program, program_asm, program_asm_size); + printf("done!\n"); + printf("program size = %d\n", program_size); + + printf("writing program to disk...\n"); + fwrite(program, sizeof(uint16_t), program_size, fp); + printf("done!\n"); + + free(program); +} diff --git a/vm/main.c b/vm/main.c index 9fb8136..822d784 100644 --- a/vm/main.c +++ b/vm/main.c @@ -1,5 +1,7 @@ +#include "asm/asm.h" +#include "common/op_str.h" +#include "common/video_character_display.h" #include "vm.h" -#include "vm/asm.h" #include #include #include @@ -75,16 +77,6 @@ Interrupt int_queue_pop(InterruptQueue* queue) return val; } -#define ch_width 8 -#define ch_height 8 -static const int width_in_ch = 40; -static const int height_in_ch = 12; - -static const int px_width = 4; -static const int px_height = 8; -static const int width_in_px = width_in_ch * ch_width * px_width; -static const int height_in_px = height_in_ch * ch_height * px_height; - typedef struct { IODevice io_device; @@ -121,7 +113,7 @@ int sdldevice_construct(SdlDevice* device) SDL_Window* window; SDL_Renderer* renderer; res = SDL_CreateWindowAndRenderer( - width_in_px, height_in_px, 0, &window, &renderer); + vcd_width_in_px, vcd_height_in_px, 0, &window, &renderer); if (res != 0) { fprintf(stderr, "error: could not create window/renderer: %s\n", @@ -132,8 +124,8 @@ int sdldevice_construct(SdlDevice* device) SDL_Texture* buffer_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STREAMING, - width_in_px, - height_in_px); + vcd_width_in_px, + vcd_height_in_px); if (buffer_texture == NULL) { fprintf(stderr, "error: could not create buffer texture: %s\n", @@ -205,22 +197,23 @@ void sdldevice_set_char(IODevice* io_device, uint16_t offset, uint8_t value) return; } - for (int ch_y = 0; ch_y < ch_height; ++ch_y) { - for (int ch_x = 0; ch_x < ch_width; ++ch_x) { - bool ch - = charset[value] >> (ch_y * ch_width + (ch_width - ch_x - 1)) + for (int ch_y = 0; ch_y < vcd_ch_height; ++ch_y) { + for (int ch_x = 0; ch_x < vcd_ch_width; ++ch_x) { + bool ch = charset[value] + >> (ch_y * vcd_ch_width + (vcd_ch_width - ch_x - 1)) & 1; - for (int px_y = 0; px_y < px_height; ++px_y) { - for (int px_x = 0; px_x < px_width; ++px_x) { + for (int px_y = 0; px_y < vcd_px_height; ++px_y) { + for (int px_x = 0; px_x < vcd_px_width; ++px_x) { - int x = (offset % width_in_ch * ch_width + ch_x) * px_width + int x = (offset % vcd_width_in_ch * vcd_ch_width + ch_x) + * vcd_px_width + px_x; - int y - = (offset / width_in_ch * ch_height + ch_y) * px_height + int y = (offset / vcd_width_in_ch * vcd_ch_height + ch_y) + * vcd_px_height + px_y; - buffer[y * width_in_px + x] = ch + buffer[y * vcd_width_in_px + x] = ch ? (SDL_Color) { 0xff, 0xff, 0xff, 0xff } : (SDL_Color) { 0x00, 0x00, 0x00, 0xff }; } @@ -507,7 +500,7 @@ int main(void) s_push_r(R2), s_mov16_r_ml(R2, screen_y), - s_mul_i(R2, R2, width_in_ch), + s_mul_i(R2, R2, vcd_width_in_ch), s_mov16_r_ml(R1, screen_x), s_add_i(R1, R1, 0x0c00), s_add_r(R1, R1, R2), @@ -517,7 +510,7 @@ int main(void) s_add_i(R1, R1, 1), s_mov16_ml_r(screen_x, R1), - s_cmp_i(R1, width_in_ch), + s_cmp_i(R1, vcd_width_in_ch), s_mov16_r_r(R2, Rfl), s_and_i(R2, R2, 1 << Fl_Eq), s_jnz_l(R2, put_char_0), diff --git a/vm/vm.c b/vm/vm.c index 67822ec..7812399 100644 --- a/vm/vm.c +++ b/vm/vm.c @@ -1,4 +1,5 @@ #include "vm.h" +#include "common/arch.h" #include #include #include @@ -552,74 +553,3 @@ static inline uint16_t ins_op2_or_imm(VM* vm, uint16_t ins) { return ins_reg_val_or_imm(vm, ins, 6, 7, 0x7); } - -const char* op_str(Op op) -{ - switch (op) { - case Op_Nop: - return "nop"; - case Op_Hlt: - return "hlt"; - case Op_Jmp: - return "jmp"; - case Op_Jnz: - return "jnz"; - case Op_Test: - return "test"; - case Op_Cmp: - return "cmp"; - case Op_Mov8: - return "mov8"; - case Op_Mov16: - return "mov16"; - case Op_In: - return "in"; - case Op_Out: - return "out"; - case Op_Call: - return "call"; - case Op_Ret: - return "ret"; - case Op_Lit: - return "lit"; - case Op_Int: - return "int"; - case Op_Or: - return "or"; - case Op_Xor: - return "xor"; - case Op_And: - return "and"; - case Op_Shl: - return "shl"; - case Op_RShl: - return "rshl"; - case Op_Shr: - return "shr"; - case Op_RShr: - return "rshr"; - case Op_Add: - return "add"; - case Op_Sub: - return "sub"; - case Op_RSub: - return "rsub"; - case Op_Mul: - return "mul"; - case Op_IMul: - return "imul"; - case Op_Div: - return "div"; - case Op_IDiv: - return "idiv"; - case Op_RDiv: - return "rdiv"; - case Op_RIDiv: - return "ridiv"; - case Op_Mod: - return "mod"; - case Op_RMod: - return "rmod"; - } - return "---"; -} diff --git a/vm/vm.h b/vm/vm.h index 79a4904..fd89e1e 100644 --- a/vm/vm.h +++ b/vm/vm.h @@ -2,74 +2,6 @@ #include -typedef enum { - R0 = 0, - R1 = 1, - R2 = 2, - R3 = 3, - R4 = 4, - Rbp = 5, - Rsp = 6, - Rfl = 7, - Rcs = 8, - Rip = 9, -} Reg; - -typedef enum { - Fl_Zero, - Fl_Eq, - Fl_Be, - Fl_Lt, - Fl_Err, - Fl_Int, - Fl_Vcd, -} Flag; - -typedef enum { - Op_Nop, - Op_Hlt, - Op_Jmp, - Op_Jnz, - Op_Test, - Op_Cmp, - Op_Mov8, - Op_Mov16, - Op_In, - Op_Out, - Op_Call, - Op_Ret, - Op_Lit, - Op_Int, - Op_Or, - Op_Xor, - Op_And, - Op_Shl, - Op_RShl, - Op_Shr, - Op_RShr, - Op_Add, - Op_Sub, - Op_RSub, - Op_Mul, - Op_IMul, - Op_Div, - Op_IDiv, - Op_RDiv, - Op_RIDiv, - Op_Mod, - Op_RMod, -} Op; - -typedef enum { - Int_DiskRead = 0, - Int_DiskWrite = 1, - Int_Key = 32, -} VM_Int; - -typedef enum { - Device_Keyboard, -} VM_Device; - typedef struct Drive Drive; typedef void (*DriveReadFn)(Drive* drive, uint8_t* block, uint16_t i); typedef void (*DriveWriteFn)(Drive* drive, const uint8_t* block, uint16_t i); @@ -114,5 +46,3 @@ struct IODevice { }; void vm_start(Drive* boot_drive, IODevice* io_device); - -const char* op_str(Op op);