mirror of
https://github.com/jborza/emu6502.git
synced 2025-02-19 07:30:57 +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:
parent
7b0a3a0de9
commit
2ddcf62212
120
cpu.c
120
cpu.c
@ -1,6 +1,7 @@
|
||||
#include "state.h"
|
||||
#include "cpu.h"
|
||||
#include "opcodes.h"
|
||||
#include "memory.h"
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include <stdlib.h>
|
||||
@ -93,17 +94,17 @@ void AND(State6502 * state, byte operand) {
|
||||
//load accumulator
|
||||
void LDA(State6502 * state, byte operand) {
|
||||
state->a = operand;
|
||||
set_NV_flags(state, state->a);
|
||||
set_NZ_flags(state, state->a);
|
||||
}
|
||||
|
||||
void LDX(State6502 * state, byte operand) {
|
||||
state->x = operand;
|
||||
set_NV_flags(state, state->x);
|
||||
set_NZ_flags(state, state->x);
|
||||
}
|
||||
|
||||
void LDY(State6502 * state, byte operand) {
|
||||
state->y = operand;
|
||||
set_NV_flags(state, state->y);
|
||||
set_NZ_flags(state, state->y);
|
||||
}
|
||||
|
||||
void STA(State6502 * state, word address) {
|
||||
@ -278,6 +279,12 @@ void RTS_(State6502* state) {
|
||||
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) {
|
||||
byte low = pop_byte(state);
|
||||
byte high = pop_byte(state);
|
||||
@ -285,111 +292,6 @@ word pop_word(State6502 * state) {
|
||||
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) {
|
||||
byte* opcode = &state->memory[state->pc++];
|
||||
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 BCC_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 BNE_REL: unimplemented_instruction(state); break;
|
||||
case BPL_REL: unimplemented_instruction(state); break;
|
||||
|
@ -154,12 +154,14 @@
|
||||
<ClCompile Include="cpu.c" />
|
||||
<ClCompile Include="disassembler.c" />
|
||||
<ClCompile Include="emu6502.c" />
|
||||
<ClCompile Include="memory.c" />
|
||||
<ClCompile Include="test6502.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="cpu.h" />
|
||||
<ClInclude Include="disassembler.h" />
|
||||
<ClInclude Include="flags.h" />
|
||||
<ClInclude Include="memory.h" />
|
||||
<ClInclude Include="opcodes.h" />
|
||||
<ClInclude Include="state.h" />
|
||||
<ClInclude Include="test6502.h" />
|
||||
|
111
memory.c
Normal file
111
memory.c
Normal 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
40
memory.h
Normal 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);
|
93
test6502.c
93
test6502.c
@ -163,10 +163,30 @@ void test_LDA_IMM() {
|
||||
|
||||
//assert
|
||||
assertA(&state, 0xAA);
|
||||
assert_flag_n(&state, 1);
|
||||
|
||||
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() {
|
||||
//initialize
|
||||
State6502 state = create_blank_state();
|
||||
@ -843,6 +863,25 @@ void test_LDX_IMM() {
|
||||
|
||||
//assert
|
||||
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);
|
||||
}
|
||||
@ -938,6 +977,25 @@ void test_LDY_IMM() {
|
||||
|
||||
//assert
|
||||
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);
|
||||
}
|
||||
@ -2203,14 +2261,38 @@ void test_BRK() {
|
||||
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();
|
||||
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_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_ldy[] = { test_LDY_IMM, test_LDY_ZP, test_LDY_ZPX, test_LDY_ABS, test_LDY_ABSX };
|
||||
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_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_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 };
|
||||
@ -2229,6 +2311,7 @@ fp* tests_adc[] = { test_ADC_IMM_multiple };
|
||||
fp* tests_bit[] = { test_BIT_multiple };
|
||||
fp* tests_jsr_rts[] = { test_JSR, test_JSR_RTS };
|
||||
fp* tests_brk[] = { test_BRK };
|
||||
fp* tests_branch[] = { test_BEQ, test_BEQ_skip };
|
||||
|
||||
#define RUN(suite) run_suite(suite, sizeof(suite)/sizeof(fp*))
|
||||
|
||||
@ -2241,16 +2324,16 @@ void run_suite(fp * *suite, int size) {
|
||||
}
|
||||
|
||||
void run_tests() {
|
||||
RUN(tests_branch);
|
||||
RUN(tests_sbc);
|
||||
RUN(tests_brk);
|
||||
RUN(tests_jsr_rts);
|
||||
RUN(tests_bit);
|
||||
RUN(tests_adc);
|
||||
RUN(tests_lda);
|
||||
RUN(tests_ora);
|
||||
RUN(tests_and);
|
||||
RUN(tests_ldx);
|
||||
RUN(tests_lda);
|
||||
RUN(tests_ldx);
|
||||
RUN(tests_ldy);
|
||||
RUN(tests_stx);
|
||||
RUN(tests_sty);
|
||||
|
Loading…
x
Reference in New Issue
Block a user