seperate out asm and kern

This commit is contained in:
sfja 2025-03-31 19:49:36 +02:00
parent b9a837e3c7
commit 335822afc6
10 changed files with 408 additions and 171 deletions

View File

@ -34,12 +34,22 @@ endif
HEADERS = $(shell find . -name *.h) 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_SOURCES = $(shell find vm/ -name *.c)
VM_OBJECTS = $(patsubst %.c,build/%.o,$(VM_SOURCES)) 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 $@) @mkdir -p $(dir $@)
$(CC) $^ -o $@ $(F_FLAGS) $(OPTIMIZATION) $(L_FLAGS) $(CC) $^ -o $@ $(F_FLAGS) $(OPTIMIZATION) $(L_FLAGS)

View File

@ -1,5 +1,5 @@
#include "asm.h" #include "asm.h"
#include "vm.h" #include "common/op_str.h"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@ -633,6 +633,9 @@ uint16_t assemble_to_binary(uint16_t* out, const Line* lines, size_t lines_size)
printf("done!\n"); printf("done!\n");
} }
free(unres_labels);
free(res_labels);
return ip * 2; return ip * 2;
} }

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "vm.h" #include "common/arch.h"
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>

69
common/arch.h Normal file
View File

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

74
common/op_str.h Normal file
View File

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

View File

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

215
kern/main.c Normal file
View File

@ -0,0 +1,215 @@
#include "asm/asm.h"
#include "common/video_character_display.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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);
}

View File

@ -1,5 +1,7 @@
#include "asm/asm.h"
#include "common/op_str.h"
#include "common/video_character_display.h"
#include "vm.h" #include "vm.h"
#include "vm/asm.h"
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <SDL2/SDL_error.h> #include <SDL2/SDL_error.h>
#include <SDL2/SDL_events.h> #include <SDL2/SDL_events.h>
@ -75,16 +77,6 @@ Interrupt int_queue_pop(InterruptQueue* queue)
return val; 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 { typedef struct {
IODevice io_device; IODevice io_device;
@ -121,7 +113,7 @@ int sdldevice_construct(SdlDevice* device)
SDL_Window* window; SDL_Window* window;
SDL_Renderer* renderer; SDL_Renderer* renderer;
res = SDL_CreateWindowAndRenderer( 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) { if (res != 0) {
fprintf(stderr, fprintf(stderr,
"error: could not create window/renderer: %s\n", "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_Texture* buffer_texture = SDL_CreateTexture(renderer,
SDL_PIXELFORMAT_RGBA32, SDL_PIXELFORMAT_RGBA32,
SDL_TEXTUREACCESS_STREAMING, SDL_TEXTUREACCESS_STREAMING,
width_in_px, vcd_width_in_px,
height_in_px); vcd_height_in_px);
if (buffer_texture == NULL) { if (buffer_texture == NULL) {
fprintf(stderr, fprintf(stderr,
"error: could not create buffer texture: %s\n", "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; return;
} }
for (int ch_y = 0; ch_y < ch_height; ++ch_y) { for (int ch_y = 0; ch_y < vcd_ch_height; ++ch_y) {
for (int ch_x = 0; ch_x < ch_width; ++ch_x) { for (int ch_x = 0; ch_x < vcd_ch_width; ++ch_x) {
bool ch bool ch = charset[value]
= charset[value] >> (ch_y * ch_width + (ch_width - ch_x - 1)) >> (ch_y * vcd_ch_width + (vcd_ch_width - ch_x - 1))
& 1; & 1;
for (int px_y = 0; px_y < px_height; ++px_y) { for (int px_y = 0; px_y < vcd_px_height; ++px_y) {
for (int px_x = 0; px_x < px_width; ++px_x) { 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; + px_x;
int y int y = (offset / vcd_width_in_ch * vcd_ch_height + ch_y)
= (offset / width_in_ch * ch_height + ch_y) * px_height * vcd_px_height
+ px_y; + 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) { 0xff, 0xff, 0xff, 0xff }
: (SDL_Color) { 0x00, 0x00, 0x00, 0xff }; : (SDL_Color) { 0x00, 0x00, 0x00, 0xff };
} }
@ -507,7 +500,7 @@ int main(void)
s_push_r(R2), s_push_r(R2),
s_mov16_r_ml(R2, screen_y), 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_mov16_r_ml(R1, screen_x),
s_add_i(R1, R1, 0x0c00), s_add_i(R1, R1, 0x0c00),
s_add_r(R1, R1, R2), s_add_r(R1, R1, R2),
@ -517,7 +510,7 @@ int main(void)
s_add_i(R1, R1, 1), s_add_i(R1, R1, 1),
s_mov16_ml_r(screen_x, R1), 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_mov16_r_r(R2, Rfl),
s_and_i(R2, R2, 1 << Fl_Eq), s_and_i(R2, R2, 1 << Fl_Eq),
s_jnz_l(R2, put_char_0), s_jnz_l(R2, put_char_0),

72
vm/vm.c
View File

@ -1,4 +1,5 @@
#include "vm.h" #include "vm.h"
#include "common/arch.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@ -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); 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 "---";
}

70
vm/vm.h
View File

@ -2,74 +2,6 @@
#include <stdint.h> #include <stdint.h>
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 struct Drive Drive;
typedef void (*DriveReadFn)(Drive* drive, uint8_t* block, uint16_t i); typedef void (*DriveReadFn)(Drive* drive, uint8_t* block, uint16_t i);
typedef void (*DriveWriteFn)(Drive* drive, const 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); void vm_start(Drive* boot_drive, IODevice* io_device);
const char* op_str(Op op);