1
0
mirror of https://github.com/jborza/emu6502.git synced 2024-06-01 04:41:41 +00:00

fixed zero flag handling in LDA, LDX, LDY

added BEQ+test
split memory function to a separate module
This commit is contained in:
jborza 2019-04-27 12:43:15 +02:00
parent 7b0a3a0de9
commit 2ddcf62212
6 changed files with 254 additions and 115 deletions

120
cpu.c
View File

@ -1,6 +1,7 @@
#include "state.h" #include "state.h"
#include "cpu.h" #include "cpu.h"
#include "opcodes.h" #include "opcodes.h"
#include "memory.h"
#include <stdio.h> #include <stdio.h>
#include <memory.h> #include <memory.h>
#include <stdlib.h> #include <stdlib.h>
@ -93,17 +94,17 @@ void AND(State6502 * state, byte operand) {
//load accumulator //load accumulator
void LDA(State6502 * state, byte operand) { void LDA(State6502 * state, byte operand) {
state->a = operand; state->a = operand;
set_NV_flags(state, state->a); set_NZ_flags(state, state->a);
} }
void LDX(State6502 * state, byte operand) { void LDX(State6502 * state, byte operand) {
state->x = operand; state->x = operand;
set_NV_flags(state, state->x); set_NZ_flags(state, state->x);
} }
void LDY(State6502 * state, byte operand) { void LDY(State6502 * state, byte operand) {
state->y = operand; state->y = operand;
set_NV_flags(state, state->y); set_NZ_flags(state, state->y);
} }
void STA(State6502 * state, word address) { void STA(State6502 * state, word address) {
@ -278,6 +279,12 @@ void RTS_(State6502* state) {
state->pc = address + 1; state->pc = address + 1;
} }
void BEQ(State6502* state) {
word address = get_address_relative(state);
if (state->flags.z)
state->pc = address;
}
word pop_word(State6502 * state) { word pop_word(State6502 * state) {
byte low = pop_byte(state); byte low = pop_byte(state);
byte high = pop_byte(state); byte high = pop_byte(state);
@ -285,111 +292,6 @@ word pop_word(State6502 * state) {
return result; return result;
} }
word read_word(State6502 * state, word address) {
return state->memory[address] | state->memory[address + 1] << 8;
}
word get_address_zero_page(State6502 * state) {
return pop_byte(state);
}
byte get_byte_zero_page(State6502 * state) {
//8 bit addressing, only the first 256 bytes of the memory
return state->memory[get_address_zero_page(state)];
}
word get_address_zero_page_x(State6502 * state) {
//address is zero page, so wraparound byte
byte address = pop_byte(state) + state->x;
return address;
}
byte get_byte_zero_page_x(State6502 * state) {
return state->memory[get_address_zero_page_x(state)];
}
word get_address_zero_page_y(State6502 * state) {
//address is zero page, so wraparound byte
byte address = pop_byte(state) + state->y;
return address;
}
byte get_byte_zero_page_y(State6502 * state) {
return state->memory[get_address_zero_page_y(state)];
}
word get_address_absolute(State6502 * state) {
//absolute indexed, 16 bits
word address = pop_word(state);
return address;
}
byte get_byte_absolute(State6502 * state)
{
//absolute indexed, 16 bits
return state->memory[get_address_absolute(state)];
}
word get_address_absolute_x(State6502 * state) {
//absolute added with the contents of x register
word address = pop_word(state) + state->x;
return address;
}
byte get_byte_absolute_x(State6502 * state) {
return state->memory[get_address_absolute_x(state)];
}
word get_address_absolute_y(State6502 * state) {
//absolute added with the contents of x register
word address = pop_word(state) + state->y;
return address;
}
byte get_byte_absolute_y(State6502 * state) {
//absolute added with the contents of y register
return state->memory[get_address_absolute_y(state)];
}
word get_address_indirect_jmp(State6502 * state) {
//AN INDIRECT JUMP MUST NEVER USE A VECTOR BEGINNING ON THE LAST BYTE OF A PAGE
word indirect_address = pop_word(state);
if ((indirect_address & 0xFF) == 0xFF) {
//avoid crossing the page boundary
return state->memory[indirect_address] | state->memory[indirect_address - 0xFF] << 8;
}
else {
return read_word(state, indirect_address);
}
}
word get_address_indirect_x(State6502 * state) {
//pre-indexed indirect with the X register
//zero-page address is added to x register
byte indirect_address = pop_byte(state) + state->x;
//pointing to address of a word holding the address of the operand
word address = read_word(state, indirect_address);
return address;
}
byte get_byte_indirect_x(State6502 * state) {
//pre-indexed indirect with the X register
return state->memory[get_address_indirect_x(state)];
}
word get_address_indirect_y(State6502 * state) {
//post-indexed indirect
//zero-page address as an argument
byte indirect_address = pop_byte(state);
//the address and the following byte is read as a word, adding Y register
word address = read_word(state, indirect_address) + state->y;
return address;
}
byte get_byte_indirect_y(State6502 * state) {
return state->memory[get_address_indirect_y(state)];
}
int emulate_6502_op(State6502 * state) { int emulate_6502_op(State6502 * state) {
byte* opcode = &state->memory[state->pc++]; byte* opcode = &state->memory[state->pc++];
switch (*opcode) { switch (*opcode) {
@ -416,7 +318,7 @@ int emulate_6502_op(State6502 * state) {
case ASL_ABSX: ASL_MEM(state, get_address_absolute_x(state)); break; case ASL_ABSX: ASL_MEM(state, get_address_absolute_x(state)); break;
case BCC_REL: unimplemented_instruction(state); break; case BCC_REL: unimplemented_instruction(state); break;
case BCS_REL: unimplemented_instruction(state); break; case BCS_REL: unimplemented_instruction(state); break;
case BEQ_REL: unimplemented_instruction(state); break; case BEQ_REL: BEQ(state); break;
case BMI_REL: unimplemented_instruction(state); break; case BMI_REL: unimplemented_instruction(state); break;
case BNE_REL: unimplemented_instruction(state); break; case BNE_REL: unimplemented_instruction(state); break;
case BPL_REL: unimplemented_instruction(state); break; case BPL_REL: unimplemented_instruction(state); break;

View File

@ -154,12 +154,14 @@
<ClCompile Include="cpu.c" /> <ClCompile Include="cpu.c" />
<ClCompile Include="disassembler.c" /> <ClCompile Include="disassembler.c" />
<ClCompile Include="emu6502.c" /> <ClCompile Include="emu6502.c" />
<ClCompile Include="memory.c" />
<ClCompile Include="test6502.c" /> <ClCompile Include="test6502.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="cpu.h" /> <ClInclude Include="cpu.h" />
<ClInclude Include="disassembler.h" /> <ClInclude Include="disassembler.h" />
<ClInclude Include="flags.h" /> <ClInclude Include="flags.h" />
<ClInclude Include="memory.h" />
<ClInclude Include="opcodes.h" /> <ClInclude Include="opcodes.h" />
<ClInclude Include="state.h" /> <ClInclude Include="state.h" />
<ClInclude Include="test6502.h" /> <ClInclude Include="test6502.h" />

111
memory.c Normal file
View File

@ -0,0 +1,111 @@
#include "memory.h"
word read_word(State6502* state, word address) {
return state->memory[address] | state->memory[address + 1] << 8;
}
word get_address_zero_page(State6502* state) {
return pop_byte(state);
}
byte get_byte_zero_page(State6502* state) {
//8 bit addressing, only the first 256 bytes of the memory
return state->memory[get_address_zero_page(state)];
}
word get_address_zero_page_x(State6502* state) {
//address is zero page, so wraparound byte
byte address = pop_byte(state) + state->x;
return address;
}
byte get_byte_zero_page_x(State6502* state) {
return state->memory[get_address_zero_page_x(state)];
}
word get_address_zero_page_y(State6502* state) {
//address is zero page, so wraparound byte
byte address = pop_byte(state) + state->y;
return address;
}
byte get_byte_zero_page_y(State6502* state) {
return state->memory[get_address_zero_page_y(state)];
}
word get_address_absolute(State6502* state) {
//absolute indexed, 16 bits
word address = pop_word(state);
return address;
}
byte get_byte_absolute(State6502* state)
{
//absolute indexed, 16 bits
return state->memory[get_address_absolute(state)];
}
word get_address_absolute_x(State6502* state) {
//absolute added with the contents of x register
word address = pop_word(state) + state->x;
return address;
}
byte get_byte_absolute_x(State6502* state) {
return state->memory[get_address_absolute_x(state)];
}
word get_address_absolute_y(State6502* state) {
//absolute added with the contents of x register
word address = pop_word(state) + state->y;
return address;
}
byte get_byte_absolute_y(State6502* state) {
//absolute added with the contents of y register
return state->memory[get_address_absolute_y(state)];
}
word get_address_indirect_jmp(State6502* state) {
//AN INDIRECT JUMP MUST NEVER USE A VECTOR BEGINNING ON THE LAST BYTE OF A PAGE
word indirect_address = pop_word(state);
if ((indirect_address & 0xFF) == 0xFF) {
//avoid crossing the page boundary
return state->memory[indirect_address] | state->memory[indirect_address - 0xFF] << 8;
}
else {
return read_word(state, indirect_address);
}
}
word get_address_indirect_x(State6502* state) {
//pre-indexed indirect with the X register
//zero-page address is added to x register
byte indirect_address = pop_byte(state) + state->x;
//pointing to address of a word holding the address of the operand
word address = read_word(state, indirect_address);
return address;
}
byte get_byte_indirect_x(State6502* state) {
//pre-indexed indirect with the X register
return state->memory[get_address_indirect_x(state)];
}
word get_address_indirect_y(State6502* state) {
//post-indexed indirect
//zero-page address as an argument
byte indirect_address = pop_byte(state);
//the address and the following byte is read as a word, adding Y register
word address = read_word(state, indirect_address) + state->y;
return address;
}
byte get_byte_indirect_y(State6502* state) {
return state->memory[get_address_indirect_y(state)];
}
word get_address_relative(State6502* state) {
int8_t address = (int8_t)pop_byte(state);
return state->pc + address;
}

40
memory.h Normal file
View File

@ -0,0 +1,40 @@
#pragma once
#include "state.h"
word read_word(State6502* state, word address);
word get_address_zero_page(State6502* state);
byte get_byte_zero_page(State6502* state);
word get_address_zero_page_x(State6502* state);
byte get_byte_zero_page_x(State6502* state);
word get_address_zero_page_y(State6502* state);
byte get_byte_zero_page_y(State6502* state);
word get_address_absolute(State6502* state);
byte get_byte_absolute(State6502* state);
word get_address_absolute_x(State6502* state);
byte get_byte_absolute_x(State6502* state);
word get_address_absolute_y(State6502* state);
byte get_byte_absolute_y(State6502* state);
word get_address_indirect_jmp(State6502* state);
word get_address_indirect_x(State6502* state);
byte get_byte_indirect_x(State6502* state);
word get_address_indirect_y(State6502* state);
byte get_byte_indirect_y(State6502* state);
word get_address_relative(State6502* state);

View File

@ -163,10 +163,30 @@ void test_LDA_IMM() {
//assert //assert
assertA(&state, 0xAA); assertA(&state, 0xAA);
assert_flag_n(&state, 1);
test_cleanup(&state); test_cleanup(&state);
} }
void test_LDA_IMM_zero() {
//initialize
State6502 state = create_blank_state();
//arrange
char program[] = { LDA_IMM, 0x00 };
memcpy(state.memory, program, sizeof(program));
//act
test_step(&state);
//assert
assertA(&state, 0x00);
assert_flag_z(&state, 1);
test_cleanup(&state);
}
void test_LDA_ZP() { void test_LDA_ZP() {
//initialize //initialize
State6502 state = create_blank_state(); State6502 state = create_blank_state();
@ -843,6 +863,25 @@ void test_LDX_IMM() {
//assert //assert
assertX(&state, 0xAA); assertX(&state, 0xAA);
assert_flag_n(&state, 1);
test_cleanup(&state);
}
void test_LDX_IMM_zero() {
//initialize
State6502 state = create_blank_state();
//arrange
char program[] = { LDX_IMM, 0x00 }; //LDX #$AA
memcpy(state.memory, program, sizeof(program));
//act
test_step(&state);
//assert
assertX(&state, 0x00);
assert_flag_z(&state, 1);
test_cleanup(&state); test_cleanup(&state);
} }
@ -938,6 +977,25 @@ void test_LDY_IMM() {
//assert //assert
assertY(&state, 0xAA); assertY(&state, 0xAA);
assert_flag_n(&state, 1);
test_cleanup(&state);
}
void test_LDY_IMM_zero() {
//initialize
State6502 state = create_blank_state();
//arrange
char program[] = { LDY_IMM, 0x00 };
memcpy(state.memory, program, sizeof(program));
//act
test_step(&state);
//assert
assertY(&state, 0x00);
assert_flag_z(&state, 1);
test_cleanup(&state); test_cleanup(&state);
} }
@ -2203,14 +2261,38 @@ void test_BRK() {
assert_flag_b(&state, 1); assert_flag_b(&state, 1);
} }
//BEQ, BCC, ...
void test_BEQ() {
State6502 state = create_blank_state();
char program[] = { LDX_IMM, 0x00, BEQ_REL, 0xFC };
memcpy(state.memory, program, sizeof(program));
//act
test_step(&state);
test_step(&state);
//assert
assert_pc(&state, 0x00);
}
void test_BEQ_skip() {
State6502 state = create_blank_state();
char program[] = { LDX_IMM, 0x01, BEQ_REL, 0xFC };
memcpy(state.memory, program, sizeof(program));
//act
test_step(&state);
test_step(&state);
//assert
assert_pc(&state, 0x04);
}
///////////////////// /////////////////////
typedef void fp(); typedef void fp();
fp* tests_lda[] = { test_LDA_IMM, test_LDA_ZP, test_LDA_ZPX, test_LDA_ZPX_wraparound, test_LDA_ABS, test_LDA_ABSX, test_LDA_ABSY, test_LDA_INDX, test_LDA_INDY }; fp* tests_lda[] = { test_LDA_IMM, test_LDA_IMM_zero, test_LDA_ZP, test_LDA_ZPX, test_LDA_ZPX_wraparound, test_LDA_ABS, test_LDA_ABSX, test_LDA_ABSY, test_LDA_INDX, test_LDA_INDY };
fp* tests_ora[] = { test_ORA_IMM, test_ORA_ZP, test_ORA_ZPX, test_ORA_ABS, test_ORA_ABSX, test_ORA_ABSY, test_ORA_INDX, test_ORA_INDY }; fp* tests_ora[] = { test_ORA_IMM, test_ORA_ZP, test_ORA_ZPX, test_ORA_ABS, test_ORA_ABSX, test_ORA_ABSY, test_ORA_INDX, test_ORA_INDY };
fp* tests_and[] = { test_AND_IMM, test_AND_ZP, test_AND_ZPX, test_AND_ABS, test_AND_ABSX, test_AND_ABSY, test_AND_INDX, test_AND_INDY }; fp* tests_and[] = { test_AND_IMM, test_AND_ZP, test_AND_ZPX, test_AND_ABS, test_AND_ABSX, test_AND_ABSY, test_AND_INDX, test_AND_INDY };
fp* tests_ldx[] = { test_LDX_IMM, test_LDX_ZP, test_LDX_ZPY, test_LDX_ABS, test_LDX_ABSY }; fp* tests_ldx[] = { test_LDX_IMM, test_LDX_IMM_zero, test_LDX_ZP, test_LDX_ZPY, test_LDX_ABS, test_LDX_ABSY };
fp* tests_ldy[] = { test_LDY_IMM, test_LDY_ZP, test_LDY_ZPX, test_LDY_ABS, test_LDY_ABSX }; fp* tests_ldy[] = { test_LDY_IMM, test_LDY_IMM_zero, test_LDY_ZP, test_LDY_ZPX, test_LDY_ABS, test_LDY_ABSX };
fp* tests_stx[] = { test_STX_ZP, test_STX_ZPY, test_STX_ABS }; fp* tests_stx[] = { test_STX_ZP, test_STX_ZPY, test_STX_ABS };
fp* tests_sty[] = { test_STY_ZP, test_STY_ZPX, test_STY_ABS }; fp* tests_sty[] = { test_STY_ZP, test_STY_ZPX, test_STY_ABS };
fp* tests_inx_iny_dex_dey[] = { test_DEX, test_DEX_wraparound, test_DEY, test_DEY_wraparound, test_INX, test_INX_wraparound, test_INY, test_INY_wraparound }; fp* tests_inx_iny_dex_dey[] = { test_DEX, test_DEX_wraparound, test_DEY, test_DEY_wraparound, test_INX, test_INX_wraparound, test_INY, test_INY_wraparound };
@ -2229,6 +2311,7 @@ fp* tests_adc[] = { test_ADC_IMM_multiple };
fp* tests_bit[] = { test_BIT_multiple }; fp* tests_bit[] = { test_BIT_multiple };
fp* tests_jsr_rts[] = { test_JSR, test_JSR_RTS }; fp* tests_jsr_rts[] = { test_JSR, test_JSR_RTS };
fp* tests_brk[] = { test_BRK }; fp* tests_brk[] = { test_BRK };
fp* tests_branch[] = { test_BEQ, test_BEQ_skip };
#define RUN(suite) run_suite(suite, sizeof(suite)/sizeof(fp*)) #define RUN(suite) run_suite(suite, sizeof(suite)/sizeof(fp*))
@ -2241,16 +2324,16 @@ void run_suite(fp * *suite, int size) {
} }
void run_tests() { void run_tests() {
RUN(tests_branch);
RUN(tests_sbc); RUN(tests_sbc);
RUN(tests_brk); RUN(tests_brk);
RUN(tests_jsr_rts); RUN(tests_jsr_rts);
RUN(tests_bit); RUN(tests_bit);
RUN(tests_adc); RUN(tests_adc);
RUN(tests_lda);
RUN(tests_ora); RUN(tests_ora);
RUN(tests_and); RUN(tests_and);
RUN(tests_ldx);
RUN(tests_lda); RUN(tests_lda);
RUN(tests_ldx);
RUN(tests_ldy); RUN(tests_ldy);
RUN(tests_stx); RUN(tests_stx);
RUN(tests_sty); RUN(tests_sty);

View File

@ -4,3 +4,4 @@
//typedef unsigned __int16 uint16_t; //typedef unsigned __int16 uint16_t;
typedef uint8_t byte; typedef uint8_t byte;
typedef uint16_t word; typedef uint16_t word;
typedef int8_t signed_byte;