cnpemu/test/test_CPU_6502.c

2344 lines
90 KiB
C

#include "unity.h"
#include "CPU_6502.h"
#include "memory.h"
#include "common.h"
#define NOP 0xEA
uint16_t last_read_address = 0;
uint16_t last_write_address = 0;
uint8_t last_write_value = 0;
void setUp(void) {
last_read_address = 0;
last_write_address = 0;
last_write_value = 0;
}
void tearDown(void) { }
uint8_t read_mem(void *context, uint16_t address) {
last_read_address = address;
return NOP;
}
void write_mem(void *context, uint16_t address, uint8_t value) {
last_write_address = address;
last_write_value = value;
}
void test_CPU_6502_new_delete(void) {
struct CPU_6502_instance *cpu = CPU_6502_new(NULL, write_mem, read_mem);
TEST_ASSERT_NOT_NULL(cpu);
CPU_6502_delete(&cpu);
TEST_ASSERT_NULL(cpu);
}
void test_CPU_6502_initialization(void) {
struct CPU_6502_instance *cpu = CPU_6502_new(NULL, write_mem, read_mem);
TEST_ASSERT_NOT_NULL(cpu);
TEST_ASSERT_EQUAL(CPU_6502_VECTOR_RESET_HI, last_read_address);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xFF, cpu->state.sp, "Stack pointer should be initialized to 0xFF");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0xEAEA, cpu->state.pc, "Program counter should be pointing to 0xEAEA");
TEST_ASSERT_MESSAGE(cpu->state.status & CPU_6502_STATUS_UNUSED, "Unused bit should be set");
TEST_ASSERT_MESSAGE(cpu->state.status & CPU_6502_STATUS_INTERRUPT, "Interrupt bit should be set");
TEST_ASSERT_MESSAGE(cpu->state.status & CPU_6502_STATUS_BREAK, "Break bit should be set");
TEST_ASSERT_UNLESS_MESSAGE(cpu->state.status & CPU_6502_STATUS_DECIMAL, "Decimal bit should be set");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0, cpu->state.a, "Accumulator should be initialized to 0x00");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0, cpu->state.x, "X register should be initialized to 0x00");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0, cpu->state.y, "Y register should be initialized to 0x00");
CPU_6502_delete(&cpu);
}
void test_CPU_6502_nop_step(void) {
struct CPU_6502_instance *cpu = CPU_6502_new(NULL, write_mem, read_mem);
TEST_ASSERT_NOT_NULL(cpu);
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0xEAEB, cpu->state.pc, "Program counter should be incremented by 1");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0xEAEA, last_read_address, "NOP should read from 0xEAEA");
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0xEAEC, cpu->state.pc, "Program counter should be incremented by 1");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0xEAEB, last_read_address, "NOP should read from 0xEAEB");
CPU_6502_delete(&cpu);
}
void test_CPU_6502_LDA_immediate(void) {
struct MEMORY_instance *mem = MEMORY_new(2, false);
TEST_ASSERT_NOT_NULL(mem);
/* LDA #5 */
MEMORY_write(mem, 0, 0xA9);
MEMORY_write(mem, 1, 0x05);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func)MEMORY_write, (COMMON_read_func)MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "LDA #5 should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "LDA #5 should move pc after immediate data");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x05, cpu->state.a, "LDA #5 should load accumulator with 0x05");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_LDX(void) {
struct MEMORY_instance *mem = MEMORY_new(2, false);
TEST_ASSERT_NOT_NULL(mem);
/* LDX #5 */
MEMORY_write(mem, 0, 0xA2);
MEMORY_write(mem, 1, 0x05);
/* LDX #0 */
MEMORY_write(mem, 2, 0xA2);
MEMORY_write(mem, 3, 0x00);
/* LDX #-1 */
MEMORY_write(mem, 4, 0xA2);
MEMORY_write(mem, 5, 0xFF);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func)MEMORY_write, (COMMON_read_func)MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "LDX #5 should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "LDX #5 should move pc after immediate data");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x05, cpu->state.x, "LDX #5 should load X register with 0x05");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "LDX #5 should not set zero flag for non-zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "LDX #5 should not set negative flag for positive value");
cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "LDX #0 should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0004, cpu->state.pc, "LDX #0 should move pc after immediate data");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00, cpu->state.x, "LDX #0 should load X register with 0x00");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "LDX #0 should set zero flag for zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "LDX #0 should not set negative flag for zero value");
cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "LDX #-1 should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0006, cpu->state.pc, "LDX #-1 should move pc after immediate data");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xFF, cpu->state.x, "LDX #-1 should load X register with 0xFF");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "LDX #-1 should not set zero flag for non-zero value");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "LDX #-1 should set negative flag for negative value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_LDA_absolute(void) {
struct MEMORY_instance *mem = MEMORY_new(512, false);
TEST_ASSERT_NOT_NULL(mem);
/* LDA $0102 */
MEMORY_write(mem, 0, 0xAD);
MEMORY_write(mem, 1, 0x02);
MEMORY_write(mem, 2, 0x01);
/* Value to load */
MEMORY_write(mem, 0x0102, 0x06);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func)MEMORY_write, (COMMON_read_func)MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x04, cycles, "LDA $0102 should consume 4 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0003, cpu->state.pc, "LDA $0102 should move pc after absolute address");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x06, cpu->state.a, "LDA $0102 should load accumulator with 0x06");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_LDA_zero_page(void) {
struct MEMORY_instance *mem = MEMORY_new(512, false);
TEST_ASSERT_NOT_NULL(mem);
/* LDA $05 */
MEMORY_write(mem, 0, 0xA5);
MEMORY_write(mem, 1, 0x05);
/* Value to load */
MEMORY_write(mem, 0x0005, 0x07);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func)MEMORY_write, (COMMON_read_func)MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x03, cycles, "LDA $05 should consume 4 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "LDA $05 should move pc after zero page address");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x07, cpu->state.a, "LDA $05 should load accumulator with 0x07");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_LDA_zero_page_x(void) {
struct MEMORY_instance *mem = MEMORY_new(512, false);
TEST_ASSERT_NOT_NULL(mem);
/* LDA $05,X */
MEMORY_write(mem, 0, 0xB5);
MEMORY_write(mem, 1, 0x05);
/* Value to load */
MEMORY_write(mem, 0x0007, 0x08);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func)MEMORY_write, (COMMON_read_func)MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.x = 0x02;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x04, cycles, "LDA $05,X should consume 4 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "LDA $05,X should move pc after zero page address");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x08, cpu->state.a, "LDA $05,X should load accumulator with 0x08");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_LDA_zero_page_x_should_not_carry(void) {
struct MEMORY_instance *mem = MEMORY_new(512, false);
TEST_ASSERT_NOT_NULL(mem);
/* LDA $FF,X */
MEMORY_write(mem, 0, 0xB5);
MEMORY_write(mem, 1, 0xFF);
/* Value to load */
MEMORY_write(mem, 0x0005, 0x09);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func)MEMORY_write, (COMMON_read_func)MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.x = 0x06;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x04, cycles, "LDA $FF,X should consume 4 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "LDA $FF,X should move pc after zero page address");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x09, cpu->state.a, "LDA $FF,X should load accumulator with 0x09");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_LDA_absolute_x(void) {
struct MEMORY_instance *mem = MEMORY_new(512, false);
TEST_ASSERT_NOT_NULL(mem);
/* LDA $0102,X */
MEMORY_write(mem, 0, 0xBD);
MEMORY_write(mem, 1, 0x02);
MEMORY_write(mem, 2, 0x01);
/* Value to load */
MEMORY_write(mem, 0x0104, 0x0A);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func)MEMORY_write, (COMMON_read_func)MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.x = 0x02;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x04, cycles, "LDA $0102,X should consume 4 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0003, cpu->state.pc, "LDA $0102,X should move pc after absolute address");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x0A, cpu->state.a, "LDA $0102,X should load accumulator with 0x0A");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_LDA_absolute_y(void) {
struct MEMORY_instance *mem = MEMORY_new(512, false);
TEST_ASSERT_NOT_NULL(mem);
/* LDA $0102,Y */
MEMORY_write(mem, 0, 0xB9);
MEMORY_write(mem, 1, 0x02);
MEMORY_write(mem, 2, 0x01);
/* Value to load */
MEMORY_write(mem, 0x0104, 0x0A);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func)MEMORY_write, (COMMON_read_func)MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.y = 0x02;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x04, cycles, "LDA $0102,Y should consume 4 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0003, cpu->state.pc, "LDA $0102,Y should move pc after absolute address");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x0A, cpu->state.a, "LDA $0102,Y should load accumulator with 0x0A");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_LDA_indirect_x(void) {
struct MEMORY_instance *mem = MEMORY_new(512, false);
TEST_ASSERT_NOT_NULL(mem);
/* LDA ($02,X) */
MEMORY_write(mem, 0, 0xA1);
MEMORY_write(mem, 1, 0x05);
/* ptr address */
MEMORY_write(mem, 0x07, 0x0A);
MEMORY_write(mem, 0x08, 0x01);
/* value to load */
MEMORY_write(mem, 0x010A, 0xC1);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func)MEMORY_write, (COMMON_read_func)MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.x = 0x02;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x06, cycles, "LDA ($02,X) should consume 4 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "LDA ($02,X) should move pc after absolute address");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xC1, cpu->state.a, "LDA ($02,X) should load accumulator with 0x0A");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_LDA_indirect_y(void) {
struct MEMORY_instance *mem = MEMORY_new(512, false);
TEST_ASSERT_NOT_NULL(mem);
/* LDA ($02),Y */
MEMORY_write(mem, 0, 0xB1);
MEMORY_write(mem, 1, 0x05);
/* ptr address */
MEMORY_write(mem, 0x05, 0x0A);
MEMORY_write(mem, 0x06, 0x01);
/* value to load */
MEMORY_write(mem, 0x010C, 0xC1);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func)MEMORY_write, (COMMON_read_func)MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.y = 0x02;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x05, cycles, "LDA ($02),Y should consume 4 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "LDA ($02),Y should move pc after absolute address");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xC1, cpu->state.a, "LDA ($02),Y should load accumulator with 0xC1");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_LDY(void) {
struct MEMORY_instance *mem = MEMORY_new(2, false);
TEST_ASSERT_NOT_NULL(mem);
/* LDY #5 */
MEMORY_write(mem, 0, 0xA0);
MEMORY_write(mem, 1, 0x05);
/* LDY #0 */
MEMORY_write(mem, 2, 0xA0);
MEMORY_write(mem, 3, 0x00);
/* LDY #-1 */
MEMORY_write(mem, 4, 0xA0);
MEMORY_write(mem, 5, 0xFF);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "LDY #5 should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "LDY #5 should move pc after immediate data");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x05, cpu->state.y, "LDY #5 should load Y register with 0x05");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO,
"LDY #5 should not set zero flag for non-zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE,
"LDY #5 should not set negative flag for positive value");
cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "LDY #0 should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0004, cpu->state.pc, "LDY #0 should move pc after immediate data");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00, cpu->state.y, "LDY #0 should load Y register with 0x00");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "LDY #0 should set zero flag for zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE,
"LDY #0 should not set negative flag for zero value");
cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "LDY #-1 should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0006, cpu->state.pc, "LDY #-1 should move pc after immediate data");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xFF, cpu->state.y, "LDY #-1 should load Y register with 0xFF");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO,
"LDY #-1 should not set zero flag for non-zero value");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE,
"LDY #-1 should set negative flag for negative value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_JMP_absolute(void) {
struct MEMORY_instance *mem = MEMORY_new(512, false);
TEST_ASSERT_NOT_NULL(mem);
/* JMP $0200 */
MEMORY_write(mem, 0, 0x4C);
MEMORY_write(mem, 1, 0x00);
MEMORY_write(mem, 2, 0x02);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x03, cycles, "JMP $0200 should consume 3 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0200, cpu->state.pc, "JMP $0200 should move pc to $0200");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_TXS(void) {
struct MEMORY_instance *mem = MEMORY_new(512, false);
TEST_ASSERT_NOT_NULL(mem);
/* TXS */
MEMORY_write(mem, 0, 0x9A);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.sp = 0x00;
cpu->state.x = 0x05;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "TXS should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0001, cpu->state.pc, "TXS should move pc to $0001");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x05, cpu->state.sp, "TXS should set stack pointer to 0x05");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_STA(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* STA $0200 */
MEMORY_write(mem, 0, 0x8D);
MEMORY_write(mem, 1, 0x00);
MEMORY_write(mem, 2, 0x02);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.a = 0x05;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x04, cycles, "STA $0200 should consume 4 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0003, cpu->state.pc, "STA $0200 should move pc to $0003");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x05, MEMORY_read(mem, 0x0200), "STA $0200 should store 0x05 at $0200");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_BNE_with_equal(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* BNE $05 */
MEMORY_write(mem, 0, 0xD0);
MEMORY_write(mem, 1, 0x05);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.status |= CPU_6502_STATUS_ZERO;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "BNE $0200 should consume 3 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "BNE should move pc to $0002");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_BNE_with_not_equal(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* BNE $05 */
MEMORY_write(mem, 0, 0xD0);
MEMORY_write(mem, 1, 0x05);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.status &= ~CPU_6502_STATUS_ZERO;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "BNE $0200 should consume 4 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0007, cpu->state.pc, "BNE $0200 should move pc to $0002");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_BNE_with_not_equal_neg_offset(void) {
/*
* test:
* lda #2
* lda #1
* bne test
* lda #3
*/
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* LDA #2 */
MEMORY_write(mem, 0x0000, 0xA9);
MEMORY_write(mem, 0x0001, 0x02);
/* LDA #1 */
MEMORY_write(mem, 0x0002, 0xA9);
MEMORY_write(mem, 0x0003, 0x01);
/* BNE $FA */
MEMORY_write(mem, 0x0004, 0xD0);
MEMORY_write(mem, 0x0005, 0xFA);
/* LDA #3 */
MEMORY_write(mem, 0x0006, 0xA9);
MEMORY_write(mem, 0x0007, 0x03);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0002;
CPU_6502_step(cpu);
CPU_6502_step(cpu);
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cpu->state.a, "Accumulator should hold 2 if proper branch was taken");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_DEX(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* DEX */
MEMORY_write(mem, 0, 0xCA);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.x = 0x05;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "DEX should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0001, cpu->state.pc, "DEX should move pc to $0001");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x04, cpu->state.x, "DEX should set x to 0x04");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO,
"DEX should not set zero flag for non-zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE,
"DEX should not set negative flag for positive value");
cpu->state.x = 0x01;
cpu->state.pc = 0x0000;
CPU_6502_step(cpu);
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO,
"DEX should set zero flag for zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE,
"DEX should not set negative flag for zero value");
cpu->state.pc = 0x0000;
CPU_6502_step(cpu);
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO,
"DEX should not set zero flag for negative value");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE,
"DEX should set negative flag for negative value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_BEQ(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* LDA #0 */
MEMORY_write(mem, 0, 0xA9);
MEMORY_write(mem, 1, 0x00);
/* BEQ test */
MEMORY_write(mem, 2, 0xF0);
MEMORY_write(mem, 3, 0x02);
/* LDA #2 */
MEMORY_write(mem, 4, 0xA9);
MEMORY_write(mem, 5, 0x02);
/* test: LDA #1 */
MEMORY_write(mem, 6, 0xA9);
MEMORY_write(mem, 7, 0x01);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
CPU_6502_step(cpu);
CPU_6502_PRINT_STATE(cpu->state);
CPU_6502_PRINT_STATUS(cpu->state.status);
CPU_6502_step(cpu);
CPU_6502_PRINT_STATE(cpu->state);
CPU_6502_PRINT_STATUS(cpu->state.status);
CPU_6502_step(cpu);
CPU_6502_PRINT_STATE(cpu->state);
CPU_6502_PRINT_STATUS(cpu->state.status);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x01, cpu->state.a, "1 should be loaded in accumulator");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_BEQ_equal(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* BEQ $05 */
MEMORY_write(mem, 0, 0xF0);
MEMORY_write(mem, 1, 0x05);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.status |= CPU_6502_STATUS_ZERO;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "BEQ $0200 should consume 3 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0007, cpu->state.pc, "BEQ $0200 should move pc to $0007");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_BEQ_not_equal(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* BEQ $05 */
MEMORY_write(mem, 0, 0xF0);
MEMORY_write(mem, 1, 0x05);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "BEQ $0200 should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "BEQ $0200 should move pc to $0002");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_DEY(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* DEY */
MEMORY_write(mem, 0, 0x88);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.y = 0x05;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "DEY should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0001, cpu->state.pc, "DEY should move pc to $0001");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x04, cpu->state.y, "DEY should set y to 0x04");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO,
"DEY should not set zero flag for non-zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE,
"DEY should not set negative flag for positive value");
cpu->state.y = 0x01;
cpu->state.pc = 0x0000;
CPU_6502_step(cpu);
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO,
"DEY should set zero flag for zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE,
"DEY should not set negative flag for zero value");
cpu->state.pc = 0x0000;
CPU_6502_step(cpu);
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO,
"DEY should not set zero flag for negative value");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE,
"DEY should set negative flag for negative value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_CMP_less_than(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* CMP #$05 */
MEMORY_write(mem, 0, 0xC9);
MEMORY_write(mem, 1, 0x05);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.a = 0x04;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "CMP #$05 should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "CMP #$05 should move pc to $0002");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "CMP #$05 should not set zero flag for < memory value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "CMP #$05 should not set carry flag for < memory value");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "CMP #$05 should set negative flag for < memory value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_CMP_greater_than(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* CMP #$05 */
MEMORY_write(mem, 0, 0xC9);
MEMORY_write(mem, 1, 0x05);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.a = 0x06;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "CMP #$05 should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "CMP #$05 should move pc to $0002");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "CMP #$05 should not set zero flag for > memory value");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "CMP #$05 should set carry flag for > memory value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "CMP #$05 should not set negative flag for > memory value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_CMP_equal(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* CMP #$05 */
MEMORY_write(mem, 0, 0xC9);
MEMORY_write(mem, 1, 0x05);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.a = 0x05;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "CMP #$05 should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "CMP #$05 should move pc to $0002");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "CMP #$05 should set zero flag for = memory value");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "CMP #$05 should set carry flag for = memory value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "CMP #$05 should not set negative flag for = memory value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_CLD(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* CLD */
MEMORY_write(mem, 0, 0xD8);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.status = CPU_6502_STATUS_DECIMAL;
cpu->state.pc = 0x0000;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "CLD should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0001, cpu->state.pc, "CLD should move pc to $0001");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_DECIMAL, "CLD should clear decimal flag");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_TYA(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* TYA */
MEMORY_write(mem, 0, 0x98);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.y = 0x05;
cpu->state.pc = 0x0000;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "TYA should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0001, cpu->state.pc, "TYA should move pc to $0001");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x05, cpu->state.a, "TYA should transfer Y to A");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "TYA should not set zero flag for non-zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "TYA should not set negative flag for non-negative value");
cpu->state.y = 0x00;
cpu->state.pc = 0x0000;
CPU_6502_step(cpu);
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "TYA should set zero flag for zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "TYA should not set negative flag for zero value");
cpu->state.y = 0xFF;
cpu->state.pc = 0x0000;
CPU_6502_step(cpu);
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "TYA should not set zero flag for negative value");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "TYA should set negative flag for negative value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_TAX(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* TAX */
MEMORY_write(mem, 0, 0xAA);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.a = 0x05;
cpu->state.pc = 0x0000;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "TAX should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0001, cpu->state.pc, "TAX should move pc to $0001");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x05, cpu->state.x, "TAX should transfer A to X");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "TAX should not set zero flag for non-zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "TAX should not set negative flag for non-negative value");
cpu->state.a = 0x00;
cpu->state.pc = 0x0000;
CPU_6502_step(cpu);
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "TAX should set zero flag for zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "TAX should not set negative flag for zero value");
cpu->state.a = 0xFF;
cpu->state.pc = 0x0000;
CPU_6502_step(cpu);
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "TAX should not set zero flag for negative value");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "TAX should set negative flag for negative value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_BPL(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* BPL */
MEMORY_write(mem, 0, 0x10);
MEMORY_write(mem, 1, 0x02);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.status |= CPU_6502_STATUS_NEGATIVE;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "BPL should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "BPL should move pc to $0002");
cpu->state.pc = 0x0000;
cpu->state.status &= ~CPU_6502_STATUS_NEGATIVE;
cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "BPL should consume 3 cycles when branch is taken");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0004, cpu->state.pc, "BPL should move pc to $0002");
}
void test_CPU_6502_CLC(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* CLC */
MEMORY_write(mem, 0, 0x18);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.status |= CPU_6502_STATUS_CARRY;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "CLC should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0001, cpu->state.pc, "CLC should move pc to $0001");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "CLC should clear carry flag");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_ADC_binary(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* ADC */
MEMORY_write(mem, 0, 0x69);
MEMORY_write(mem, 1, 0x05);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.a = 0x05;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "ADC should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "ADC should move pc to $0002");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x0A, cpu->state.a, "ADC should add value to A");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "ADC should not set zero flag for non-zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "ADC should not set negative flag for non-negative value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "ADC should not set carry flag for non-carry value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_OVERFLOW, "ADC should not set overflow flag for non-overflow value");
cpu->state.pc = 0x0000;
cpu->state.a = 0xFF;
CPU_6502_step(cpu);
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "ADC should not set zero flag for non-zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "ADC should not set negative flag for non-negative value");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "ADC should not set carry flag for when value is carried");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_OVERFLOW, "ADC should not set overflow flag for non-overflow value");
cpu->state.pc = 0x0000;
cpu->state.a = 0x7F;
CPU_6502_step(cpu);
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "ADC should not set zero flag for non-zero value");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "ADC should set negative flag for negative value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "ADC should not set carry flag for non-carry value");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_OVERFLOW, "ADC should set overflow flag for overflow value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_EOR(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* EOR */
MEMORY_write(mem, 0, 0x49);
MEMORY_write(mem, 1, 0x05);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.a = 0x0F;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "EOR should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "EOR should move pc to $0002");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x0A, cpu->state.a, "EOR should add value to A");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "EOR should not set zero flag for non-zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "EOR should not set negative flag for non-negative value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_SEI(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* SEI */
MEMORY_write(mem, 0, 0x78);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.status &= ~CPU_6502_STATUS_INTERRUPT;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "SEI should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0001, cpu->state.pc, "SEI should move pc to $0001");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_INTERRUPT, "SEI should set interrupt disable flag");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_INY(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* INY */
MEMORY_write(mem, 0, 0xC8);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.y = 0x0F;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "INY should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0001, cpu->state.pc, "INY should move pc to $0001");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x10, cpu->state.y, "INY should increment Y");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "INY should not set zero flag for non-zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "INY should not set negative flag for non-negative value");
cpu->state.pc = 0x0000;
cpu->state.y = 0xF4;
CPU_6502_step(cpu);
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "INY should not set zero flag for non-zero value");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "INY should set negative flag for negative value");
cpu->state.pc = 0x0000;
cpu->state.y = 0xFF;
CPU_6502_step(cpu);
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "INY should set zero flag for zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "INY should not set negative flag for zero value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_INX(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* INX */
MEMORY_write(mem, 0, 0xE8);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.x = 0x0F;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "INX should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0001, cpu->state.pc, "INX should move pc to $0001");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x10, cpu->state.x, "INX should increment X");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "INX should not set zero flag for non-zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "INX should not set negative flag for non-negative value");
cpu->state.pc = 0x0000;
cpu->state.x = 0xF4;
CPU_6502_step(cpu);
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "INX should not set zero flag for non-zero value");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "INX should set negative flag for negative value");
cpu->state.pc = 0x0000;
cpu->state.x = 0xFF;
CPU_6502_step(cpu);
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "INX should set zero flag for zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "INX should not set negative flag for zero value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_INC(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* INC $05 */
MEMORY_write(mem, 0, 0xE6);
MEMORY_write(mem, 1, 0x05);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
MEMORY_write(mem, 0x05, 0x0F);
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x05, cycles, "INC $05 should consume 5 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "INC $05 should move pc to $0002");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x10, MEMORY_read(mem, 0x05), "INC $05 should increment memory");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "INC $05 should not set zero flag for non-zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "INC $05 should not set negative flag for non-negative value");
cpu->state.pc = 0x0000;
MEMORY_write(mem, 0x05, 0xF4);
CPU_6502_step(cpu);
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "INC $05 should not set zero flag for non-zero value");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "INC $05 should set negative flag for negative value");
cpu->state.pc = 0x0000;
MEMORY_write(mem, 0x05, 0xFF);
CPU_6502_step(cpu);
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "INC $05 should set zero flag for zero value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "INC $05 should not set negative flag for zero value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_JSR(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* JSR $1234 */
MEMORY_write(mem, 0, 0x20);
MEMORY_write(mem, 1, 0x34);
MEMORY_write(mem, 2, 0x12);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.sp = 0xFF;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x06, cycles, "JSR $1234 should consume 6 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x1234, cpu->state.pc, "JSR $1234 should move pc to $1234");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xFD, cpu->state.sp, "JSR $1234 should decrement sp to $FD");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00, MEMORY_read(mem, 0x01FF), "JSR $1234 should push high byte of return address to $01FF");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, MEMORY_read(mem, 0x01FE), "JSR $1234 should push low byte of return address to $01FE");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_PHA(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* PHA */
MEMORY_write(mem, 0, 0x48);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.sp = 0xFF;
cpu->state.a = 0x0F;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x03, cycles, "PHA should consume 3 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0001, cpu->state.pc, "PHA should move pc to $0001");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xFE, cpu->state.sp, "PHA should decrement sp to $FE");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x0F, MEMORY_read(mem, 0x01FF), "PHA should push accumulator to $01FF");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_STY(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* STY $05 */
MEMORY_write(mem, 0, 0x84);
MEMORY_write(mem, 1, 0x05);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.y = 0x0F;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x03, cycles, "STY $05 should consume 3 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "STY $05 should move pc to $0002");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x0F, MEMORY_read(mem, 0x05), "STY $05 should store y register to $05");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_PLA(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* PLA */
MEMORY_write(mem, 0, 0x68);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.sp = 0xFE;
MEMORY_write(mem, 0x01FF, 0x0F);
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x04, cycles, "PLA should consume 4 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0001, cpu->state.pc, "PLA should move pc to $0001");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xFF, cpu->state.sp, "PLA should increment sp to $FF");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x0F, cpu->state.a, "PLA should load accumulator from $01FF");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_RTS(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* RTS */
MEMORY_write(mem, 0, 0x60);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.sp = 0xFD;
MEMORY_write(mem, 0x01FF, 0x00);
MEMORY_write(mem, 0x01FE, 0x03);
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x06, cycles, "RTS should consume 6 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0004, cpu->state.pc, "RTS should move pc to $0004");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xFF, cpu->state.sp, "RTS should decrement sp to $FF");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_JSR_RTS(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* JSR $0300 */
MEMORY_write(mem, 0, 0x20);
MEMORY_write(mem, 1, 0x00);
MEMORY_write(mem, 2, 0x03);
/* RTS */
MEMORY_write(mem, 0x0300, 0x60);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0300, cpu->state.pc, "JSR $0300 should move pc to $0301");
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0003, cpu->state.pc, "RTS should move pc to $0003");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_CPY(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* CPY #$0F */
MEMORY_write(mem, 0, 0xC0);
MEMORY_write(mem, 1, 0x0F);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.y = 0x0F;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "CPY #$0F should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "CPY #$0F should move pc to $0002");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x0F, cpu->state.y, "CPY #$0F should not change y register");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "CPY #$0F should set zero flag for equal values");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "CPY #$0F should clear negative flag for equal values");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "CPY #$0F should set carry flag for equal values");
cpu->state.pc = 0x0000;
cpu->state.y = 0x10;
CPU_6502_step(cpu);
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "CPY #$0F should clear zero flag for non-equal values");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "CPY #$0F should clear negative flag for equal values");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "CPY #$0F should set carry flag when register > memory value");
cpu->state.pc = 0x0000;
cpu->state.y = 0x0E;
CPU_6502_step(cpu);
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "CPY #$0F should clear zero flag for non-equal values");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "CPY #$0F should set negative flag when register < memory value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "CPY #$0F should clear carry flag when register < memory value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_CPX(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* CPX #$0F */
MEMORY_write(mem, 0, 0xE0);
MEMORY_write(mem, 1, 0x0F);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.x = 0x0F;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "CPX #$0F should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "CPX #$0F should move pc to $0002");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x0F, cpu->state.x, "CPX #$0F should not change x register");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "CPX #$0F should set zero flag for equal values");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "CPX #$0F should clear negative flag for equal values");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "CPX #$0F should set carry flag for equal values");
cpu->state.pc = 0x0000;
cpu->state.x = 0x10;
CPU_6502_step(cpu);
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "CPX #$0F should clear zero flag for non-equal values");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "CPX #$0F should clear negative flag for equal values");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "CPX #$0F should set carry flag when register > memory value");
cpu->state.pc = 0x0000;
cpu->state.x = 0x0E;
CPU_6502_step(cpu);
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "CPX #$0F should clear zero flag for non-equal values");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "CPX #$0F should set negative flag when register < memory value");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "CPX #$0F should clear carry flag when register < memory value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_BCC(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* BCC $03 */
MEMORY_write(mem, 0, 0x90);
MEMORY_write(mem, 1, 0x03);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.status &= ~CPU_6502_STATUS_CARRY;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "BCC $03 should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0005, cpu->state.pc, "BCC $03 should move pc to $0003 when carry flag is clear");
cpu->state.pc = 0x0000;
cpu->state.status |= CPU_6502_STATUS_CARRY;
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "BCC $03 should move pc to $0002 when carry flag is set");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_BMI(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* BMI $03 */
MEMORY_write(mem, 0, 0x30);
MEMORY_write(mem, 1, 0x03);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.status |= CPU_6502_STATUS_NEGATIVE;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "BMI $03 should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0005, cpu->state.pc, "BMI $03 should move pc to $0005 when negative flag is set");
cpu->state.pc = 0x0000;
cpu->state.status &= ~CPU_6502_STATUS_NEGATIVE;
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "BMI $03 should move pc to $0002 when negative flag is clear");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_BCS(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* BCS $03 */
MEMORY_write(mem, 0, 0xB0);
MEMORY_write(mem, 1, 0x03);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.status |= CPU_6502_STATUS_CARRY;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "BCS $03 should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0005, cpu->state.pc, "BCS $03 should move pc to $0005 when carry flag is set");
cpu->state.pc = 0x0000;
cpu->state.status &= ~CPU_6502_STATUS_CARRY;
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "BCS $03 should move pc to $0002 when carry flag is clear");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_TSX(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* TSX */
MEMORY_write(mem, 0, 0xBA);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.sp = 0x0F;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "TSX should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x0F, cpu->state.x, "TSX should set X register to stack pointer value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_TXA(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* TXA */
MEMORY_write(mem, 0, 0x8A);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.x = 0x0F;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "TXA should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x0F, cpu->state.a, "TXA should set A register to X register value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_PLP(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* PLP */
MEMORY_write(mem, 0, 0x28);
MEMORY_write(mem, 0x01FE, 0xB5);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.status = 0x00;
cpu->state.sp = 0xFD;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x04, cycles, "PLP should consume 4 cycles");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xB5, cpu->state.status, "PLP should set status register to stack value");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_BVC(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* BVC $03 */
MEMORY_write(mem, 0, 0x50);
MEMORY_write(mem, 1, 0x03);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.status |= CPU_6502_STATUS_OVERFLOW;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "BVC $03 should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "BVC $03 should move pc to $0002 when overflow flag is clear");
cpu->state.pc = 0x0000;
cpu->state.status &= ~CPU_6502_STATUS_OVERFLOW;
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0005, cpu->state.pc, "BVC $03 should move pc to $0005 when overflow flag is set");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_BVS(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* BVS $03 */
MEMORY_write(mem, 0, 0x70);
MEMORY_write(mem, 1, 0x03);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.status |= CPU_6502_STATUS_OVERFLOW;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "BVS $03 should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0005, cpu->state.pc, "BVS $03 should move pc to $0005 when overflow flag is set");
cpu->state.pc = 0x0000;
cpu->state.status &= ~CPU_6502_STATUS_OVERFLOW;
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0002, cpu->state.pc, "BVS $03 should move pc to $0002 when overflow flag is clear");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_PHP(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* PHP */
MEMORY_write(mem, 0, 0x08);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.status = 0xA5;
cpu->state.sp = 0xFD;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x03, cycles, "PHP should consume 3 cycles");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xA5, MEMORY_read(mem, 0x01FD), "PHP should push status register to stack");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_DEC(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* DEC */
MEMORY_write(mem, 0, 0xC6);
MEMORY_write(mem, 1, 0x0F);
MEMORY_write(mem, 0x000F, 0x04);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x05, cycles, "DEC accumulator should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x03, MEMORY_read(mem, 0x000F), "DEC accumulator should decrement accumulator by 1");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_DEC_accumulator(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* DEC */
MEMORY_write(mem, 0, 0x3A);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.a = 0x05;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "DEC accumulator should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x04, cpu->state.a, "DEC accumulator should decrement accumulator by 1");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_AND(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* AND immediate */
MEMORY_write(mem, 0, 0x29);
MEMORY_write(mem, 1, 0x0F);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.a = 0xFF;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "AND immediate should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x0F, cpu->state.a, "AND immediate should AND accumulator with immediate memory location");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_PHY(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* PHY */
MEMORY_write(mem, 0, 0x5A);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.y = 0xA5;
cpu->state.sp = 0xFD;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x03, cycles, "PHY should consume 3 cycles");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xA5, MEMORY_read(mem, 0x01FD), "PHY should push Y register to stack");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_PLY(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* PLY */
MEMORY_write(mem, 0, 0x7A);
MEMORY_write(mem, 0x01FE, 0xA5);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.sp = 0xFD;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x04, cycles, "PLY should consume 4 cycles");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xA5, cpu->state.y, "PLY should pull Y register from stack");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_JMP_indirect(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* JMP indirect */
MEMORY_write(mem, 0, 0x6C);
MEMORY_write(mem, 1, 0x0F);
MEMORY_write(mem, 2, 0x00);
MEMORY_write(mem, 0x000F, 0x0A);
MEMORY_write(mem, 0x0010, 0x0B);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x05, cycles, "JMP indirect should consume 5 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0B0A, cpu->state.pc, "JMP indirect should jump to address in memory location");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_BRK(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* BRK */
MEMORY_write(mem, 0, 0x00);
MEMORY_write(mem, 0xFFFE, 0x0A);
MEMORY_write(mem, 0xFFFF, 0x0B);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
uint8_t orig_status = cpu->state.status;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x07, cycles, "BRK should consume 7 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0B0A, cpu->state.pc, "BRK should jump to interrupt vector");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xFC, cpu->state.sp, "BRK should push PC & status to stack");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_BREAK, "BRK should set break flag in status register");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_INTERRUPT, "BRK should set interrupt flag in status register");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00, MEMORY_read(mem, 0x01FF), "BRK should push PC HH to stack");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, MEMORY_read(mem, 0x01FE), "BRK should push PC LL to stack");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(orig_status, MEMORY_read(mem, 0x01FD), "BRK should push status register to stack");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_STX(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* STX absolute */
MEMORY_write(mem, 0, 0x8E);
MEMORY_write(mem, 1, 0x0F);
MEMORY_write(mem, 2, 0x00);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.x = 0x0A;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x04, cycles, "STX absolute should consume 4 cycles");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x0A, MEMORY_read(mem, 0x000F), "STX absolute should store X register in memory");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_RTI(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* RTI */
MEMORY_write(mem, 0, 0x40);
MEMORY_write(mem, 0x01FF, 0x0A);
MEMORY_write(mem, 0x01FE, 0x0B);
MEMORY_write(mem, 0x01FD, 0xB5);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.sp = 0xFC;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x06, cycles, "RTI should consume 6 cycles");
TEST_ASSERT_EQUAL_HEX16_MESSAGE(0x0A0B, cpu->state.pc, "RTI should jump to address in memory location");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xFF, cpu->state.sp, "RTI should pull PC & status from stack");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xB5, cpu->state.status, "RTI should pull status register from stack");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_ORA(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* ORA immediate */
MEMORY_write(mem, 0, 0x09);
MEMORY_write(mem, 1, 0x0A);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.a = 0xB0;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "ORA immediate should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xBA, cpu->state.a, "ORA immediate should OR A register with value in memory");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "ORA immediate should set negative flag when result bit 7 is set");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "ORA immediate should not set zero flag when result is not zero");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_SEC(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* SEC */
MEMORY_write(mem, 0, 0x38);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.status &= ~CPU_6502_STATUS_CARRY;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "SEC should consume 2 cycles");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "SEC should set carry flag in status register");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_CLI(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* CLI */
MEMORY_write(mem, 0, 0x58);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.status |= CPU_6502_STATUS_INTERRUPT;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "CLI should consume 2 cycles");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_INTERRUPT, "CLI should clear interrupt disable flag in status register");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_SED(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* SED */
MEMORY_write(mem, 0, 0xF8);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.status &= ~CPU_6502_STATUS_DECIMAL;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "SED should consume 2 cycles");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_DECIMAL, "SED should set decimal flag in status register");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_CLV(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* CLV */
MEMORY_write(mem, 0, 0xB8);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.status |= CPU_6502_STATUS_OVERFLOW;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "CLV should consume 2 cycles");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_OVERFLOW, "CLV should clear overflow flag in status register");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_BIT(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* BIT zero page */
MEMORY_write(mem, 0x1000, 0x24);
MEMORY_write(mem, 0x1001, 0x00);
MEMORY_write(mem, 0x0001, 0x00);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x1000;
cpu->state.status |= CPU_6502_STATUS_NEGATIVE;
cpu->state.status |= CPU_6502_STATUS_OVERFLOW;
cpu->state.status &= ~CPU_6502_STATUS_ZERO;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x03, cycles, "BIT zero page should consume 3 cycles");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "BIT zero page should set zero flag in status register");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "BIT should set negative flag to bit 7 of memory location");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_OVERFLOW, "BIT should set overflow flag to bit 6 of memory location");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_ASL_accumulator(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* ASL accumulator */
MEMORY_write(mem, 0, 0x0A);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.a = 0x82;
cpu->state.status &= ~CPU_6502_STATUS_CARRY;
cpu->state.status |= CPU_6502_STATUS_ZERO;
cpu->state.status |= CPU_6502_STATUS_NEGATIVE;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "ASL accumulator should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x04, cpu->state.a, "ASL accumulator should shift left accumulator");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "ASL accumulator should set carry flag to input bit 7");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "ASL accumulator should set zero flag only if the result is 0");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "ASL accumulator should set negative flag only if result bit 7 is set");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_LSR_accumulator(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* LSR accumulator */
MEMORY_write(mem, 0, 0x4A);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.a = 0x83;
cpu->state.status |= CPU_6502_STATUS_CARRY;
cpu->state.status |= CPU_6502_STATUS_ZERO;
cpu->state.status |= CPU_6502_STATUS_NEGATIVE;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "LSR accumulator should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x41, cpu->state.a, "LSR accumulator should shift right accumulator");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "LSR accumulator should set carry flag to input bit 1 if the shifted bit is set");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "LSR accumulator should set zero flag only if the result is 0");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "LSR accumulator should set negative flag");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_ROL_accumulator(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* ROL accumulator */
MEMORY_write(mem, 0, 0x2A);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.a = 0x82;
cpu->state.status &= ~CPU_6502_STATUS_CARRY;
cpu->state.status |= CPU_6502_STATUS_ZERO;
cpu->state.status |= CPU_6502_STATUS_NEGATIVE;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "ROL accumulator should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x04, cpu->state.a, "ROL accumulator should shift left accumulator");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "ROL accumulator should set carry flag to input bit 7");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "ROL accumulator should set zero flag only if the result is 0");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "ROL accumulator should set negative flag only if result bit 7 is set");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_ROR_accumulator(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* ROR accumulator */
MEMORY_write(mem, 0, 0x6A);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.a = 0x83;
cpu->state.status |= CPU_6502_STATUS_CARRY;
cpu->state.status |= CPU_6502_STATUS_ZERO;
cpu->state.status |= CPU_6502_STATUS_NEGATIVE;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "ROR accumulator should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xC1, cpu->state.a, "ROR accumulator should shift right accumulator");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "ROR accumulator should set carry flag to input bit 1 if the shifted bit is set");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "ROR accumulator should set zero flag only if the result is 0");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "ROR accumulator should set negative flag");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_SBC(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* SBC immediate */
MEMORY_write(mem, 0, 0xE9);
MEMORY_write(mem, 1, 0x01);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.a = 0x01;
cpu->state.status |= CPU_6502_STATUS_CARRY;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "SBC immediate should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x00, cpu->state.a, "SBC immediate should subtract immediate from accumulator");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "SBC immediate should set carry flag if no borrow");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "SBC immediate should set zero flag if result is zero");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "SBC immediate should set negative flag if result bit 7 is not set");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_SBC_negative_result(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* SBC immediate */
MEMORY_write(mem, 0, 0xE9);
MEMORY_write(mem, 1, 0x02);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
cpu->state.a = 0x01;
cpu->state.status |= CPU_6502_STATUS_CARRY;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "SBC immediate should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0xFF, cpu->state.a, "SBC immediate should subtract immediate from accumulator");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "SBC immediate should set carry flag if no borrow");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "SBC immediate should not set zero flag if result is not zero");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "SBC immediate should set negative flag if result bit 7 is not set");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_SBC_overflow(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
/* SBC immediate */
MEMORY_write(mem, 0, 0xE9);
/* 100 decimal */
MEMORY_write(mem, 1, 0x64);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func) MEMORY_write, (COMMON_read_func) MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
cpu->state.pc = 0x0000;
/* 2's compliment -100 decimal */
cpu->state.a = 0x9C;
cpu->state.status |= CPU_6502_STATUS_CARRY;
uint8_t cycles = CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x02, cycles, "SBC immediate should consume 2 cycles");
TEST_ASSERT_EQUAL_HEX8_MESSAGE(0x38, cpu->state.a, "SBC immediate should subtract immediate from accumulator");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_CARRY, "SBC immediate should set carry flag if no borrow");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_ZERO, "SBC immediate should not set zero flag if result is not zero");
TEST_ASSERT_TRUE_MESSAGE(cpu->state.status & CPU_6502_STATUS_OVERFLOW, "SBC immediate should set overflow flag when overflow occurs");
TEST_ASSERT_FALSE_MESSAGE(cpu->state.status & CPU_6502_STATUS_NEGATIVE, "SBC immediate should set negative flag if result bit 7 is not set");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
void test_CPU_6502_counters_reset_with_cpu(void) {
struct CPU_6502_instance *cpu = CPU_6502_new(NULL, write_mem, read_mem);
TEST_ASSERT_NOT_NULL(cpu);
cpu->counters.instructions = 1234;
cpu->counters.cycles = 5678;
CPU_6502_reset(cpu);
TEST_ASSERT_EQUAL_MESSAGE(0, cpu->counters.instructions, "CPU counters (instructions) should be reset when CPU is reset");
TEST_ASSERT_EQUAL_MESSAGE(0, cpu->counters.cycles, "CPU counters (cycles) should be reset when CPU is reset");
CPU_6502_delete(&cpu);
TEST_ASSERT_NULL(cpu);
}
void test_CPU_6502_counters_instructions_increment_each_instruction(void) {
struct CPU_6502_instance *cpu = CPU_6502_new(NULL, write_mem, read_mem);
TEST_ASSERT_NOT_NULL(cpu);
cpu->counters.instructions = 0;
cpu->counters.cycles = 0;
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_MESSAGE(1, cpu->counters.instructions, "CPU counters (instructions) should be incremented each instruction");
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_MESSAGE(2, cpu->counters.instructions, "CPU counters (instructions) should be incremented each instruction");
CPU_6502_delete(&cpu);
TEST_ASSERT_NULL(cpu);
}
void test_CPU_6502_counters_cycles_increment_each_instruction(void) {
struct CPU_6502_instance *cpu = CPU_6502_new(NULL, write_mem, read_mem);
TEST_ASSERT_NOT_NULL(cpu);
cpu->counters.instructions = 0;
cpu->counters.cycles = 0;
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_MESSAGE(2, cpu->counters.cycles, "CPU counters (cycles) should be incremented each instruction");
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_MESSAGE(4, cpu->counters.cycles, "CPU counters (cycles) should be incremented each instruction");
CPU_6502_delete(&cpu);
TEST_ASSERT_NULL(cpu);
}
void test_CPU_6502_counters_branch(void) {
struct MEMORY_instance *mem = MEMORY_new(1024, false);
TEST_ASSERT_NOT_NULL(mem);
struct CPU_6502_instance *cpu = CPU_6502_new(mem, (COMMON_write_func)MEMORY_write, (COMMON_read_func)MEMORY_read);
TEST_ASSERT_NOT_NULL(cpu);
TEST_ASSERT_EQUAL(0, cpu->counters.branches);
/* BCC */
cpu->state.pc = 0x0000;
cpu->state.status &= ~CPU_6502_STATUS_CARRY;
MEMORY_write(mem, 0x0000, 0x90);
MEMORY_write(mem, 0x0001, 0x02);
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_MESSAGE(1, cpu->counters.branches, "BCC should increment branch instruction counter");
TEST_ASSERT_EQUAL_MESSAGE(1, cpu->counters.branches_taken, "BCC should increment branch instruction taken counter when a branch is taken");
/* BCS */
cpu->state.pc = 0x0000;
MEMORY_write(mem, 0x0000, 0xB0);
MEMORY_write(mem, 0x0001, 0x02);
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_MESSAGE(2, cpu->counters.branches, "BCS should increment branch instruction counter");
TEST_ASSERT_EQUAL_MESSAGE(1, cpu->counters.branches_taken, "BCS should not increment branch instruction taken counter");
/* BEQ */
cpu->state.pc = 0x0000;
cpu->state.status |= CPU_6502_STATUS_ZERO;
MEMORY_write(mem, 0x0000, 0xF0);
MEMORY_write(mem, 0x0001, 0x02);
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_MESSAGE(3, cpu->counters.branches, "BEQ should increment branch instruction counter");
TEST_ASSERT_EQUAL_MESSAGE(2, cpu->counters.branches_taken, "BEQ should not increment branch instruction taken counter");
/* BNE */
cpu->state.pc = 0x0000;
MEMORY_write(mem, 0x0000, 0xD0);
MEMORY_write(mem, 0x0001, 0x02);
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_MESSAGE(4, cpu->counters.branches, "BNE should increment branch instruction counter");
TEST_ASSERT_EQUAL_MESSAGE(2, cpu->counters.branches_taken, "BNE should not increment branch instruction taken counter");
/* BMI */
cpu->state.pc = 0x0000;
cpu->state.status |= CPU_6502_STATUS_NEGATIVE;
MEMORY_write(mem, 0x0000, 0x30);
MEMORY_write(mem, 0x0001, 0x02);
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_MESSAGE(5, cpu->counters.branches, "BMI should increment branch instruction counter");
TEST_ASSERT_EQUAL_MESSAGE(3, cpu->counters.branches_taken, "BMI should not increment branch instruction taken counter");
/* BPL */
cpu->state.pc = 0x0000;
MEMORY_write(mem, 0x0000, 0x10);
MEMORY_write(mem, 0x0001, 0x02);
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_MESSAGE(6, cpu->counters.branches, "BPL should increment branch instruction counter");
TEST_ASSERT_EQUAL_MESSAGE(3, cpu->counters.branches_taken, "BMI should not increment branch instruction taken counter");
/* BVC */
cpu->state.pc = 0x0000;
cpu->state.status |= CPU_6502_STATUS_OVERFLOW;
MEMORY_write(mem, 0x0000, 0x50);
MEMORY_write(mem, 0x0001, 0x02);
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_MESSAGE(7, cpu->counters.branches, "BVC should increment branch instruction counter");
TEST_ASSERT_EQUAL_MESSAGE(3, cpu->counters.branches_taken, "BVC should increment branch instruction taken counter");
/* BVS */
cpu->state.pc = 0x0000;
MEMORY_write(mem, 0x0000, 0x70);
MEMORY_write(mem, 0x0001, 0x02);
CPU_6502_step(cpu);
TEST_ASSERT_EQUAL_MESSAGE(8, cpu->counters.branches, "BVS should increment branch instruction counter");
TEST_ASSERT_EQUAL_MESSAGE(4, cpu->counters.branches_taken, "BVS should not increment branch instruction taken counter");
CPU_6502_delete(&cpu);
MEMORY_delete(&mem);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_CPU_6502_new_delete);
RUN_TEST(test_CPU_6502_initialization);
RUN_TEST(test_CPU_6502_nop_step);
RUN_TEST(test_CPU_6502_LDA_immediate);
RUN_TEST(test_CPU_6502_LDA_absolute);
RUN_TEST(test_CPU_6502_LDA_zero_page);
RUN_TEST(test_CPU_6502_LDA_zero_page_x);
RUN_TEST(test_CPU_6502_LDA_zero_page_x_should_not_carry);
RUN_TEST(test_CPU_6502_LDA_absolute_x);
RUN_TEST(test_CPU_6502_LDA_absolute_y);
RUN_TEST(test_CPU_6502_LDA_indirect_x);
RUN_TEST(test_CPU_6502_LDA_indirect_y);
RUN_TEST(test_CPU_6502_LDX);
RUN_TEST(test_CPU_6502_LDY);
RUN_TEST(test_CPU_6502_JMP_absolute);
RUN_TEST(test_CPU_6502_TXS);
RUN_TEST(test_CPU_6502_STA);
RUN_TEST(test_CPU_6502_BNE_with_equal);
RUN_TEST(test_CPU_6502_BNE_with_not_equal);
RUN_TEST(test_CPU_6502_BNE_with_not_equal_neg_offset);
RUN_TEST(test_CPU_6502_DEX);
RUN_TEST(test_CPU_6502_DEY);
RUN_TEST(test_CPU_6502_BEQ_equal);
RUN_TEST(test_CPU_6502_BEQ_not_equal);
RUN_TEST(test_CPU_6502_CMP_less_than);
RUN_TEST(test_CPU_6502_CMP_greater_than);
RUN_TEST(test_CPU_6502_CMP_equal);
RUN_TEST(test_CPU_6502_CLD);
RUN_TEST(test_CPU_6502_TYA);
RUN_TEST(test_CPU_6502_TAX);
RUN_TEST(test_CPU_6502_BPL);
RUN_TEST(test_CPU_6502_CLC);
RUN_TEST(test_CPU_6502_ADC_binary);
RUN_TEST(test_CPU_6502_EOR);
RUN_TEST(test_CPU_6502_SEI);
RUN_TEST(test_CPU_6502_INY);
RUN_TEST(test_CPU_6502_INX);
RUN_TEST(test_CPU_6502_INC);
RUN_TEST(test_CPU_6502_JSR);
RUN_TEST(test_CPU_6502_PHA);
RUN_TEST(test_CPU_6502_STY);
RUN_TEST(test_CPU_6502_PLA);
RUN_TEST(test_CPU_6502_RTS);
RUN_TEST(test_CPU_6502_JSR_RTS);
RUN_TEST(test_CPU_6502_BEQ);
RUN_TEST(test_CPU_6502_CPY);
RUN_TEST(test_CPU_6502_CPX);
RUN_TEST(test_CPU_6502_BCC);
RUN_TEST(test_CPU_6502_BMI);
RUN_TEST(test_CPU_6502_BCS);
RUN_TEST(test_CPU_6502_TSX);
RUN_TEST(test_CPU_6502_TXA);
RUN_TEST(test_CPU_6502_PLP);
RUN_TEST(test_CPU_6502_BVC);
RUN_TEST(test_CPU_6502_BVS);
RUN_TEST(test_CPU_6502_PHP);
RUN_TEST(test_CPU_6502_DEC);
RUN_TEST(test_CPU_6502_DEC_accumulator);
RUN_TEST(test_CPU_6502_AND);
RUN_TEST(test_CPU_6502_PHY);
RUN_TEST(test_CPU_6502_PLY);
RUN_TEST(test_CPU_6502_JMP_indirect);
RUN_TEST(test_CPU_6502_BRK);
RUN_TEST(test_CPU_6502_STX);
RUN_TEST(test_CPU_6502_RTI);
RUN_TEST(test_CPU_6502_ORA);
RUN_TEST(test_CPU_6502_SEC);
RUN_TEST(test_CPU_6502_CLI);
RUN_TEST(test_CPU_6502_SED);
RUN_TEST(test_CPU_6502_CLV);
RUN_TEST(test_CPU_6502_BIT);
RUN_TEST(test_CPU_6502_ASL_accumulator);
RUN_TEST(test_CPU_6502_LSR_accumulator);
RUN_TEST(test_CPU_6502_ROL_accumulator);
RUN_TEST(test_CPU_6502_ROR_accumulator);
RUN_TEST(test_CPU_6502_SBC);
RUN_TEST(test_CPU_6502_SBC_negative_result);
RUN_TEST(test_CPU_6502_SBC_overflow);
RUN_TEST(test_CPU_6502_counters_reset_with_cpu);
RUN_TEST(test_CPU_6502_counters_instructions_increment_each_instruction);
RUN_TEST(test_CPU_6502_counters_cycles_increment_each_instruction);
RUN_TEST(test_CPU_6502_counters_branch);
return UNITY_END();
}