keyboard interrupts work
This commit is contained in:
parent
b74c99b05e
commit
ad79f82f1f
78
vm/asm.c
78
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 },
|
.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;
|
||||||
|
28
vm/asm.h
28
vm/asm.h
@ -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'
|
||||||
|
66
vm/main.c
66
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)
|
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
108
vm/vm.c
@ -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 "---";
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user