From 836a076d1c51e469d38a4953a2ee47651941e3c0 Mon Sep 17 00:00:00 2001 From: jborza Date: Sat, 4 May 2019 14:11:39 +0200 Subject: [PATCH] fixed PHP flag handling + test --- cpu.c | 50 +++++++++++++++++++++++++++++--------------------- emu6502.c | 17 +++++++++++++---- flags.h | 16 ++++++++-------- test6502.c | 26 +++++++++++++++++++++++--- 4 files changed, 73 insertions(+), 36 deletions(-) diff --git a/cpu.c b/cpu.c index 93d04e8..734ce71 100644 --- a/cpu.c +++ b/cpu.c @@ -30,9 +30,18 @@ void set_NZ_flags(State6502 * state, byte value) { state->flags.n = is_negative(value); } -byte flags_as_byte(State6502* state) { - byte flags_value; - memcpy(&flags_value, &state->flags, sizeof(Flags)); +byte flags_as_byte(State6502 * state) { + byte flags_value = 0; + flags_value |= state->flags.c << 0; + flags_value |= state->flags.z << 1; + flags_value |= state->flags.i << 2; + flags_value |= state->flags.d << 3; + //flag B is active with PHP + flags_value |= 1 << 4; + //unused bit is active with PHP + flags_value |= 1 << 5; + flags_value |= state->flags.v << 6; + flags_value |= state->flags.n << 7; return flags_value; } @@ -52,7 +61,7 @@ void clear_state(State6502 * state) { state->x = 0; state->y = 0; state->pc = 0; - state->sp = 0xFF; + state->sp = 0xFF; clear_flags(state); state->running = 1; } @@ -62,7 +71,7 @@ void push_byte_to_stack(State6502 * state, byte value) { state->memory[STACK_HOME + state->sp--] = value; } -void push_word_to_stack(State6502* state, word value) { +void push_word_to_stack(State6502 * state, word value) { push_byte_to_stack(state, (value >> 8) & 0xFF); push_byte_to_stack(state, value & 0xFF); } @@ -71,7 +80,7 @@ byte pop_byte_from_stack(State6502 * state) { return state->memory[STACK_HOME + ++(state->sp)]; } -word pop_word_from_stack(State6502* state) { +word pop_word_from_stack(State6502 * state) { byte low = pop_byte_from_stack(state); byte high = pop_byte_from_stack(state); return low + ((word)high << 8); @@ -274,12 +283,12 @@ void JSR(State6502 * state, word address) { state->pc = address; } -void RTS_(State6502* state) { +void RTS_(State6502 * state) { word address = pop_word_from_stack(state); state->pc = address + 1; } -void RTI_(State6502* state) { +void RTI_(State6502 * state) { //interrupt pushes PC first, then status register //RTI should pull status register and program counter from the stack byte sr = pop_byte_from_stack(state); @@ -287,60 +296,60 @@ void RTI_(State6502* state) { state->pc = address; } -void BEQ(State6502* state) { +void BEQ(State6502 * state) { word address = get_address_relative(state); if (state->flags.z) state->pc = address; } -void BNE(State6502* state) { +void BNE(State6502 * state) { word address = get_address_relative(state); if (!state->flags.z) state->pc = address; } -void BCC(State6502* state) { +void BCC(State6502 * state) { word address = get_address_relative(state); if (!state->flags.c) state->pc = address; } -void BCS(State6502* state) { +void BCS(State6502 * state) { word address = get_address_relative(state); if (state->flags.c) state->pc = address; } -void BMI(State6502* state) { +void BMI(State6502 * state) { word address = get_address_relative(state); if (state->flags.n) state->pc = address; } -void BPL(State6502* state) { +void BPL(State6502 * state) { word address = get_address_relative(state); if (!state->flags.n) state->pc = address; } -void BVS(State6502* state) { +void BVS(State6502 * state) { word address = get_address_relative(state); if (state->flags.v) state->pc = address; } -void BVC(State6502* state) { +void BVC(State6502 * state) { word address = get_address_relative(state); if (!state->flags.v) state->pc = address; } -void PLA_(State6502* state) { +void PLA_(State6502 * state) { state->a = pop_byte_from_stack(state); set_NZ_flags(state, state->a); } -void PLP_(State6502* state) { +void PLP_(State6502 * state) { byte value = pop_byte_from_stack(state); //we don't read the BRK flag value &= ~(1 << 4); @@ -349,9 +358,8 @@ void PLP_(State6502* state) { memset(&state->flags, value, sizeof(Flags)); } -void PHP_(State6502* state) { - byte flags_value; - memcpy(&flags_value, &state->flags, sizeof(Flags)); +void PHP_(State6502 * state) { + byte flags_value = flags_as_byte(state); push_byte_to_stack(state, flags_value); } diff --git a/emu6502.c b/emu6502.c index 8cb7abe..73d281e 100644 --- a/emu6502.c +++ b/emu6502.c @@ -22,12 +22,18 @@ byte* read_nestest() { int err = errno; exit(1); } - byte buffer[NESTEST_SIZE]; + static byte buffer[NESTEST_SIZE]; int read = fread(&buffer, sizeof(byte), NESTEST_SIZE, file); fclose(file); return buffer; } +byte debug_flags_as_byte(State6502* state) { + byte flags_value = 0; + memcpy(&flags_value, &state->flags, sizeof(Flags)); + return flags_value; +} + void run_nestest() { State6502 state; clear_state(&state); @@ -38,16 +44,19 @@ void run_nestest() { memcpy(state.memory + NESTEST_DST, bin, NESTEST_SIZE); memcpy(state.memory + 0x8000, bin, NESTEST_SIZE); state.pc = NESTEST_DST; + //a little cheat to simulate probably a JSR and SEI at the beginning + state.sp = 0xfd; + state.flags.i = 1; do{ char* dasm = disassemble_6502_to_string(state.memory, state.pc); - printf("%-50s A:%02X X:%02X Y:%02X P:%02X SP:%02X\n", dasm, state.a, state.x, state.y, flags_as_byte(&state), state.sp); + printf("%-50s A:%02X X:%02X Y:%02X P:%02X SP:%02X\n", dasm, state.a, state.x, state.y, debug_flags_as_byte(&state), state.sp); emulate_6502_op(&state); } while (state.flags.b != 1); } int main() { - //run_nestest(); - run_tests(); + run_nestest(); + //run_tests(); return 0; } \ No newline at end of file diff --git a/flags.h b/flags.h index 5187b75..01ccbb8 100644 --- a/flags.h +++ b/flags.h @@ -4,12 +4,12 @@ typedef struct Flags { //flags high to low: NV-BDIZC - uint8_t c : 1; //set if last operation caused an overflow from bit 7 of the result or an underflow from bit 0 - uint8_t z : 1; //set if the result of the last operation was zero - uint8_t i : 1; //set with SEI and cleared with CLI - uint8_t d : 1; //set with SEC and cleared with CLD - uint8_t b : 1; //set when BRK executed - uint8_t pad : 1; //not used - uint8_t v : 1; //if the result has yielded an invalid two's complement result - uint8_t n : 1; //set if the result of the last operation set bit 7 to one + uint8_t c : 1; //0 - set if last operation caused an overflow from bit 7 of the result or an underflow from bit 0 + uint8_t z : 1; //1 - set if the result of the last operation was zero + uint8_t i : 1; //2 - set with SEI and cleared with CLI + uint8_t d : 1; //3 - set with SEC and cleared with CLD + uint8_t b : 1; //4 - set when BRK executed + uint8_t pad : 1; //5 - not used + uint8_t v : 1; //6 - if the result has yielded an invalid two's complement result + uint8_t n : 1; //7 - set if the result of the last operation set bit 7 to one } Flags; \ No newline at end of file diff --git a/test6502.c b/test6502.c index 3832ea2..5ae2380 100644 --- a/test6502.c +++ b/test6502.c @@ -2001,7 +2001,6 @@ void test_PHP() { state.flags.d = 1; state.flags.i = 1; state.flags.v = 1; - state.sp = 0xFF; //arrange char program[] = { PHP }; @@ -2018,6 +2017,27 @@ void test_PHP() { test_cleanup(&state); } +void test_PLP_no_flags() { + //initialize + State6502 state = create_blank_state(); + //no flags are set + + //arrange + char program[] = { PHP }; + memcpy(state.memory, program, sizeof(program)); + + //act + test_step(&state); + + //assert + assert_sp(&state, 0xFE); + byte expected_value = (1 << 4) | (1 << 5); + assert_memory(&state, 0x1FF, expected_value); + + //cleanup + test_cleanup(&state); +} + void test_PLP() { State6502 state = create_blank_state(); state.sp = 0xFE; @@ -2051,7 +2071,7 @@ void test_PLP2() { //arrange char program[] = { PLP }; memcpy(state.memory, program, sizeof(program)); - state.memory[0x1FF] = 0x04; //all flags should be on + state.memory[0x1FF] = 0x04; //only flag i should be set //act test_step(&state); @@ -2494,7 +2514,7 @@ fp* tests_eor[] = { test_EOR_IMM, test_EOR_ZP, test_EOR_ZPX, test_EOR_ABS, test_ fp* tests_sta[] = { test_STA_ZP, test_STA_ZPX, test_STA_ABS, test_STA_ABSX, test_STA_ABSY, test_STA_INDX, test_STA_INDY }; fp* tests_pha_pla[] = { test_PHA, test_PLA, test_PLA_N, test_PLA_Z, test_PHA_PLA }; fp* tests_txs_tsx[] = { test_TXS, test_TSX, test_TXS_Z }; -fp* tests_php_plp[] = { test_PHP, test_PLP, test_PLP2 }; +fp* tests_php_plp[] = { test_PHP, test_PLP_no_flags, test_PLP, test_PLP2 }; fp* tests_jmp[] = { test_JMP, test_JMP_IND, test_JMP_IND_wrap }; fp* tests_cmp[] = { test_CMP_ABS_equal, test_CMP_ABS_greater, test_CMP_ABS_greater_2, test_CMP_ABS_less_than, test_CPX_ABS, test_CPY_ABS }; fp* tests_sbc[] = { test_SBC_IMM_multiple };