read from disk

This commit is contained in:
sfja 2025-03-31 16:20:10 +02:00
parent 42246deb35
commit bcd1500f9c
7 changed files with 112 additions and 39 deletions

View File

@ -8,6 +8,7 @@ C_FLAGS = \
-Wall -Wextra -Wpedantic -Wconversion \
-pedantic -pedantic-errors \
-Wno-unused-variable \
-Wno-unused-parameter \
-I. \
L_FLAGS = -pthread

View File

@ -7,7 +7,7 @@
-pedantic
-pedantic-errors
-Wno-unused-variable
# -Wno-unused-parameter
-Wno-unused-parameter
# -Wno-unused-function
-I.

View File

@ -163,6 +163,13 @@ Line s_lit_l(int op1_label)
.op1 = (Ex) { .label = op1_label },
};
}
Line s_int(uint8_t int_id)
{
return (Line) {
.ty = LineTy_Int,
.op1 = (Ex) { .imm = int_id },
};
}
Line s_iret(void)
{
return (Line) { .ty = LineTy_IRet };
@ -456,6 +463,14 @@ void assemble_to_binary(uint16_t* out, const Line* lines, size_t lines_size)
ADD_LABEL(op1);
break;
}
case LineTy_Int: {
uint16_t int_id = line->op1.imm & 0xff;
uint32_t ins = Op_Int;
ins |= (uint16_t)(int_id << 8);
out[ip++] = (uint16_t)ins;
break;
}
case LineTy_IRet: {
out[ip++] = Op_IRet;
break;

View File

@ -26,6 +26,7 @@ typedef enum {
LineTy_In_Imm,
LineTy_Lit_Imm,
LineTy_Lit_Label,
LineTy_Int,
LineTy_IRet,
LineTy_Or_Imm,
LineTy_And_Imm,
@ -72,6 +73,7 @@ Line s_mov16_ml_r(int dst_label, Reg op2_reg);
Line s_in_i(Reg dst_reg, uint16_t op1_imm);
Line s_lit_i(uint16_t op1_imm);
Line s_lit_l(int op1_label);
Line s_int(uint8_t int_id);
Line s_iret(void);
Line s_or_i(Reg dst_reg, Reg op1_reg, uint16_t op2_imm);
Line s_and_i(Reg dst_reg, Reg op1_reg, uint16_t op2_imm);

View File

@ -400,18 +400,20 @@ int main(void)
Line program_asm[] = {
// clang-format off
s_nop(),
// set video character display flag
s_or_i(Rfl, Rfl, 1 << Fl_Vcd),
// setup stack
s_mov16_r_i(Rbp, 2048),
// rsp points *at* the top element
s_mov16_r_i(Rbp, 2048),
s_mov16_r_i(Rsp, 2048 - 2),
// load interrupt table
s_lit_l(interrupt_table),
// set interrupt flag
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),
@ -430,7 +432,7 @@ int main(void)
s_push_r(R2),
// read keyboard port
s_in_i(R0, 0),
s_in_i(R0, Device_Keyboard),
s_add_i(R0, R0, 'A' - 4),
s_cmp_i(R0, 105),
@ -467,7 +469,7 @@ int main(void)
size_t program_asm_size = sizeof(program_asm) / sizeof(program_asm[0]);
uint16_t* program = calloc(512, sizeof(uint16_t));
uint16_t* program = calloc(512 * 2, sizeof(uint16_t));
assemble_to_binary(program, program_asm, program_asm_size);
// dump_program(program);
@ -485,6 +487,7 @@ int main(void)
vm_start(&drive.drive, &io_device.io_device);
free(program);
sdldevice_destroy(&io_device);
}

102
vm/vm.c
View File

@ -17,7 +17,12 @@ typedef struct {
} VM;
static inline void run_arithm_ins(VM* vm, uint16_t ins);
static inline int jump_to_interrupt(VM* vm, uint16_t int_id);
static inline void handle_device_read(VM* vm, Reg dst_reg, uint16_t device_id);
static inline void handle_device_write(
VM* vm, uint16_t op1, uint16_t device_id);
static inline int handle_interrupt(VM* vm, uint8_t int_id);
static inline int jump_to_interrupt_handler(VM* vm, uint8_t int_id);
static inline void interrupt_return(VM* vm);
static inline void maybe_update_vcd(VM* vm, uint16_t addr);
static inline uint16_t eat_uint16(VM* vm);
static inline uint16_t read_seg_uint16(VM* vm, uint16_t ptr);
@ -57,8 +62,9 @@ void vm_start(Drive* boot_drive, IODevice* io_device)
uint16_t* rfl = &vm->regs[Rfl];
uint16_t* rcs = &vm->regs[Rcs];
const uint16_t bootloader_size = 512;
const uint16_t block_size = vm->boot_drive->block_size;
for (uint16_t i = 0; i * block_size < 512; ++i) {
for (uint16_t i = 0; i * block_size < bootloader_size; ++i) {
vm->boot_drive->read(vm->boot_drive, &vm->mem[i * block_size], i);
}
@ -209,29 +215,13 @@ void vm_start(Drive* boot_drive, IODevice* io_device)
case Op_In: {
Reg dst_reg = ins_dst_reg(ins);
uint16_t device_id = ins_op1_or_imm(vm, ins);
switch (device_id) {
case 0:
vm->regs[dst_reg] = vm->keyboard_port_input;
break;
default:
fprintf(
stderr, "warning: no input device %d\n", device_id);
break;
}
handle_device_read(vm, dst_reg, device_id);
break;
}
case Op_Out: {
uint16_t op1 = ins_op2(vm, ins);
uint16_t device_id = ins_op1_or_imm(vm, ins);
switch (device_id) {
default:
fprintf(stderr,
"warning: no output device %d\n",
device_id);
break;
}
handle_device_write(vm, op1, device_id);
break;
}
case Op_Lit: {
@ -242,17 +232,14 @@ void vm_start(Drive* boot_drive, IODevice* io_device)
case Op_Int: {
uint8_t int_id = (uint8_t)(ins >> 8 & 0xff);
int res = jump_to_interrupt(vm, int_id);
int res = handle_interrupt(vm, int_id);
if (res != 0) {
goto halt_execution;
}
break;
}
case Op_IRet: {
*rip = *(uint16_t*)&vm->mem[*rsp];
*rsp -= 2;
*rcs = *(uint16_t*)&vm->mem[*rsp];
*rsp -= 2;
interrupt_return(vm);
break;
}
@ -287,7 +274,7 @@ void vm_start(Drive* boot_drive, IODevice* io_device)
goto halt_execution;
case InterruptType_KeyEvent: {
if (vm->interrupt_timeout <= 0 && (*rfl >> Fl_Int & 1)) {
int res = jump_to_interrupt(vm, 0);
int res = jump_to_interrupt_handler(vm, Int_Key);
if (res != 0) {
goto halt_execution;
}
@ -376,11 +363,53 @@ static inline void run_arithm_ins(VM* vm, uint16_t ins)
}
}
static inline int jump_to_interrupt(VM* vm, uint16_t int_id)
static inline void handle_device_read(VM* vm, Reg dst_reg, uint16_t device_id)
{
switch (device_id) {
case Device_Keyboard:
vm->regs[dst_reg] = vm->keyboard_port_input;
break;
default:
fprintf(stderr, "warning: no input device %d\n", device_id);
break;
}
}
static inline void handle_device_write(VM* vm, uint16_t op1, uint16_t device_id)
{
switch (device_id) {
default:
fprintf(stderr, "warning: no output device %d\n", device_id);
break;
}
}
static inline int handle_interrupt(VM* vm, uint8_t int_id)
{
switch ((VM_Int)int_id) {
case Int_DiskRead: {
uint16_t addr = vm->regs[R0];
uint16_t block = vm->regs[R1];
vm->boot_drive->read(vm->boot_drive, &vm->mem[addr], block);
break;
}
case Int_DiskWrite: {
uint16_t addr = vm->regs[R0];
uint16_t block = vm->regs[R1];
vm->boot_drive->write(vm->boot_drive, &vm->mem[addr], block);
break;
}
default:
return jump_to_interrupt_handler(vm, int_id);
}
return 0;
}
static inline int jump_to_interrupt_handler(VM* vm, uint8_t int_id)
{
uint16_t* rip = &vm->regs[Rip];
uint16_t* rsp = &vm->regs[Rsp];
uint16_t* rfl = &vm->regs[Rfl];
uint16_t* rip = &vm->regs[Rip];
uint16_t* rcs = &vm->regs[Rcs];
if ((*rfl >> Fl_Int & 1) == 0) {
@ -389,15 +418,16 @@ static inline int jump_to_interrupt(VM* vm, uint16_t int_id)
return -1;
}
uint16_t offset = int_id - 32;
uint16_t int_table_size = *(uint16_t*)&vm->mem[vm->int_table];
if (int_id >= int_table_size) {
if (offset >= int_table_size) {
fprintf(stderr, "error: interrupt outside table (%d)\n", int_id);
vm->regs[Rfl] |= 1 << Fl_Err;
return -1;
}
uint16_t int_addr = *(uint16_t*)&vm->mem[vm->int_table + int_id * 2 + 2];
uint16_t int_addr = *(uint16_t*)&vm->mem[vm->int_table + offset * 2 + 2];
*rsp += 2;
*(uint16_t*)&vm->mem[*rsp] = *rcs;
@ -410,6 +440,18 @@ static inline int jump_to_interrupt(VM* vm, uint16_t int_id)
return 0;
}
static inline void interrupt_return(VM* vm)
{
uint16_t* rsp = &vm->regs[Rsp];
uint16_t* rip = &vm->regs[Rip];
uint16_t* rcs = &vm->regs[Rcs];
*rip = *(uint16_t*)&vm->mem[*rsp];
*rsp -= 2;
*rcs = *(uint16_t*)&vm->mem[*rsp];
*rsp -= 2;
}
static inline void maybe_update_vcd(VM* vm, uint16_t addr)
{
if (!vm->io_device)

10
vm/vm.h
View File

@ -59,6 +59,16 @@ typedef enum {
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);