fixed PHP flag handling + test

This commit is contained in:
jborza 2019-05-04 14:11:39 +02:00
parent 8754aaef9f
commit 836a076d1c
4 changed files with 73 additions and 36 deletions

50
cpu.c
View File

@ -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);
}

View File

@ -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;
}

16
flags.h
View File

@ -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;

View File

@ -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 };