From 655ee84ba2304b2fe85b28290580338d29a68c3c Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Sat, 5 Dec 2020 20:25:38 +0100 Subject: - have some emulation modes for single stepping, breaking, changing emulation speed - started to make a better CPU state output with opcode mnemonics --- emu/6502.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++----- emu/6502.h | 11 ++++++++-- emu/emu.c | 4 ++++ emu/emul.c | 55 ++++++++++++++++++++++++++++++++++++++++------- emu/emul.h | 2 ++ emu/options.ggo | 6 +++++- emu/options.ggo.in | 6 +++++- 7 files changed, 130 insertions(+), 17 deletions(-) (limited to 'emu') diff --git a/emu/6502.c b/emu/6502.c index 877f3f5..c52373f 100644 --- a/emu/6502.c +++ b/emu/6502.c @@ -150,10 +150,62 @@ static bool is_carry( cpu_6502_t *cpu ) { return cpu->PS & PS_C; } + +static const char mnemonic[NOF_OPCODES][MAX_MENMONIC_LENGTH] = { + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /* 0 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", + /* 1 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", + /* 2 */ "JSR", "???", "???", "???", "???", "???", "???", "???", "???", "???", "ROL", "???", "???", "???", "???", "???", + /* 3 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", + /* 4 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "JMP", "???", "???", "???", + /* 5 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", + /* 6 */ "RTS", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", + /* 7 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", + /* 8 */ "???", "???", "???", "???", "???", "???", "STX", "???", "DEY", "???", "???", "???", "???", "???", "STX", "???", + /* 9 */ "BCC", "???", "???", "???", "???", "???", "???", "???", "???", "???", "TXS", "???", "???", "???", "???", "???", + /* A */ "LDY", "???", "LDX", "???", "LDY", "LDA", "LDX", "???", "???", "LDA", "???", "???", "???", "???", "???", "???", + /* B */ "BCS", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", + /* C */ "???", "???", "???", "???", "???", "???", "???", "???", "INY", "???", "DEX", "???", "???", "???", "???", "???", + /* D */ "BNE", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", + /* E */ "CPX", "???", "???", "???", "???", "???", "INC", "???", "???", "SBC", "NOP", "???", "???", "???", "???", "???", + /* F */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???" + +/* + "BRK", "ORA", "" , "", "TSB", "ORA", "ASL", "RMB0", "PHP", "ORA", "ASL", "" , "TSB", "ORA", "ASL", "BBR0", + "BPL", "ORA", "ORA", "", "TRB", "ORA", "ASL", "RMB1", "CLC", "ORA", "INC", "" , "TRB", "ORA", "ASL", "BBR1", + "JSR", "AND", "" , "", "BIT", "AND", "ROL", "RMB2", "PLP", "AND", "ROL", "" , "BIT", "AND", "ROL", "BBR2", + "BMI", "AND", "AND", "", "BIT", "AND", "ROL", "RMB3", "SEC", "AND", "DEC", "" , "BIT", "AND", "ROL", "BBR3", + "RTI", "EOR", "" , "", "" , "EOR", "LSR", "RMB4", "PHA", "EOR", "LSR", "" , "JMP", "EOR", "LSR", "BBR4", + "BVC", "EOR", "EOR", "", "" , "EOR", "LSR", "RMB5", "CLI", "EOR", "PHY", "" , "" , "EOR", "LSR", "BBR5", + "RTS", "ADC", "" , "", "STZ", "ADC", "ROR", "RMB6", "PLA", "ADC", "ROR", "" , "JMP", "ADC", "ROR", "BBR6", + "BVS", "ADC", "ADC", "", "STZ", "ADC", "ROR", "RMB7", "SEI", "ADC", "PLY", "" , "JMP", "ADC", "ROR", "BBR7", + "BRA", "STA", "" , "", "STY", "STA", "STX", "SMB0", "DEY", "BIT", "TXA", "" , "STY", "STA", "STX", "BBS0", + "BCC", "STA", "STA", "", "STY", "STA", "STX", "SMB1", "TYA", "STA", "TXS", "" , "STZ", "STA", "STZ", "BBS1", + "LDY", "LDA", "LDX", "", "LDY", "LDA", "LDX", "SMB2", "TAY", "LDA", "TAX", "" , "LDY", "LDA", "LDX", "BBS2", + "BCS", "LDA", "LDA", "", "LDY", "LDA", "LDX", "SMB3", "CLV", "LDA", "TSX", "" , "LDY", "LDA", "LDX", "BBS3", + "CPY", "CMP", "" , "", "CPY", "CMP", "DEC", "SMB4", "INY", "CMP", "DEX", "WAI", "CPY", "CMP", "DEC", "BBS4", + "BNE", "CMP", "CMP", "", "" , "CMP", "DEC", "SMB5", "CLD", "CMP", "PHX", "STP", "" , "CMP", "DEC", "BBS5", + "CPX", "SBC", "" , "", "CPX", "SBC", "INC", "SMB6", "INX", "SBC", "NOP", "" , "CPX", "SBC", "INC", "BBS6", + "BEQ", "SBC", "SBC", "", "" , "SBC", "INC", "SMB7", "SED", "SBC", "PLX", "" , "" , "SBC", "INC", "BBS7" +*/ +}; + +void cpu_6502_get_opcode_mnemonic( cpu_6502_t *cpu, char *buf, int buflen, uint16_t addr ) +{ + uint8_t opcode; + + opcode = cpu_6502_read_byte( cpu, addr ); -void cpu_6502_print_state( cpu_6502_t *cpu, uint8_t opcode ) + snprintf( buf, buflen, "%s (%02X)", mnemonic[opcode], opcode ); +} + +void cpu_6502_print_state( cpu_6502_t *cpu, uint16_t addr ) { - fprintf( stderr, "PC: %04X SP: 01%02X PS: %02X %c%c-%c%c%c%c%c A: %02X X: %02X Y: %02X OP: %02X steps: %d\n", + char opcode_str[MAX_OPCODE_MNEMONIC_STRING_LENGTH]; + + cpu_6502_get_opcode_mnemonic( cpu, opcode_str, MAX_OPCODE_MNEMONIC_STRING_LENGTH, addr ); + + fprintf( stderr, "PC: %04X SP: 01%02X PS: %02X %c%c-%c%c%c%c%c A: %02X X: %02X Y: %02X steps: %d OP: %s\n", cpu->PC, cpu->SP, cpu->PS, is_negative( cpu ) ? 'N' : 'n', is_overflow( cpu ) ? 'V' : 'v', @@ -162,7 +214,8 @@ void cpu_6502_print_state( cpu_6502_t *cpu, uint8_t opcode ) is_interrupt( cpu ) ? 'I' : 'i', is_zero( cpu ) ? 'Z' : 'z', is_carry( cpu ) ? 'C' : 'c', - cpu->A, cpu->X, cpu->Y, opcode, cpu->steps ); + cpu->A, cpu->X, cpu->Y, cpu->steps, + opcode_str ); } static void update_negative_and_sign( cpu_6502_t *cpu, uint8_t x ) @@ -200,7 +253,7 @@ void cpu_6502_step( cpu_6502_t *cpu ) cpu->PC++; if( cpu->debug_flags & DEBUG_STATUS ) { - cpu_6502_print_state( cpu, opcode ); + cpu_6502_print_state( cpu, cpu->PC-1 ); } if( cpu->debug_flags & DEBUG_STACK ) { cpu_6502_print_stack( cpu ); @@ -279,7 +332,7 @@ void cpu_6502_step( cpu_6502_t *cpu ) update_negative_and_sign( cpu, cpu->Y ); break; - case INC_IMPL: + case INC_ZERO: operand8 = cpu_6502_read_byte( cpu, cpu->PC ); cpu->PC++; tmp = cpu_6502_read_byte( cpu, operand8 ); diff --git a/emu/6502.h b/emu/6502.h index bfc8314..1880c90 100644 --- a/emu/6502.h +++ b/emu/6502.h @@ -53,7 +53,7 @@ enum { DEX_IMPL = 0xCA, DEY_IMPL = 0x88, INY_IMPL = 0xC8, - INC_IMPL = 0xE6, + INC_ZERO = 0xE6, ROL_ACC = 0x2A, BNE_REL = 0xD0, BCC_REL = 0x90, @@ -67,6 +67,12 @@ enum { NOP_IMPL = 0xEA }; +enum { + MAX_OPCODE_MNEMONIC_STRING_LENGTH = 20, + MAX_MENMONIC_LENGTH = 5, + NOF_OPCODES = 256 +}; + void cpu_6502_init( cpu_6502_t *cpu, bus_t *bus, bool initialize ); void cpu_6502_reset( cpu_6502_t *cpu ); uint8_t cpu_6502_read_byte( cpu_6502_t *cpu, uint16_t addr ); @@ -78,7 +84,8 @@ uint8_t cpu_6502_pop_byte( cpu_6502_t *cpu ); uint16_t cpu_6502_pop_word( cpu_6502_t *cpu ); void cpu_6502_run( cpu_6502_t *cpu, int steps ); void cpu_6502_step( cpu_6502_t *cpu ); -void cpu_6502_print_state( cpu_6502_t *cpu, uint8_t opcode ); +void cpu_6502_get_opcode_mnemonic( cpu_6502_t *cpu, char *buf, int buflen, uint16_t addr ); +void cpu_6502_print_state( cpu_6502_t *cpu, uint16_t addr ); void cpu_6502_print_memory( cpu_6502_t *cpu, uint16_t base, uint8_t size ); void cpu_6502_print_stack( cpu_6502_t *cpu ); void cpu_6502_print_zerop_page( cpu_6502_t *cpu ); diff --git a/emu/emu.c b/emu/emu.c index 539c89b..421d4cc 100644 --- a/emu/emu.c +++ b/emu/emu.c @@ -73,6 +73,10 @@ int main( int argc, char *argv[] ) if( args_info.debug_given ) { emul.debug = true; } + if( args_info.start_paused_given ) { + emul.paused = true; + emul.speed = 25; + } emul_start( &emul ); cpu_6502_reset( &cpu ); diff --git a/emu/emul.c b/emu/emul.c index bf64d13..0399d33 100644 --- a/emu/emul.c +++ b/emu/emul.c @@ -11,6 +11,8 @@ void emul_init( emul_t *emul, cpu_6502_t *cpu, bus_t *bus, int width, int height emul->width = width; emul->height = height; emul->debug = false; + emul->paused = false; + emul->speed = CPU_FREQUENCY; } void emul_start( emul_t *emul ) @@ -78,31 +80,68 @@ void emul_run( emul_t *emul, int nof_steps ) if( emul->gui ) { SDL_Event event; bool done = false; + + if( emul->paused ) { + fprintf( stderr, "CPU is paused, press\n" + "(s) for single step\n" + "(c) for continue running\n" + "(b) break to single stepping\n" + "(+) speed up\n" + "(-) speed down\n" + "(q) or (ESC) for shutting down\n" ); + } + while( !done ) { uint32_t frame_start = SDL_GetTicks( ); - + SDL_PollEvent( &event ); switch( event.type ) { case SDL_KEYDOWN: switch( event.key.keysym.sym ) { case SDLK_ESCAPE: + case SDLK_q: done = true; break; + case SDLK_c: + fprintf( stderr, "continuing at normal speed %1.6f MHz\n", ( (double)emul->speed / 1000000 ) ); + emul->paused = false; + break; + case SDLK_b: + fprintf( stderr, "CPU paused (in single step mode)\n" ); + emul->paused = true; + break; + case SDLK_s: + cpu_6502_run( emul->cpu, 1 ); + break; + case SDLK_PLUS: + case SDLK_KP_PLUS: + emul->speed *= 10; + if( emul->speed > CPU_FREQUENCY ) { + emul->speed = CPU_FREQUENCY; + } + fprintf( stderr, "CPU speed is %1.6f MHz now\n", ( (double)emul->speed / 1000000 ) ); + break; + case SDLK_MINUS: + case SDLK_KP_MINUS: + emul->speed /= 10; + if( emul->speed < 25 ) { + emul->speed = 25; + } + fprintf( stderr, "CPU speed is %1.6f MHz now\n", ( (double)emul->speed / 1000000 ) ); + break; } break; - + case SDL_QUIT: done = true; - break; + break; } - cpu_6502_run( emul->cpu, CPU_FREQUENCY / DISPLAY_FPS ); - - if( emul->debug ) { - cpu_6502_print_state( emul->cpu, 0 ); + if( !emul->paused ) { + cpu_6502_run( emul->cpu, emul->speed / DISPLAY_FPS ); } - + SDL_RenderCopy( emul->renderer, emul->background_texture, NULL, NULL ); for( int i = 0; i < emul->bus->nof_devices; i++ ) { diff --git a/emu/emul.h b/emu/emul.h index a0e6b5f..fa443a0 100644 --- a/emu/emul.h +++ b/emu/emul.h @@ -34,6 +34,8 @@ typedef struct emul_t { int width; int height; bool debug; + bool paused; + int speed; #ifdef WITH_GUI SDL_Window *window; SDL_Renderer *renderer; diff --git a/emu/options.ggo b/emu/options.ggo index 5a93897..90bb5c1 100644 --- a/emu/options.ggo +++ b/emu/options.ggo @@ -51,7 +51,7 @@ section "Debug Options" option "print-7seg" - "Print what the 7-segment display on the VIA is doing" optional - + section "GUI Options" option "width" - @@ -65,3 +65,7 @@ section "GUI Options" int typestr="pixel" default="250" optional + + option "start-paused" - + "Start the CPU in paused mode" + optional diff --git a/emu/options.ggo.in b/emu/options.ggo.in index 9e54009..ccec63e 100644 --- a/emu/options.ggo.in +++ b/emu/options.ggo.in @@ -51,7 +51,7 @@ section "Debug Options" option "print-7seg" - "Print what the 7-segment display on the VIA is doing" optional - + section "GUI Options" option "width" - @@ -65,3 +65,7 @@ section "GUI Options" int typestr="pixel" default="250" optional + + option "start-paused" - + "Start the CPU in paused mode" + optional -- cgit v1.2.3-54-g00ecf