keyboard interrupts work

This commit is contained in:
sfja 2025-03-31 02:12:09 +02:00
parent b74c99b05e
commit ad79f82f1f
5 changed files with 169 additions and 113 deletions

View File

@ -51,10 +51,10 @@ Line s_mov8_mi_i(uint16_t dst_imm, uint16_t op2_imm)
.op2 = (Ex) { .imm = 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) { return (Line) {
.ty = LineTy_Mov8_MemImm_Imm, .ty = LineTy_Mov8_MemImm_Reg,
.dst = (Ex) { .imm = dst_imm }, .dst = (Ex) { .imm = dst_imm },
.op2 = (Ex) { .reg = (uint16_t)op2_reg }, .op2 = (Ex) { .reg = (uint16_t)op2_reg },
}; };
@ -120,21 +120,21 @@ Line s_iret(void)
return (Line) { .ty = LineTy_IRet }; 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) \ Line s_##FN##_r_i(Reg dst_reg, Reg op1_reg, uint16_t op2_imm) \
{ \ { \
return (Line) { \ return (Line) { \
.ty = LineTy_##LINETY##_Reg_Imm, \ .ty = LineTy_##LINETY##_Imm, \
.dst = (Ex) { .reg = (uint16_t)dst_reg }, \ .dst = (Ex) { .reg = (uint16_t)dst_reg }, \
.op1 = (Ex) { .reg = (uint16_t)op1_reg }, \ .op1 = (Ex) { .reg = (uint16_t)op1_reg }, \
.op2 = (Ex) { .imm = op2_imm }, \ .op2 = (Ex) { .imm = op2_imm }, \
}; \ }; \
} }
DEFINE_BINARY_R_I(or, Or) DEFINE_BINARY_I(or, Or)
DEFINE_BINARY_R_I(and, And) DEFINE_BINARY_I(and, And)
DEFINE_BINARY_R_I(add, Add) DEFINE_BINARY_I(add, Add)
DEFINE_BINARY_R_I(sub, Sub) DEFINE_BINARY_I(sub, Sub)
static inline void add_dst_reg(uint32_t* ins, uint16_t reg); static inline void add_dst_reg(uint32_t* ins, uint16_t reg);
static inline void add_op1_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; size_t res_labels_size = 0;
#define ADD_LABEL(LABEL) \ #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) { for (size_t i = 0; i < lines_size; ++i) {
bool is_label = false;
bool is_data = false;
const Line* line = &lines[i]; const Line* line = &lines[i];
uint16_t ins_ip = ip;
switch (line->ty) { switch (line->ty) {
case LineTy_Label: { case LineTy_Label: {
res_labels[res_labels_size++] res_labels[res_labels_size++]
= (ResolvedLabel) { line->op1.label, ip * 2 }; = (ResolvedLabel) { line->op1.label, ip * 2 };
is_label = true;
break; break;
} }
case LineTy_DataImm: { case LineTy_DataImm: {
out[ip++] = line->op1.imm; out[ip++] = line->op1.imm;
is_data = true;
break; break;
} }
case LineTy_DataLabel: { case LineTy_DataLabel: {
ADD_LABEL(line->op1.label); ADD_LABEL(line->op1.label);
is_data = true;
break; break;
} }
case LineTy_Nop: { 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; uint16_t op2 = line->op2.reg;
uint32_t ins = Op_Mov16; uint32_t ins = Op_Mov16;
ins |= (op2 & 0xfu) << 6; ins |= (op2 & 0xfu) << 7;
ins |= (dst & 0xfu) << 12; ins |= (dst & 0xfu) << 12;
out[ip++] = (uint16_t)ins; 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 dst = line->dst.reg;
uint16_t op1 = line->op1.imm; uint16_t op1 = line->op1.imm;
uint32_t ins = Op_Lit; uint32_t ins = Op_In;
set_is_imm(&ins); set_is_imm(&ins);
add_dst_reg(&ins, dst); 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; out[ip++] = Op_IRet;
break; break;
} }
case LineTy_Or_Reg_Imm: case LineTy_Or_Imm:
case LineTy_And_Reg_Imm: case LineTy_And_Imm:
case LineTy_Add_Reg_Imm: case LineTy_Add_Imm:
case LineTy_Sub_Reg_Imm: { case LineTy_Sub_Imm: {
uint16_t dst = line->dst.reg; uint16_t dst = line->dst.reg;
uint16_t op1 = line->op1.reg; uint16_t op1 = line->op1.reg;
uint16_t op2 = line->op2.imm; 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; 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) { for (size_t i = 0; i < unres_labels_size; ++i) {
bool found = false; bool found = false;
for (size_t j = 0; j < res_labels_size; ++j) { for (size_t j = 0; j < res_labels_size; ++j) {
if (res_labels[j].label == unres_labels[i].label) { if (res_labels[j].label == unres_labels[i].label) {
out[unres_labels[i].ptr] = res_labels[j].ip; out[unres_labels[i].ptr] = res_labels[j].ip;
found = true; 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; break;
} }
} }
@ -349,6 +390,7 @@ void assemble_to_binary(uint16_t* out, const Line* lines, size_t lines_size)
unres_labels[i].label); unres_labels[i].label);
} }
} }
printf("done!\n");
} }
static inline void add_dst_reg(uint32_t* ins, uint16_t reg) 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) static inline uint16_t linety_arithm_ins(LineTy ty)
{ {
switch (ty) { switch (ty) {
case LineTy_Or_Reg_Imm: case LineTy_Or_Imm:
return Op_Or; return Op_Or;
case LineTy_And_Reg_Imm: case LineTy_And_Imm:
return Op_And; return Op_And;
case LineTy_Add_Reg_Imm: case LineTy_Add_Reg_Imm:
return Op_Add; return Op_Add;

View File

@ -21,10 +21,10 @@ typedef enum {
LineTy_Lit_Imm, LineTy_Lit_Imm,
LineTy_Lit_Label, LineTy_Lit_Label,
LineTy_IRet, LineTy_IRet,
LineTy_Or_Reg_Imm, LineTy_Or_Imm,
LineTy_And_Reg_Imm, LineTy_And_Imm,
LineTy_Add_Reg_Imm, LineTy_Add_Imm,
LineTy_Sub_Reg_Imm, LineTy_Sub_Imm,
} LineTy; } LineTy;
typedef struct { typedef struct {
@ -52,7 +52,7 @@ Line s_nop(void);
Line s_hlt(void); Line s_hlt(void);
Line s_jmp_l(int op1_label); Line s_jmp_l(int op1_label);
Line s_mov8_mi_i(uint16_t dst_imm, uint16_t op2_imm); 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_r(Reg dst_reg, Reg op2_reg);
Line s_mov16_r_i(Reg dst_reg, uint16_t op2_imm); 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); 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_i(uint16_t op1_imm);
Line s_lit_l(int op1_label); Line s_lit_l(int op1_label);
Line s_iret(void); Line s_iret(void);
Line s_or_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_r_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_r_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_r_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); 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'

View File

@ -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) void sdldevice_set_char(IODevice* io_device, uint16_t offset, uint8_t value)
{ {
printf("value = %d '%c'\n", value, value); printf("value = %d '%c', offset = %d\n", value, value, offset);
return; if (value < 'A' || value > 'C')
return;
SdlDevice* device = io_device->self; SdlDevice* device = io_device->self;
pthread_mutex_lock(&device->mutex); pthread_mutex_lock(&device->mutex);
@ -238,9 +239,9 @@ void sdldevice_wait_for_interrupt(IODevice* io_device)
pthread_mutex_lock(&device->mutex); 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); pthread_cond_wait(&device->interrupt_waiter, &device->mutex);
printf("vm: got interrupt!\n"); // printf("vm: got interrupt!\n");
pthread_mutex_unlock(&device->mutex); pthread_mutex_unlock(&device->mutex);
} }
@ -297,7 +298,7 @@ void sdldevice_poll_events(SdlDevice* device)
pthread_mutex_unlock(&device->mutex); pthread_mutex_unlock(&device->mutex);
if (should_notify) { if (should_notify) {
printf("sdldevice: interrupt occured!\n"); // printf("sdldevice: interrupt occured!\n");
pthread_cond_signal(&device->interrupt_waiter); 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) __attribute__((unused)) static inline void dump_program(uint16_t* program)
{ {
for (size_t rip = 0; rip < 80; ++rip) { for (size_t rip = 20; rip < 60; ++rip) {
uint8_t* out = (uint8_t*)program; uint16_t val = program[rip];
// clang-format off printf("[%02lx] = %02x %02x %c%c%c%c %c%c%c%c %c%c%c%c %c%c%c%c "
printf( "%s\n",
"out[%2ld] = %c%c%c%c %c%c%c%c\n", rip rip * 2,
, out[rip] >> 7 & 1 ? '1' : '0' val >> 8,
, out[rip] >> 6 & 1 ? '1' : '0' val & 0xff,
, out[rip] >> 5 & 1 ? '1' : '0' fmt_binary(val >> 8),
, out[rip] >> 4 & 1 ? '1' : '0' fmt_binary(val & 0xff),
, out[rip] >> 3 & 1 ? '1' : '0' op_str(val & 0x3f));
, out[rip] >> 2 & 1 ? '1' : '0'
, out[rip] >> 1 & 1 ? '1' : '0'
, out[rip] >> 0 & 1 ? '1' : '0'
);
// clang-format on
} }
} }
@ -384,26 +380,18 @@ int main(void)
{ {
int res; int res;
SdlDevice io_device;
res = sdldevice_construct(&io_device);
if (res != 0) {
exit(1);
}
int main_loop = 1; int main_loop = 1;
int interrupt_table = 2; int interrupt_table = 2;
int keyboard_interrupt = 3; int keyboard_interrupt = 3;
#define L(LABEL) s_label(LABEL) #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[] = { Line program_asm[] = {
// clang-format off // clang-format off
s_nop(), s_nop(),
// set video character display flag // set video character display flag
s_or_r_i(Rfl, Rfl, 1 << Fl_Vcd), s_or_i(Rfl, Rfl, 1 << Fl_Vcd),
// print ABC // print ABC
s_mov8_mi_i(0x0c00 + 0, 'A'), s_mov8_mi_i(0x0c00 + 0, 'A'),
@ -418,18 +406,21 @@ int main(void)
// load interrupt table // load interrupt table
s_lit_l(interrupt_table), s_lit_l(interrupt_table),
// set interrupt flag // set interrupt flag
s_or_r_i(Rfl, Rfl, 1 << Fl_Int), s_or_i(Rfl, Rfl, 1 << Fl_Int),
L(main_loop), L(main_loop),
s_hlt(), s_hlt(),
s_jmp_l(main_loop), s_jmp_l(main_loop),
s_nop(),
L(interrupt_table), L(interrupt_table),
// size // size
s_data_i(1), s_data_i(1),
s_data_l(keyboard_interrupt), s_data_l(keyboard_interrupt),
s_nop(), s_nop(),
L(keyboard_interrupt), L(keyboard_interrupt),
s_nop(),
s_nop(),
// clear interrupt flag // 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 // setup stack frame
s_push_r(Rbp), s_push_r(Rbp),
s_mov16_r_r(Rbp, Rsp), s_mov16_r_r(Rbp, Rsp),
@ -438,14 +429,15 @@ int main(void)
// read keyboard port // read keyboard port
s_in_i(R0, 0), 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 // tear down frame
s_pop_r(R0), s_pop_r(R0),
s_mov16_r_r(Rsp, Rbp), s_mov16_r_r(Rsp, Rbp),
s_pop_r(Rbp), s_pop_r(Rbp),
// set interrupt flag // set interrupt flag
s_or_r_i(Rfl, Rfl, 1 << Fl_Int), s_or_i(Rfl, Rfl, 1 << Fl_Int),
// return from interrupt // return from interrupt
s_iret(), s_iret(),
@ -459,9 +451,17 @@ int main(void)
dump_program(program); dump_program(program);
/*return 0;*/
MemDrive drive; MemDrive drive;
memdrive_construct(&drive, (uint64_t*)program, 512); 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); vm_start(&drive.drive, &io_device.io_device);
sdldevice_destroy(&io_device); sdldevice_destroy(&io_device);

108
vm/vm.c
View File

@ -8,18 +8,19 @@ typedef struct {
uint16_t regs[10]; uint16_t regs[10];
uint8_t* mem; uint8_t* mem;
Drive* boot_drive; Drive* boot_drive;
int16_t seg_count; uint16_t seg_count;
int16_t seg_size; uint16_t seg_size;
IODevice* io_device; IODevice* io_device;
uint16_t int_table; uint16_t int_table;
int interrupt_timeout; int interrupt_timeout;
uint16_t keyboard_port_input; uint16_t keyboard_port_input;
} VM; } 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 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 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 Op ins_op(uint16_t ins); static inline Op ins_op(uint16_t ins);
static inline Reg ins_dst_reg(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_op1_or_imm(VM* vm, uint16_t ins);
static inline uint16_t ins_op2_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) void vm_start(Drive* boot_drive, IODevice* io_device)
{ {
const uint16_t seg_count = 16; const uint16_t seg_count = 16;
@ -47,7 +46,7 @@ void vm_start(Drive* boot_drive, IODevice* io_device)
.seg_size = seg_size, .seg_size = seg_size,
.io_device = io_device, .io_device = io_device,
.int_table = 0, .int_table = 0,
.interrupt_timeout = 0, .interrupt_timeout = 10,
.keyboard_port_input = 0, .keyboard_port_input = 0,
}; };
@ -67,10 +66,10 @@ void vm_start(Drive* boot_drive, IODevice* io_device)
uint16_t ins = eat_uint16(vm); uint16_t ins = eat_uint16(vm);
Op op = ins_op(ins); 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) { if (*rip >= 300) {
printf("rip >= 74\n"); printf("killed: rip >= 200\n");
exit(0); exit(0);
} }
@ -79,11 +78,12 @@ void vm_start(Drive* boot_drive, IODevice* io_device)
break; break;
case Op_Hlt: case Op_Hlt:
vm->io_device->wait_for_interrupt(vm->io_device); vm->io_device->wait_for_interrupt(vm->io_device);
vm->interrupt_timeout = 0;
break; break;
case Op_Jmp: { case Op_Jmp: {
bool is_farjump = ins >> 7 & 1; bool is_farjump = ins >> 7 & 1;
if (is_farjump) { 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); uint16_t op1 = ins_op1_or_imm(vm, ins);
*rcs = cs; *rcs = cs;
*rip = op1; *rip = op1;
@ -196,9 +196,8 @@ void vm_start(Drive* boot_drive, IODevice* io_device)
vm->regs[dst_reg] = vm->keyboard_port_input; vm->regs[dst_reg] = vm->keyboard_port_input;
break; break;
default: default:
fprintf(stderr, fprintf(
"warning: input, no device %d\n", stderr, "warning: no input device %d\n", device_id);
device_id);
break; break;
} }
break; break;
@ -210,7 +209,7 @@ void vm_start(Drive* boot_drive, IODevice* io_device)
switch (device_id) { switch (device_id) {
default: default:
fprintf(stderr, fprintf(stderr,
"warning: output, no device %d\n", "warning: no output device %d\n",
device_id); device_id);
break; break;
} }
@ -286,40 +285,6 @@ halt_execution:
return; 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) static inline void run_arithm_ins(VM* vm, uint16_t ins)
{ {
typedef uint16_t u; 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) static inline void maybe_update_vcd(VM* vm, uint16_t addr)
{ {
if (!vm->io_device) 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) static inline uint16_t eat_uint16(VM* vm)
{ {
uint16_t* rip = &vm->regs[Rip]; uint16_t* rip = &vm->regs[Rip];
uint16_t* rcs = &vm->regs[Rcs]; uint16_t ins = read_seg_uint16(vm, *rip);
uint16_t ins = *(uint16_t*)&vm->mem[*rcs * vm->seg_size + *rip];
*rip += 2; *rip += 2;
return ins; 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) static inline Op ins_op(uint16_t ins)
{ {
return ins & 0x3F; 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); 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) { switch (op) {
case Op_Nop: case Op_Nop:
@ -532,5 +534,5 @@ static inline const char* op_str(Op op)
case Op_RMod: case Op_RMod:
return "rmod"; return "rmod";
} }
return "<unknown>"; return "---";
} }

View File

@ -102,3 +102,5 @@ 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);