diff --git a/emulator_shell.c b/emulator_shell.c index d2738f9..d0d32ee 100644 --- a/emulator_shell.c +++ b/emulator_shell.c @@ -6,6 +6,9 @@ // gcc emulator_shell.c `pkg-config --cflags --libs gtk+-3.0` -o emulator + +//===== GTK SETUP ===== + static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data) { switch (event->keyval) @@ -40,6 +43,62 @@ static gboolean on_key_release(GtkWidget *widget, GdkEventKey *event, gpointer u return FALSE; } +//===== EMULATOR SETUP ===== + +typedef struct ConditionCodes { + //bitfields for condition codes + //the number following the variables sets the number of bits + uint8_t z:1; + uint8_t s:1; + uint8_t p:1; + uint8_t cy:1; + uint8_t ac:1; + uint8_t pad:3; +} ConditionCodes; + + +typedef struct State8080 { + uint8_t a; + uint8_t b; + uint8_t c; + uint8_t d; + uint8_t e; + uint8_t h; + uint8_t l; + uint16_t sp; + uint16_t pc; + uint8_t *memory; + ConditionCodes cc; + uint8_t int_enable; + uint8_t shift_offset; + uint8_t shift0; + uint8_t shift1; +} State8080; + +unsigned char cycles8080[] = { + 4, 10, 7, 5, 5, 5, 7, 4, 4, 10, 7, 5, 5, 5, 7, 4, //0x00..0x0f + 4, 10, 7, 5, 5, 5, 7, 4, 4, 10, 7, 5, 5, 5, 7, 4, //0x10..0x1f + 4, 10, 16, 5, 5, 5, 7, 4, 4, 10, 16, 5, 5, 5, 7, 4, //etc + 4, 10, 13, 5, 10, 10, 10, 4, 4, 10, 13, 5, 5, 5, 7, 4, + + 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5, //0x40..0x4f + 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5, + 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5, + 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 5, + + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, //0x80..8x4f + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, + + 11, 10, 10, 10, 17, 11, 7, 11, 11, 10, 10, 10, 10, 17, 7, 11, //0xc0..0xcf + 11, 10, 10, 10, 17, 11, 7, 11, 11, 10, 10, 10, 10, 17, 7, 11, + 11, 10, 10, 18, 17, 11, 7, 11, 11, 5, 10, 5, 17, 17, 7, 11, + 11, 10, 10, 4, 17, 11, 7, 11, 11, 5, 10, 4, 17, 17, 7, 11, +}; + +//===== EMULATOR FUNCTIONS ===== + int disassemble8080(unsigned char* code) { int opbytes = 1; switch (*code) { @@ -338,39 +397,6 @@ int disassemble8080(unsigned char* code) { } -// ================= EMULATOR CODE ====================== - - -typedef struct ConditionCodes { - //bitfields for condition codes - //the number following the variables sets the number of bits - uint8_t z:1; - uint8_t s:1; - uint8_t p:1; - uint8_t cy:1; - uint8_t ac:1; - uint8_t pad:3; -} ConditionCodes; - - -typedef struct State8080 { - uint8_t a; - uint8_t b; - uint8_t c; - uint8_t d; - uint8_t e; - uint8_t h; - uint8_t l; - uint16_t sp; - uint16_t pc; - uint8_t *memory; - ConditionCodes cc; - uint8_t int_enable; - uint8_t shift_offset; - uint8_t shift0; - uint8_t shift1; -} State8080; - void unknownInstruction(State8080* state) { printf("Error: Unknown instruction"); return exit(1); @@ -400,6 +426,12 @@ void printState(State8080* state) { uint8_t machineIn(State8080* state, uint8_t port) { uint8_t a; switch(port) { + case 0: + a = 1; + break; + case 2: + a = 0; + break; case 3: { uint16_t v = (state->shift1<<8) | (state->shift0); @@ -410,7 +442,7 @@ uint8_t machineIn(State8080* state, uint8_t port) { return a; } -uint8_t machineOut(State8080* state, uint8_t port, uint8_t value) { +void machineOut(State8080* state, uint8_t port, uint8_t value) { switch(port) { case 2: { @@ -536,6 +568,19 @@ int emulate8080(State8080* state) { state->pc++; } break; + case 0x27: // DAA + { + if ((state->a & 0x0f) > 9) { + state->a += 6; + } else if ((state->a & 0xf0) > 0x90) { + uint16_t res = (uint16_t) state->a + 0x60; + state->a = res & 0xff; + state->cc.cy = (res > 0xff); + state->cc.z = ((res & 0xff) == 0); + state->cc.s = (0x80 == (res & 0x80)); + state->cc.p = parity((res & 0xff), 8); + } + } case 0x29: // DAD H { uint32_t hl = (state->h << 8) | state->l; @@ -814,14 +859,17 @@ int emulate8080(State8080* state) { printState(state); } - void GenerateInterrupt(State8080* state, int interrupt_num) + void generateInterrupt(State8080* state, int interrupt_num) { - //perform "PUSH PC" - Push(state, (state->pc & 0xFF00) >> 8, (state->pc & 0xff)); + //perform "PUSH PC" + state->memory[state->sp-1] = ((state->pc & 0xFF00) >> 8); + state->memory[state->sp-2] = (state->pc & 0xff); + state->sp -= 2; //Set the PC to the low memory vector. - //This is identical to an "RST interrupt_num" instruction. - state->pc = 8 * interrupt_num; + + state->pc = 8 * interrupt_num; + state->int_enable = 0; } @@ -845,6 +893,8 @@ void read_Space_Invaders_ROM(State8080* state, const char* filename, int offset) int main (int argc, char *argv[]) { + + // GTK INIT gtk_init(&argc, &argv); GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_print("Test\n"); @@ -853,10 +903,9 @@ int main (int argc, char *argv[]) { gtk_widget_show(window); - //Initializations + // EMULATOR INIT - State8080 *state = (State8080*) calloc(1, sizeof(State8080)); - //memset(state, 0, sizeof(State8080)); + State8080 *state = (State8080*) calloc(1, sizeof(State8080)); //memset obsolte with calloc state->cc.z = 1; state->cc.s = 1; state->cc.p = 1; @@ -877,6 +926,17 @@ int main (int argc, char *argv[]) { emulate8080(state); i++; sleep(0.00001); + if ( time() - lastInterrupt > 1.0/60.0) //1/60 second has elapsed + { + //only do an interrupt if they are enabled + if (state->int_enable) + { + GenerateInterrupt(state, 2); //interrupt 2 + + //Save the time we did this + lastInterrupt = time(); + } + } } gtk_main(); free(state->memory);