mirror of
https://github.com/jborza/emu6502.git
synced 2024-11-21 08:31:23 +00:00
fixed PHP flag handling + test
This commit is contained in:
parent
8754aaef9f
commit
836a076d1c
50
cpu.c
50
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);
|
||||
}
|
||||
|
||||
|
17
emu6502.c
17
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;
|
||||
}
|
16
flags.h
16
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;
|
26
test6502.c
26
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 };
|
||||
|
Loading…
Reference in New Issue
Block a user