read from disk
This commit is contained in:
parent
42246deb35
commit
bcd1500f9c
1
Makefile
1
Makefile
@ -8,6 +8,7 @@ C_FLAGS = \
|
|||||||
-Wall -Wextra -Wpedantic -Wconversion \
|
-Wall -Wextra -Wpedantic -Wconversion \
|
||||||
-pedantic -pedantic-errors \
|
-pedantic -pedantic-errors \
|
||||||
-Wno-unused-variable \
|
-Wno-unused-variable \
|
||||||
|
-Wno-unused-parameter \
|
||||||
-I. \
|
-I. \
|
||||||
|
|
||||||
L_FLAGS = -pthread
|
L_FLAGS = -pthread
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
-pedantic
|
-pedantic
|
||||||
-pedantic-errors
|
-pedantic-errors
|
||||||
-Wno-unused-variable
|
-Wno-unused-variable
|
||||||
# -Wno-unused-parameter
|
-Wno-unused-parameter
|
||||||
# -Wno-unused-function
|
# -Wno-unused-function
|
||||||
-I.
|
-I.
|
||||||
|
|
||||||
|
15
vm/asm.c
15
vm/asm.c
@ -163,6 +163,13 @@ Line s_lit_l(int op1_label)
|
|||||||
.op1 = (Ex) { .label = 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)
|
Line s_iret(void)
|
||||||
{
|
{
|
||||||
return (Line) { .ty = LineTy_IRet };
|
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);
|
ADD_LABEL(op1);
|
||||||
break;
|
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: {
|
case LineTy_IRet: {
|
||||||
out[ip++] = Op_IRet;
|
out[ip++] = Op_IRet;
|
||||||
break;
|
break;
|
||||||
|
2
vm/asm.h
2
vm/asm.h
@ -26,6 +26,7 @@ typedef enum {
|
|||||||
LineTy_In_Imm,
|
LineTy_In_Imm,
|
||||||
LineTy_Lit_Imm,
|
LineTy_Lit_Imm,
|
||||||
LineTy_Lit_Label,
|
LineTy_Lit_Label,
|
||||||
|
LineTy_Int,
|
||||||
LineTy_IRet,
|
LineTy_IRet,
|
||||||
LineTy_Or_Imm,
|
LineTy_Or_Imm,
|
||||||
LineTy_And_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_in_i(Reg dst_reg, uint16_t op1_imm);
|
||||||
Line s_lit_i(uint16_t op1_imm);
|
Line s_lit_i(uint16_t op1_imm);
|
||||||
Line s_lit_l(int op1_label);
|
Line s_lit_l(int op1_label);
|
||||||
|
Line s_int(uint8_t int_id);
|
||||||
Line s_iret(void);
|
Line s_iret(void);
|
||||||
Line s_or_i(Reg dst_reg, Reg op1_reg, uint16_t op2_imm);
|
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);
|
Line s_and_i(Reg dst_reg, Reg op1_reg, uint16_t op2_imm);
|
||||||
|
19
vm/main.c
19
vm/main.c
@ -400,18 +400,20 @@ int main(void)
|
|||||||
Line program_asm[] = {
|
Line program_asm[] = {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
s_nop(),
|
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
|
// rsp points *at* the top element
|
||||||
|
s_mov16_r_i(Rbp, 2048),
|
||||||
s_mov16_r_i(Rsp, 2048 - 2),
|
s_mov16_r_i(Rsp, 2048 - 2),
|
||||||
|
|
||||||
// load interrupt table
|
|
||||||
s_lit_l(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_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),
|
L(main_loop),
|
||||||
s_hlt(),
|
s_hlt(),
|
||||||
s_jmp_l(main_loop),
|
s_jmp_l(main_loop),
|
||||||
@ -430,7 +432,7 @@ int main(void)
|
|||||||
s_push_r(R2),
|
s_push_r(R2),
|
||||||
|
|
||||||
// read keyboard port
|
// read keyboard port
|
||||||
s_in_i(R0, 0),
|
s_in_i(R0, Device_Keyboard),
|
||||||
s_add_i(R0, R0, 'A' - 4),
|
s_add_i(R0, R0, 'A' - 4),
|
||||||
|
|
||||||
s_cmp_i(R0, 105),
|
s_cmp_i(R0, 105),
|
||||||
@ -467,7 +469,7 @@ int main(void)
|
|||||||
|
|
||||||
size_t program_asm_size = sizeof(program_asm) / sizeof(program_asm[0]);
|
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);
|
assemble_to_binary(program, program_asm, program_asm_size);
|
||||||
|
|
||||||
// dump_program(program);
|
// dump_program(program);
|
||||||
@ -485,6 +487,7 @@ int main(void)
|
|||||||
|
|
||||||
vm_start(&drive.drive, &io_device.io_device);
|
vm_start(&drive.drive, &io_device.io_device);
|
||||||
|
|
||||||
|
free(program);
|
||||||
sdldevice_destroy(&io_device);
|
sdldevice_destroy(&io_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
102
vm/vm.c
102
vm/vm.c
@ -17,7 +17,12 @@ typedef struct {
|
|||||||
} VM;
|
} VM;
|
||||||
|
|
||||||
static inline void run_arithm_ins(VM* vm, uint16_t ins);
|
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 void maybe_update_vcd(VM* vm, uint16_t addr);
|
||||||
static inline uint16_t eat_uint16(VM* vm);
|
static inline uint16_t eat_uint16(VM* vm);
|
||||||
static inline uint16_t read_seg_uint16(VM* vm, uint16_t ptr);
|
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* rfl = &vm->regs[Rfl];
|
||||||
uint16_t* rcs = &vm->regs[Rcs];
|
uint16_t* rcs = &vm->regs[Rcs];
|
||||||
|
|
||||||
|
const uint16_t bootloader_size = 512;
|
||||||
const uint16_t block_size = vm->boot_drive->block_size;
|
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);
|
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: {
|
case Op_In: {
|
||||||
Reg dst_reg = ins_dst_reg(ins);
|
Reg dst_reg = ins_dst_reg(ins);
|
||||||
uint16_t device_id = ins_op1_or_imm(vm, ins);
|
uint16_t device_id = ins_op1_or_imm(vm, ins);
|
||||||
|
handle_device_read(vm, dst_reg, device_id);
|
||||||
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;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Op_Out: {
|
case Op_Out: {
|
||||||
uint16_t op1 = ins_op2(vm, ins);
|
uint16_t op1 = ins_op2(vm, ins);
|
||||||
uint16_t device_id = ins_op1_or_imm(vm, ins);
|
uint16_t device_id = ins_op1_or_imm(vm, ins);
|
||||||
|
handle_device_write(vm, op1, device_id);
|
||||||
switch (device_id) {
|
|
||||||
default:
|
|
||||||
fprintf(stderr,
|
|
||||||
"warning: no output device %d\n",
|
|
||||||
device_id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Op_Lit: {
|
case Op_Lit: {
|
||||||
@ -242,17 +232,14 @@ void vm_start(Drive* boot_drive, IODevice* io_device)
|
|||||||
case Op_Int: {
|
case Op_Int: {
|
||||||
uint8_t int_id = (uint8_t)(ins >> 8 & 0xff);
|
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) {
|
if (res != 0) {
|
||||||
goto halt_execution;
|
goto halt_execution;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Op_IRet: {
|
case Op_IRet: {
|
||||||
*rip = *(uint16_t*)&vm->mem[*rsp];
|
interrupt_return(vm);
|
||||||
*rsp -= 2;
|
|
||||||
*rcs = *(uint16_t*)&vm->mem[*rsp];
|
|
||||||
*rsp -= 2;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,7 +274,7 @@ void vm_start(Drive* boot_drive, IODevice* io_device)
|
|||||||
goto halt_execution;
|
goto halt_execution;
|
||||||
case InterruptType_KeyEvent: {
|
case InterruptType_KeyEvent: {
|
||||||
if (vm->interrupt_timeout <= 0 && (*rfl >> Fl_Int & 1)) {
|
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) {
|
if (res != 0) {
|
||||||
goto halt_execution;
|
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* rsp = &vm->regs[Rsp];
|
||||||
uint16_t* rfl = &vm->regs[Rfl];
|
uint16_t* rfl = &vm->regs[Rfl];
|
||||||
|
uint16_t* rip = &vm->regs[Rip];
|
||||||
uint16_t* rcs = &vm->regs[Rcs];
|
uint16_t* rcs = &vm->regs[Rcs];
|
||||||
|
|
||||||
if ((*rfl >> Fl_Int & 1) == 0) {
|
if ((*rfl >> Fl_Int & 1) == 0) {
|
||||||
@ -389,15 +418,16 @@ static inline int jump_to_interrupt(VM* vm, uint16_t int_id)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t offset = int_id - 32;
|
||||||
uint16_t int_table_size = *(uint16_t*)&vm->mem[vm->int_table];
|
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);
|
fprintf(stderr, "error: interrupt outside table (%d)\n", int_id);
|
||||||
vm->regs[Rfl] |= 1 << Fl_Err;
|
vm->regs[Rfl] |= 1 << Fl_Err;
|
||||||
return -1;
|
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;
|
*rsp += 2;
|
||||||
*(uint16_t*)&vm->mem[*rsp] = *rcs;
|
*(uint16_t*)&vm->mem[*rsp] = *rcs;
|
||||||
@ -410,6 +440,18 @@ static inline int jump_to_interrupt(VM* vm, uint16_t int_id)
|
|||||||
return 0;
|
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)
|
static inline void maybe_update_vcd(VM* vm, uint16_t addr)
|
||||||
{
|
{
|
||||||
if (!vm->io_device)
|
if (!vm->io_device)
|
||||||
|
10
vm/vm.h
10
vm/vm.h
@ -59,6 +59,16 @@ typedef enum {
|
|||||||
Op_RMod,
|
Op_RMod,
|
||||||
} Op;
|
} 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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user