diff --git a/src/cpu.c b/src/cpu.c index 1b9ebec..24ff8f1 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -18,6 +18,8 @@ cpu * new_cpu() { m->l = new_lcd(); m->k = new_keys(); m->cycle = 0; + m->run_to_nop = false; + m->run_to_ret = 0; return m; } @@ -26,4 +28,4 @@ void destroy_cpu(cpu* m) { destroy_lcd(m->l); destroy_keys(m->k); free(m); -} \ No newline at end of file +} diff --git a/src/cpu.h b/src/cpu.h index 616e898..797ea12 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -24,9 +24,10 @@ #define EMU_FLAG_WAIT_FOR_INTERRUPT 0x02 #define CLOCK_SPRINT 0x00 -#define CLOCK_FAST 0x01 -#define CLOCK_SLOW 0x02 -#define CLOCK_STEP 0x04 +#define CLOCK_TURBO 0x01 +#define CLOCK_FAST 0x02 +#define CLOCK_SLOW 0x04 +#define CLOCK_STEP 0x08 typedef struct { // clock mode @@ -65,6 +66,12 @@ typedef struct { lcd* l; // keys keys* k; + // whether we should switch to clock mode STEP when the next NOP is encountered + bool run_to_nop; + // if >0, will be incremented/decremented when encountering JSR/RTS respectively and we'll switch to + // STEP when it's decremented to zero, allowing "run until return" + int run_to_ret; + } cpu; cpu * new_cpu(); diff --git a/src/gui.c b/src/gui.c index b20e91c..2501f51 100644 --- a/src/gui.c +++ b/src/gui.c @@ -170,6 +170,21 @@ void update_gui(cpu *m) { // start by populating the monitor mvwprintw(wnd_monitor_content, 0, 0, "PC: %04x, OP: %02x (%s)", m->pc_actual, m->opcode, translate_opcode(m->opcode)); + if (m->run_to_nop && m->opcode == 0xea) { + // 0xea is NOP - we use this as a breakpoint + m->clock_mode = CLOCK_STEP; + m->run_to_nop = false; + } else if (m->run_to_ret && m->opcode == 0x60) { + // 0x60 is RTS + m->run_to_ret--; + if (!m->run_to_ret) { + // We're returning from the frame where run-to-ret was requested + m->clock_mode = CLOCK_STEP; + } + } else if (m->run_to_ret && m->opcode == 0x20) { + // 0x20 is JSR. We want to see an additional return after this, then. + m->run_to_ret++; + } mvwprintw(wnd_monitor_content, 1, 0, "ACC: %02x, X: %02x, Y: %02x, SP: %02x", m->ac, m->x, m->y, m->sp); mvwprintw(wnd_monitor_content, 2, 0, "SR: %c%c-%c%c%c%c%c, cycle: %08x", m->sr & 0x80 ? 'N' : '-', @@ -180,7 +195,17 @@ void update_gui(cpu *m) { m->sr & 0x02 ? 'Z' : '-', m->sr & 0x01 ? 'C' : '-', m->cycle); - mvwprintw(wnd_monitor_content, 3, 0, "Clock mode: %s", m->clock_mode == CLOCK_FAST ? "FAST" : m->clock_mode == CLOCK_SLOW ? "SLOW" : "STEP"); + mvwprintw(wnd_monitor_content, 3, 0, "Clock mode: %s", m->clock_mode == CLOCK_TURBO ? "TURBO" : m->clock_mode == CLOCK_FAST ? "FAST " : m->clock_mode == CLOCK_SLOW ? "SLOW " : "STEP "); + if (m->run_to_nop) { + mvwprintw(wnd_monitor_content, 3, 18, "RTN"); + } else { + mvwprintw(wnd_monitor_content, 3, 18, " "); + } + if (m->run_to_ret) { + mvwprintw(wnd_monitor_content, 3, 22, "RTR %d", m->run_to_ret); + } else { + mvwprintw(wnd_monitor_content, 3, 22, " "); + } wrefresh(wnd_monitor_content); // populate memory monitor @@ -224,6 +249,11 @@ void update_gui(cpu *m) { switch (m->clock_mode) { case CLOCK_SPRINT: + case CLOCK_TURBO: + cbreak(); + read = getch(); + keep_going = true; + break; case CLOCK_FAST: halfdelay(1); read = getch(); @@ -260,6 +290,11 @@ void update_gui(cpu *m) { m->clock_mode = CLOCK_FAST; } break; + case KEY_F(9): // F9 + if (!(m->clock_mode == CLOCK_SPRINT)) { + m->clock_mode = CLOCK_TURBO; + } + break; case 10: m->k->key_enter = true; keep_going = true; @@ -304,7 +339,19 @@ void update_gui(cpu *m) { memory_start = 0xfe; } break; + case 'n': + if (!(m->clock_mode == CLOCK_SPRINT)) { + m->clock_mode = CLOCK_TURBO; + m->run_to_nop = true; + } + break; + case 'r': + if (!(m->clock_mode == CLOCK_SPRINT)) { + m->clock_mode = CLOCK_TURBO; + m->run_to_ret = 1; + } + break; } } } while (!keep_going && m->clock_mode != CLOCK_SPRINT); -} \ No newline at end of file +} diff --git a/src/lcd.c b/src/lcd.c index cb15637..a7f9089 100644 --- a/src/lcd.c +++ b/src/lcd.c @@ -33,6 +33,11 @@ void process_input(lcd* l, bool enable, bool rwb, bool data, uint8_t input) if (enable && !l->enable_latch) { // rising edge on enable l->enable_latch = true; trace_emu("LCD rising edge on enable\n"); + if (rwb && !data) { + // There's no command to check - this is read busy flag + trace_emu("LCD read busy\n"); + process_command(l, rwb, l->data); + } if (!l->initialized && !(input & 0xc0) && (input & CMD_FUNCTION_SET) && !rwb) { trace_emu("LCD initializing \n"); l->initialized = true; diff --git a/src/opcode_handlers/logical.h b/src/opcode_handlers/logical.h index 5747f38..c52007d 100644 --- a/src/opcode_handlers/logical.h +++ b/src/opcode_handlers/logical.h @@ -167,6 +167,13 @@ case BIT_ZP: set_flag(m, FLAG_NEGATIVE, t1 & 0x80); break; +case BIT_ZPX: + t1 = read_byte(m, ZP(NEXT_BYTE(m) + m->x)); //m->mem[ZP(NEXT_BYTE(m) + m->x)]; + set_flag(m, FLAG_ZERO, !(t1 & m->ac)); + set_flag(m, FLAG_OVERFLOW, t1 & 0x40); + set_flag(m, FLAG_NEGATIVE, t1 & 0x80); + break; + case RMB0: r1 = ZP(NEXT_BYTE(m)); //m->mem[r1] &= ~0x01; diff --git a/src/opcode_handlers/store.h b/src/opcode_handlers/store.h index a6aa83e..31f5ea0 100644 --- a/src/opcode_handlers/store.h +++ b/src/opcode_handlers/store.h @@ -54,7 +54,7 @@ case STA_INZP: case STX_ZP: r1 = ZP(NEXT_BYTE(m)); - write_byte(m, r1, m->ac); //m->mem[r1] = m->x; + write_byte(m, r1, m->x); //m->mem[r1] = m->x; mark_dirty(m, r1); break; diff --git a/src/opcodes.h b/src/opcodes.h index 537abd8..fae72d1 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -65,6 +65,7 @@ #define BIT_AB 0x2C #define BIT_ZP 0x24 +#define BIT_ZPX 0x34 #define BMI_REL 0x30 #define BNE_REL 0xD0