diff --git a/vm/asm.c b/vm/asm.c index 2e141bd..7ab4fb1 100644 --- a/vm/asm.c +++ b/vm/asm.c @@ -51,10 +51,10 @@ Line s_mov8_mi_i(uint16_t dst_imm, uint16_t op2_imm) .op2 = (Ex) { .imm = op2_imm }, }; } -Line s_mov8_mi_reg(uint16_t dst_imm, Reg op2_reg) +Line s_mov8_mi_r(uint16_t dst_imm, Reg op2_reg) { return (Line) { - .ty = LineTy_Mov8_MemImm_Imm, + .ty = LineTy_Mov8_MemImm_Reg, .dst = (Ex) { .imm = dst_imm }, .op2 = (Ex) { .reg = (uint16_t)op2_reg }, }; @@ -120,21 +120,21 @@ Line s_iret(void) return (Line) { .ty = LineTy_IRet }; } -#define DEFINE_BINARY_R_I(FN, LINETY) \ +#define DEFINE_BINARY_I(FN, LINETY) \ Line s_##FN##_r_i(Reg dst_reg, Reg op1_reg, uint16_t op2_imm) \ { \ return (Line) { \ - .ty = LineTy_##LINETY##_Reg_Imm, \ + .ty = LineTy_##LINETY##_Imm, \ .dst = (Ex) { .reg = (uint16_t)dst_reg }, \ .op1 = (Ex) { .reg = (uint16_t)op1_reg }, \ .op2 = (Ex) { .imm = op2_imm }, \ }; \ } -DEFINE_BINARY_R_I(or, Or) -DEFINE_BINARY_R_I(and, And) -DEFINE_BINARY_R_I(add, Add) -DEFINE_BINARY_R_I(sub, Sub) +DEFINE_BINARY_I(or, Or) +DEFINE_BINARY_I(and, And) +DEFINE_BINARY_I(add, Add) +DEFINE_BINARY_I(sub, Sub) static inline void add_dst_reg(uint32_t* ins, uint16_t reg); static inline void add_op1_reg(uint32_t* ins, uint16_t reg); @@ -165,23 +165,37 @@ void assemble_to_binary(uint16_t* out, const Line* lines, size_t lines_size) size_t res_labels_size = 0; #define ADD_LABEL(LABEL) \ - unres_labels[unres_labels_size++] = (UnresolvedLabel) { LABEL, ip }; \ - out[ip++] = 0; + { \ + unres_labels[unres_labels_size++] = (UnresolvedLabel) { LABEL, ip }; \ + out[ip++] = 0; \ + } + printf("assembling...\n"); + printf("ip op n data...\n"); for (size_t i = 0; i < lines_size; ++i) { + bool is_label = false; + bool is_data = false; + const Line* line = &lines[i]; + uint16_t ins_ip = ip; switch (line->ty) { case LineTy_Label: { res_labels[res_labels_size++] = (ResolvedLabel) { line->op1.label, ip * 2 }; + + is_label = true; break; } case LineTy_DataImm: { out[ip++] = line->op1.imm; + + is_data = true; break; } case LineTy_DataLabel: { ADD_LABEL(line->op1.label); + + is_data = true; break; } case LineTy_Nop: { @@ -231,7 +245,7 @@ void assemble_to_binary(uint16_t* out, const Line* lines, size_t lines_size) uint16_t op2 = line->op2.reg; uint32_t ins = Op_Mov16; - ins |= (op2 & 0xfu) << 6; + ins |= (op2 & 0xfu) << 7; ins |= (dst & 0xfu) << 12; out[ip++] = (uint16_t)ins; @@ -282,7 +296,7 @@ void assemble_to_binary(uint16_t* out, const Line* lines, size_t lines_size) uint16_t dst = line->dst.reg; uint16_t op1 = line->op1.imm; - uint32_t ins = Op_Lit; + uint32_t ins = Op_In; set_is_imm(&ins); add_dst_reg(&ins, dst); @@ -314,10 +328,10 @@ void assemble_to_binary(uint16_t* out, const Line* lines, size_t lines_size) out[ip++] = Op_IRet; break; } - case LineTy_Or_Reg_Imm: - case LineTy_And_Reg_Imm: - case LineTy_Add_Reg_Imm: - case LineTy_Sub_Reg_Imm: { + case LineTy_Or_Imm: + case LineTy_And_Imm: + case LineTy_Add_Imm: + case LineTy_Sub_Imm: { uint16_t dst = line->dst.reg; uint16_t op1 = line->op1.reg; uint16_t op2 = line->op2.imm; @@ -332,14 +346,41 @@ void assemble_to_binary(uint16_t* out, const Line* lines, size_t lines_size) break; } } + + if (!is_label) { + printf("%02x %-5s %d", + ins_ip * 2, + is_data ? "data" : op_str(out[ins_ip] & 0x3f), + ip - ins_ip); + for (uint16_t i = 0; i < ip - ins_ip; ++i) { + printf(" %02x %c%c%c%c %c%c%c%c %02x %c%c%c%c %c%c%c%c ", + out[ins_ip + i] & 0xff, + fmt_binary(out[ins_ip + i] & 0xff), + out[ins_ip + i] >> 8, + fmt_binary(out[ins_ip + i] >> 8)); + } + printf("\n"); + } } + printf("resolving...\n"); + printf(" l ip v data\n"); for (size_t i = 0; i < unres_labels_size; ++i) { bool found = false; for (size_t j = 0; j < res_labels_size; ++j) { if (res_labels[j].label == unres_labels[i].label) { out[unres_labels[i].ptr] = res_labels[j].ip; found = true; + + printf("%2d %02x %02x %02x %c%c%c%c %c%c%c%c %02x %c%c%c%c " + "%c%c%c%c\n", + res_labels[j].label, + unres_labels[i].ptr * 2, + res_labels[j].ip, + out[unres_labels[i].ptr] & 0xff, + fmt_binary(out[unres_labels[i].ptr] & 0xff), + out[unres_labels[i].ptr] >> 8, + fmt_binary(out[unres_labels[i].ptr] >> 8)); break; } } @@ -349,6 +390,7 @@ void assemble_to_binary(uint16_t* out, const Line* lines, size_t lines_size) unres_labels[i].label); } } + printf("done!\n"); } static inline void add_dst_reg(uint32_t* ins, uint16_t reg) @@ -383,9 +425,9 @@ static inline void set_mov_is_store(uint32_t* ins) static inline uint16_t linety_arithm_ins(LineTy ty) { switch (ty) { - case LineTy_Or_Reg_Imm: + case LineTy_Or_Imm: return Op_Or; - case LineTy_And_Reg_Imm: + case LineTy_And_Imm: return Op_And; case LineTy_Add_Reg_Imm: return Op_Add; diff --git a/vm/asm.h b/vm/asm.h index 3ae460b..75e0022 100644 --- a/vm/asm.h +++ b/vm/asm.h @@ -21,10 +21,10 @@ typedef enum { LineTy_Lit_Imm, LineTy_Lit_Label, LineTy_IRet, - LineTy_Or_Reg_Imm, - LineTy_And_Reg_Imm, - LineTy_Add_Reg_Imm, - LineTy_Sub_Reg_Imm, + LineTy_Or_Imm, + LineTy_And_Imm, + LineTy_Add_Imm, + LineTy_Sub_Imm, } LineTy; typedef struct { @@ -52,7 +52,7 @@ Line s_nop(void); Line s_hlt(void); Line s_jmp_l(int op1_label); Line s_mov8_mi_i(uint16_t dst_imm, uint16_t op2_imm); -Line s_mov8_mi_reg(uint16_t dst_imm, Reg op2_reg); +Line s_mov8_mi_r(uint16_t dst_imm, Reg op2_reg); Line s_mov16_r_r(Reg dst_reg, Reg op2_reg); Line s_mov16_r_i(Reg dst_reg, uint16_t op2_imm); Line s_mov16_r_mr(Reg dst_reg, Reg op2_reg, uint16_t op2_offset); @@ -61,9 +61,19 @@ 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_iret(void); -Line s_or_r_i(Reg dst_reg, Reg op1_reg, uint16_t op2_imm); -Line s_and_r_i(Reg dst_reg, Reg op1_reg, uint16_t op2_imm); -Line s_add_r_i(Reg dst_reg, Reg op1_reg, uint16_t op2_imm); -Line s_sub_r_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_add_i(Reg dst_reg, Reg op1_reg, uint16_t op2_imm); +Line s_sub_i(Reg dst_reg, Reg op1_reg, uint16_t op2_imm); + +#define s_push_r(REG) s_add_i(Rsp, Rsp, 2), s_mov16_mr_r(Rsp, 0, REG) + +#define s_pop_r(REG) s_mov16_r_mr(REG, Rsp, 2), s_sub_i(Rsp, Rsp, 2) void assemble_to_binary(uint16_t* out, const Line* lines, size_t lines_size); + +#define fmt_binary(VAL) \ + (VAL) >> 7 & 1 ? '1' : '0', (VAL) >> 6 & 1 ? '1' : '0', \ + (VAL) >> 5 & 1 ? '1' : '0', (VAL) >> 4 & 1 ? '1' : '0', \ + (VAL) >> 3 & 1 ? '1' : '0', (VAL) >> 2 & 1 ? '1' : '0', \ + (VAL) >> 1 & 1 ? '1' : '0', (VAL) >> 0 & 1 ? '1' : '0' diff --git a/vm/main.c b/vm/main.c index af3b06e..11854b0 100644 --- a/vm/main.c +++ b/vm/main.c @@ -187,8 +187,9 @@ extern const bool charset[][ch_height][ch_width]; void sdldevice_set_char(IODevice* io_device, uint16_t offset, uint8_t value) { - printf("value = %d '%c'\n", value, value); - return; + printf("value = %d '%c', offset = %d\n", value, value, offset); + if (value < 'A' || value > 'C') + return; SdlDevice* device = io_device->self; pthread_mutex_lock(&device->mutex); @@ -238,9 +239,9 @@ void sdldevice_wait_for_interrupt(IODevice* io_device) pthread_mutex_lock(&device->mutex); - printf("vm: waiting for interrupt...\n"); + // printf("vm: waiting for interrupt...\n"); pthread_cond_wait(&device->interrupt_waiter, &device->mutex); - printf("vm: got interrupt!\n"); + // printf("vm: got interrupt!\n"); pthread_mutex_unlock(&device->mutex); } @@ -297,7 +298,7 @@ void sdldevice_poll_events(SdlDevice* device) pthread_mutex_unlock(&device->mutex); if (should_notify) { - printf("sdldevice: interrupt occured!\n"); + // printf("sdldevice: interrupt occured!\n"); pthread_cond_signal(&device->interrupt_waiter); } } @@ -362,21 +363,16 @@ void memdrive_drive_write(Drive* in_drive, const uint8_t* block, uint16_t i) __attribute__((unused)) static inline void dump_program(uint16_t* program) { - for (size_t rip = 0; rip < 80; ++rip) { - uint8_t* out = (uint8_t*)program; - // clang-format off - printf( - "out[%2ld] = %c%c%c%c %c%c%c%c\n", rip - , out[rip] >> 7 & 1 ? '1' : '0' - , out[rip] >> 6 & 1 ? '1' : '0' - , out[rip] >> 5 & 1 ? '1' : '0' - , out[rip] >> 4 & 1 ? '1' : '0' - , out[rip] >> 3 & 1 ? '1' : '0' - , out[rip] >> 2 & 1 ? '1' : '0' - , out[rip] >> 1 & 1 ? '1' : '0' - , out[rip] >> 0 & 1 ? '1' : '0' - ); - // clang-format on + for (size_t rip = 20; rip < 60; ++rip) { + uint16_t val = program[rip]; + printf("[%02lx] = %02x %02x %c%c%c%c %c%c%c%c %c%c%c%c %c%c%c%c " + "%s\n", + rip * 2, + val >> 8, + val & 0xff, + fmt_binary(val >> 8), + fmt_binary(val & 0xff), + op_str(val & 0x3f)); } } @@ -384,26 +380,18 @@ int main(void) { int res; - SdlDevice io_device; - res = sdldevice_construct(&io_device); - if (res != 0) { - exit(1); - } - int main_loop = 1; int interrupt_table = 2; int keyboard_interrupt = 3; #define L(LABEL) s_label(LABEL) -#define s_push_r(REG) s_add_r_i(Rsp, Rsp, 2), s_mov16_mr_r(Rsp, 0, REG) -#define s_pop_r(REG) s_mov16_r_mr(REG, Rsp, 2), s_sub_r_i(Rsp, Rsp, 2) Line program_asm[] = { // clang-format off s_nop(), // set video character display flag - s_or_r_i(Rfl, Rfl, 1 << Fl_Vcd), + s_or_i(Rfl, Rfl, 1 << Fl_Vcd), // print ABC s_mov8_mi_i(0x0c00 + 0, 'A'), @@ -418,18 +406,21 @@ int main(void) // load interrupt table s_lit_l(interrupt_table), // set interrupt flag - s_or_r_i(Rfl, Rfl, 1 << Fl_Int), + s_or_i(Rfl, Rfl, 1 << Fl_Int), L(main_loop), s_hlt(), s_jmp_l(main_loop), + s_nop(), L(interrupt_table), // size s_data_i(1), s_data_l(keyboard_interrupt), s_nop(), L(keyboard_interrupt), + s_nop(), + s_nop(), // clear interrupt flag - s_and_r_i(Rfl, Rfl, (uint16_t)~(1 << Fl_Int)), + s_and_i(Rfl, Rfl, (uint16_t)~(1 << Fl_Int)), // setup stack frame s_push_r(Rbp), s_mov16_r_r(Rbp, Rsp), @@ -438,14 +429,15 @@ int main(void) // read keyboard port s_in_i(R0, 0), - s_mov8_mi_i(0x0c00 + 4, R0), + s_add_i(R0, R0, 'A' - 4), + s_mov8_mi_r(0x0c00 + 4, R0), // tear down frame s_pop_r(R0), s_mov16_r_r(Rsp, Rbp), s_pop_r(Rbp), // set interrupt flag - s_or_r_i(Rfl, Rfl, 1 << Fl_Int), + s_or_i(Rfl, Rfl, 1 << Fl_Int), // return from interrupt s_iret(), @@ -459,9 +451,17 @@ int main(void) dump_program(program); + /*return 0;*/ + MemDrive drive; memdrive_construct(&drive, (uint64_t*)program, 512); + SdlDevice io_device; + res = sdldevice_construct(&io_device); + if (res != 0) { + exit(1); + } + vm_start(&drive.drive, &io_device.io_device); sdldevice_destroy(&io_device); diff --git a/vm/vm.c b/vm/vm.c index b9c4c2a..8827105 100644 --- a/vm/vm.c +++ b/vm/vm.c @@ -8,18 +8,19 @@ typedef struct { uint16_t regs[10]; uint8_t* mem; Drive* boot_drive; - int16_t seg_count; - int16_t seg_size; + uint16_t seg_count; + uint16_t seg_size; IODevice* io_device; uint16_t int_table; int interrupt_timeout; uint16_t keyboard_port_input; } VM; -static inline int jump_to_interrupt(VM* vm, uint16_t int_id); 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 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); static inline Op ins_op(uint16_t ins); static inline Reg ins_dst_reg(uint16_t ins); @@ -32,8 +33,6 @@ static inline uint16_t ins_reg_val_or_imm( static inline uint16_t ins_op1_or_imm(VM* vm, uint16_t ins); static inline uint16_t ins_op2_or_imm(VM* vm, uint16_t ins); -static inline const char* op_str(Op op); - void vm_start(Drive* boot_drive, IODevice* io_device) { const uint16_t seg_count = 16; @@ -47,7 +46,7 @@ void vm_start(Drive* boot_drive, IODevice* io_device) .seg_size = seg_size, .io_device = io_device, .int_table = 0, - .interrupt_timeout = 0, + .interrupt_timeout = 10, .keyboard_port_input = 0, }; @@ -67,10 +66,10 @@ void vm_start(Drive* boot_drive, IODevice* io_device) uint16_t ins = eat_uint16(vm); Op op = ins_op(ins); - printf("[%3d] = %3d %s\n", *rip - 2, op, op_str(op)); + /*printf("[%3d] = %3d %s\n", *rip - 2, op, op_str(op));*/ - if (*rip >= 74) { - printf("rip >= 74\n"); + if (*rip >= 300) { + printf("killed: rip >= 200\n"); exit(0); } @@ -79,11 +78,12 @@ void vm_start(Drive* boot_drive, IODevice* io_device) break; case Op_Hlt: vm->io_device->wait_for_interrupt(vm->io_device); + vm->interrupt_timeout = 0; break; case Op_Jmp: { bool is_farjump = ins >> 7 & 1; if (is_farjump) { - uint16_t cs = ins_reg_val_or_imm(vm, ins, 8, 12, 0x7); + uint16_t cs = ins_reg_val_or_imm(vm, ins, 8, 13, 0x7); uint16_t op1 = ins_op1_or_imm(vm, ins); *rcs = cs; *rip = op1; @@ -196,9 +196,8 @@ void vm_start(Drive* boot_drive, IODevice* io_device) vm->regs[dst_reg] = vm->keyboard_port_input; break; default: - fprintf(stderr, - "warning: input, no device %d\n", - device_id); + fprintf( + stderr, "warning: no input device %d\n", device_id); break; } break; @@ -210,7 +209,7 @@ void vm_start(Drive* boot_drive, IODevice* io_device) switch (device_id) { default: fprintf(stderr, - "warning: output, no device %d\n", + "warning: no output device %d\n", device_id); break; } @@ -286,40 +285,6 @@ halt_execution: return; } -static inline int jump_to_interrupt(VM* vm, uint16_t int_id) -{ - uint16_t* rip = &vm->regs[Rip]; - uint16_t* rsp = &vm->regs[Rsp]; - uint16_t* rfl = &vm->regs[Rfl]; - uint16_t* rcs = &vm->regs[Rcs]; - - if ((*rfl >> Fl_Int & 1) == 0) { - fprintf(stderr, "error: interrupt with unset flag\n"); - vm->regs[Rfl] |= 1 << Fl_Err; - return -1; - } - - uint16_t int_table_size = *(uint16_t*)&vm->mem[vm->int_table]; - - if (int_id >= int_table_size) { - fprintf(stderr, "error: interrupt outside table\n"); - vm->regs[Rfl] |= 1 << Fl_Err; - return -1; - } - - uint16_t int_addr = *(uint16_t*)&vm->mem[vm->int_table + int_id * 2 + 2]; - - *rsp += 2; - *(uint16_t*)&vm->mem[*rsp] = *rcs; - *rsp += 2; - *(uint16_t*)&vm->mem[*rsp] = *rip; - - *rcs = 0; - *rip = int_addr; - - return 0; -} - static inline void run_arithm_ins(VM* vm, uint16_t ins) { typedef uint16_t u; @@ -392,6 +357,40 @@ static inline void run_arithm_ins(VM* vm, uint16_t ins) } } +static inline int jump_to_interrupt(VM* vm, uint16_t int_id) +{ + uint16_t* rip = &vm->regs[Rip]; + uint16_t* rsp = &vm->regs[Rsp]; + uint16_t* rfl = &vm->regs[Rfl]; + uint16_t* rcs = &vm->regs[Rcs]; + + if ((*rfl >> Fl_Int & 1) == 0) { + fprintf(stderr, "error: interrupt with unset flag\n"); + vm->regs[Rfl] |= 1 << Fl_Err; + return -1; + } + + uint16_t int_table_size = *(uint16_t*)&vm->mem[vm->int_table]; + + if (int_id >= 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]; + + *rsp += 2; + *(uint16_t*)&vm->mem[*rsp] = *rcs; + *rsp += 2; + *(uint16_t*)&vm->mem[*rsp] = *rip; + + *rcs = 0; + *rip = int_addr; + + return 0; +} + static inline void maybe_update_vcd(VM* vm, uint16_t addr) { if (!vm->io_device) @@ -408,13 +407,16 @@ static inline void maybe_update_vcd(VM* vm, uint16_t addr) static inline uint16_t eat_uint16(VM* vm) { uint16_t* rip = &vm->regs[Rip]; - uint16_t* rcs = &vm->regs[Rcs]; - - uint16_t ins = *(uint16_t*)&vm->mem[*rcs * vm->seg_size + *rip]; + uint16_t ins = read_seg_uint16(vm, *rip); *rip += 2; return ins; } +static inline uint16_t read_seg_uint16(VM* vm, uint16_t ptr) +{ + return *(uint16_t*)&vm->mem[vm->regs[Rcs] * vm->seg_size + ptr]; +} + static inline Op ins_op(uint16_t ins) { return ins & 0x3F; @@ -466,7 +468,7 @@ static inline uint16_t ins_op2_or_imm(VM* vm, uint16_t ins) return ins_reg_val_or_imm(vm, ins, 6, 7, 0x7); } -static inline const char* op_str(Op op) +const char* op_str(Op op) { switch (op) { case Op_Nop: @@ -532,5 +534,5 @@ static inline const char* op_str(Op op) case Op_RMod: return "rmod"; } - return ""; + return "---"; } diff --git a/vm/vm.h b/vm/vm.h index a2c9d19..b3c2ff3 100644 --- a/vm/vm.h +++ b/vm/vm.h @@ -102,3 +102,5 @@ struct IODevice { }; void vm_start(Drive* boot_drive, IODevice* io_device); + +const char* op_str(Op op);