summaryrefslogtreecommitdiff
path: root/emu
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2021-01-02 20:23:52 +0100
committerAndreas Baumann <mail@andreasbaumann.cc>2021-01-02 20:23:52 +0100
commit9490b470f3c0ac2357b60a56a893ab86556af634 (patch)
tree15d8358467ffdacc1bb76e9d9e926e6ee294070e /emu
parentaff63a211e9b1e397adb9dce726d8153beb96dcd (diff)
download6502-9490b470f3c0ac2357b60a56a893ab86556af634.tar.gz
6502-9490b470f3c0ac2357b60a56a893ab86556af634.tar.bz2
added VIA
added some more opcodes (SEI, CLI)
Diffstat (limited to 'emu')
-rw-r--r--emu/6502.c67
-rw-r--r--emu/6502.h43
-rw-r--r--emu/6522.c68
-rw-r--r--emu/6522.h19
-rw-r--r--emu/emu.c3
-rw-r--r--emu/emul.c13
-rw-r--r--emu/tests/test_cpu_6502.c412
7 files changed, 574 insertions, 51 deletions
diff --git a/emu/6502.c b/emu/6502.c
index 98af83a..77ea952 100644
--- a/emu/6502.c
+++ b/emu/6502.c
@@ -168,17 +168,17 @@ bool cpu_6502_is_carry( cpu_6502_t *cpu )
static const int cycles[NOF_OPCODES] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
- /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
/* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 2 */ 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
+ /* 2 */ 6, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0,
/* 3 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 4 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,
- /* 5 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 5 */ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
/* 6 */ 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 7 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 8 */ 0, 0, 0, 0, 0, 0, 3, 0, 2, 0, 0, 0, 0, 0, 4, 0,
+ /* 7 */ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 3, 3, 0, 2, 0, 0, 0, 0, 4, 4, 0,
/* 9 */ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
- /* A */ 2, 0, 2, 0, 3, 3, 3, 0, 0, 2, 0, 0, 0, 0, 0, 0,
+ /* A */ 2, 0, 2, 0, 3, 3, 3, 0, 0, 2, 0, 0, 0, 4, 0, 0,
/* B */ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* C */ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0,
/* D */ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -188,17 +188,17 @@ static const int cycles[NOF_OPCODES] = {
static const char mnemonic[NOF_OPCODES][MAX_MENMONIC_LENGTH] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
- /* 0 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???",
+ /* 0 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "ORA", "???", "???", "???", "???", "???", "???",
/* 1 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???",
- /* 2 */ "JSR", "???", "???", "???", "???", "???", "???", "???", "???", "???", "ROL", "???", "???", "???", "???", "???",
+ /* 2 */ "JSR", "???", "???", "???", "???", "???", "???", "???", "???", "AND", "ROL", "???", "???", "???", "???", "???",
/* 3 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???",
/* 4 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "JMP", "???", "???", "???",
- /* 5 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???",
+ /* 5 */ "???", "???", "???", "???", "???", "???", "???", "???", "CLI", "???", "???", "???", "???", "???", "???", "???",
/* 6 */ "RTS", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???",
- /* 7 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???",
- /* 8 */ "???", "???", "???", "???", "???", "???", "STX", "???", "DEY", "???", "???", "???", "???", "???", "STX", "???",
+ /* 7 */ "???", "???", "???", "???", "???", "???", "???", "???", "SEI", "???", "???", "???", "???", "???", "???", "???",
+ /* 8 */ "???", "???", "???", "???", "???", "STA", "STX", "???", "DEY", "???", "???", "???", "???", "STA", "STX", "???",
/* 9 */ "BCC", "???", "???", "???", "???", "???", "???", "???", "???", "???", "TXS", "???", "???", "???", "???", "???",
- /* A */ "LDY", "???", "LDX", "???", "LDY", "LDA", "LDX", "???", "???", "LDA", "???", "???", "???", "???", "???", "???",
+ /* A */ "LDY", "???", "LDX", "???", "LDY", "LDA", "LDX", "???", "???", "LDA", "???", "???", "???", "STA", "???", "???",
/* B */ "BCS", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???",
/* C */ "???", "???", "???", "???", "???", "???", "???", "???", "INY", "???", "DEX", "???", "???", "???", "???", "???",
/* D */ "BNE", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???",
@@ -345,6 +345,13 @@ void cpu_6502_step( cpu_6502_t *cpu )
update_negative_and_sign( cpu, cpu->A );
break;
+ case LDA_ABS:
+ operand16 = cpu_6502_read_word( cpu, cpu->PC );
+ cpu->PC += 2;
+ cpu->A = cpu_6502_read_byte( cpu, operand16 );
+ update_negative_and_sign( cpu, cpu->A );
+ break;
+
case STX_ZERO:
operand8 = cpu_6502_read_byte( cpu, cpu->PC );
cpu->PC++;
@@ -356,7 +363,19 @@ void cpu_6502_step( cpu_6502_t *cpu )
cpu->PC += 2;
cpu_6502_write_byte( cpu, operand16, cpu->X );
break;
-
+
+ case STA_ZERO:
+ operand8 = cpu_6502_read_byte( cpu, cpu->PC );
+ cpu->PC++;
+ cpu_6502_write_byte( cpu, operand8, cpu->A );
+ break;
+
+ case STA_ABS:
+ operand16 = cpu_6502_read_word( cpu, cpu->PC );
+ cpu->PC += 2;
+ cpu_6502_write_byte( cpu, operand16, cpu->A );
+ break;
+
case DEX_IMPL:
cpu->X--;
update_negative_and_sign( cpu, cpu->X );
@@ -391,6 +410,20 @@ void cpu_6502_step( cpu_6502_t *cpu )
cpu->A = tmp & 0xFF;
update_negative_and_sign( cpu, cpu->A );
break;
+
+ case AND_IMM:
+ operand8 = cpu_6502_read_byte( cpu, cpu->PC );
+ cpu->PC++;
+ cpu->A &= operand8;
+ update_negative_and_sign( cpu, cpu->A );
+ break;
+
+ case OR_IMM:
+ operand8 = cpu_6502_read_byte( cpu, cpu->PC );
+ cpu->PC++;
+ cpu->A |= operand8;
+ update_negative_and_sign( cpu, cpu->A );
+ break;
case CPX_IMM:
operand8 = cpu_6502_read_byte( cpu, cpu->PC );
@@ -463,6 +496,14 @@ void cpu_6502_step( cpu_6502_t *cpu )
cpu->PC++;
break;
+ case CLI_IMPL:
+ cpu->PS &= ~PS_I;
+ break;
+
+ case SEI_IMPL:
+ cpu->PS |= PS_I;
+ break;
+
case TXS_IMPL:
cpu->SP = cpu->X;
break;
diff --git a/emu/6502.h b/emu/6502.h
index c462fcc..a34443f 100644
--- a/emu/6502.h
+++ b/emu/6502.h
@@ -51,29 +51,36 @@ enum {
// opcodes
enum {
- LDX_IMM = 0xA2,
- LDX_ZERO = 0xA6,
- LDY_IMM = 0xA0,
- LDY_ZERO = 0xA4,
- LDA_IMM = 0xA9,
- LDA_ZERO = 0xA5,
+ LDX_IMM = 0xa2,
+ LDX_ZERO = 0xa6,
+ LDY_IMM = 0xa0,
+ LDY_ZERO = 0xa4,
+ LDA_IMM = 0xa9,
+ LDA_ZERO = 0xa5,
+ LDA_ABS = 0xad,
STX_ZERO = 0x86,
- STX_ABS = 0x8E,
- DEX_IMPL = 0xCA,
+ STX_ABS = 0x8e,
+ STA_ZERO = 0x85,
+ STA_ABS = 0x8d,
+ DEX_IMPL = 0xca,
DEY_IMPL = 0x88,
- INY_IMPL = 0xC8,
- INC_ZERO = 0xE6,
- ROL_ACC = 0x2A,
- BNE_REL = 0xD0,
+ INY_IMPL = 0xc8,
+ INC_ZERO = 0xe6,
+ ROL_ACC = 0x2a,
+ AND_IMM = 0x29,
+ OR_IMM = 0x09,
+ BNE_REL = 0xd0,
BCC_REL = 0x90,
- BCS_REL = 0xB0,
- JMP_ABS = 0x4C,
+ BCS_REL = 0xb0,
+ JMP_ABS = 0x4c,
JSR_ABS = 0x20,
RTS_IMPL = 0x60,
- TXS_IMPL = 0x9A,
- CPX_IMM = 0xE0,
- SBC_IMM = 0xE9,
- NOP_IMPL = 0xEA
+ CLI_IMPL = 0x58,
+ SEI_IMPL = 0x78,
+ TXS_IMPL = 0x9a,
+ CPX_IMM = 0xe0,
+ SBC_IMM = 0xe9,
+ NOP_IMPL = 0xea
};
enum {
diff --git a/emu/6522.c b/emu/6522.c
index df9144d..7cde206 100644
--- a/emu/6522.c
+++ b/emu/6522.c
@@ -22,14 +22,37 @@ void via_6522_init( via_6522_t *via, uint16_t addr, bool initialize )
if( initialize ) {
via->ddra = 0x00;
+ via->ddrb = 0x00;
+ via->pcr = 0x00;
+ via->ier = 0x00;
}
- bus_init( &via->bus );
+ bus_init( &via->busa );
+ bus_init( &via->busb );
}
-void via_6522_register( via_6522_t *via, device_t *device )
+void via_6522_reset( via_6522_t *via )
{
- bus_register( &via->bus, device, 0, 0 );
+ via->ddra = 0x00;
+ via->ddrb = 0x00;
+ via->pcr = 0x00;
+ via->ier = 0x00;
+}
+
+void via_6522_register( via_6522_t *via, int bus, device_t *device )
+{
+ switch( bus ) {
+ case PORTA:
+ bus_register( &via->busa, device, 0, 0 );
+ break;
+
+ case PORTB:
+ bus_register( &via->busb, device, 0, 0 );
+ break;
+
+ default:
+ fprintf( stderr, "ERROR: unable to register to VIA 6522 bus, use PORTA or PORTB\n" );
+ }
}
uint8_t via_6522_read( void *obj, uint16_t addr )
@@ -42,18 +65,38 @@ void via_6522_write( void *obj, uint16_t addr, uint8_t data )
via_6522_t *via = (via_6522_t *)obj;
switch( addr - via->addr ) {
- case DDRA:
- via->ddra = data;
- break;
-
case PORTA:
data &= via->ddra;
- for( int i = 0; i < via->bus.nof_devices; i++ ) {
- device_t *device = via->bus.devices[i].device;
+ for( int i = 0; i < via->busa.nof_devices; i++ ) {
+ device_t *device = via->busa.devices[i].device;
device->vtable->write( device, 0, data );
}
break;
+
+ case PORTB:
+ data &= via->ddrb;
+ for( int i = 0; i < via->busb.nof_devices; i++ ) {
+ device_t *device = via->busb.devices[i].device;
+ device->vtable->write( device, 0, data );
+ }
+ break;
+
+ case DDRB:
+ via->ddrb = data;
+ break;
+
+ case DDRA:
+ via->ddra = data;
+ break;
+ case PCR:
+ via->pcr = data;
+ break;
+
+ case IER:
+ via->ier = data;
+ break;
+
default:
fprintf( stderr, "ERROR: VIA 6522 not implemented address '%04X', data: '%02X'\n", addr, data );
break;
@@ -65,7 +108,8 @@ void via_6522_draw( void *obj, SDL_Renderer *renderer )
{
via_6522_t *via = (via_6522_t *)obj;
- via->bus.base.vtable->draw( &via->bus, renderer );
+ via->busa.base.vtable->draw( &via->busa, renderer );
+ via->busb.base.vtable->draw( &via->busb, renderer );
}
#endif
@@ -73,6 +117,8 @@ void via_6522_deinit( void *obj )
{
via_6522_t *via = (via_6522_t *)obj;
- bus_deinit( &via->bus );
+ bus_deinit( &via->busa );
+ bus_deinit( &via->busb );
+
device_deinit( &via->base );
}
diff --git a/emu/6522.h b/emu/6522.h
index 853bd3e..d3bade7 100644
--- a/emu/6522.h
+++ b/emu/6522.h
@@ -16,8 +16,16 @@
// the VIA is initialized with a base address, the addresses for
// the registers are relative to this base.
enum {
+ PORTB = 0x00,
PORTA = 0x01,
- DDRA = 0x03
+ DDRB = 0x02,
+ DDRA = 0x03,
+ T1LCL = 0x04,
+ T1LCH = 0x05,
+ ACR = 0x0b,
+ PCR = 0x0c,
+ IFR = 0x0d,
+ IER = 0x0e
};
typedef struct via_6522_t
@@ -27,14 +35,19 @@ typedef struct via_6522_t
uint16_t addr;
uint8_t ddra;
+ uint8_t ddrb;
+ uint8_t pcr;
+ uint8_t ier;
bool debug;
- bus_t bus;
+ bus_t busa;
+ bus_t busb;
} via_6522_t;
void via_6522_init( via_6522_t *via, uint16_t addr, bool initialize );
-void via_6522_register( via_6522_t *via, device_t *device );
+void via_6522_reset( via_6522_t *via );
+void via_6522_register( via_6522_t *via, int bus, device_t *device );
uint8_t via_6522_read( void *obj, uint16_t addr );
void via_6522_write( void *obj, uint16_t addr, uint8_t data );
diff --git a/emu/emu.c b/emu/emu.c
index 590f93e..b2293f9 100644
--- a/emu/emu.c
+++ b/emu/emu.c
@@ -53,7 +53,7 @@ int main( int argc, char *argv[] )
bus_register( &bus, &via.base, VIA_START, VIA_END );
seg7_init( &seg7, args_info.initialize_given );
- via_6522_register( &via, &seg7.base );
+ via_6522_register( &via, PORTA, &seg7.base );
cpu_6502_init( &cpu, &bus, args_info.initialize_given );
if( args_info.debug_given ) {
@@ -85,6 +85,7 @@ int main( int argc, char *argv[] )
emul_start( &emul );
cpu_6502_reset( &cpu );
+ via_6522_reset( &via );
emul_run( &emul, args_info.steps_arg );
diff --git a/emu/emul.c b/emu/emul.c
index ac4b64c..21ab58b 100644
--- a/emu/emul.c
+++ b/emu/emul.c
@@ -76,13 +76,14 @@ void emul_start( emul_t *emul )
static void print_help( void )
{
- fprintf( stderr, "CPU is paused, press\n"
+ fprintf( stderr, "Keyboard commands, press\n"
"(s) for single step\n"
"(f) fini (continue to next rts)\n"
"(c) for continue running\n"
"(b) break to single stepping\n"
"(+) speed up\n"
"(-) speed down\n"
+ "(p) push the button\n"
"(q) or (ESC) for shutting down\n" );
}
@@ -105,6 +106,9 @@ void emul_run( emul_t *emul, int nof_steps )
switch( event.type ) {
case SDL_KEYDOWN:
switch( event.key.keysym.sym ) {
+ case SDLK_h:
+ print_help( );
+ break;
case SDLK_ESCAPE:
case SDLK_q:
done = true;
@@ -138,6 +142,9 @@ void emul_run( emul_t *emul, int nof_steps )
}
fprintf( stderr, "CPU speed is %1.6f MHz now\n", ( (double)emul->speed / 1000000 ) );
break;
+ case SDLK_p:
+ // TODO:push the push button connected to CA1
+ break;
}
break;
@@ -153,10 +160,6 @@ void emul_run( emul_t *emul, int nof_steps )
SDL_RenderCopy( emul->renderer, emul->background_texture, NULL, NULL );
emul->bus->base.vtable->draw( emul->bus, emul->renderer );
- //~ for( int i = 0; i < emul->bus->nof_devices; i++ ) {
- //~ device_t *device = emul->bus->devices[i].device;
- //~ device->vtable->draw( device, emul->renderer );
- //~ }
SDL_RenderPresent( emul->renderer );
diff --git a/emu/tests/test_cpu_6502.c b/emu/tests/test_cpu_6502.c
index 94b68b4..2425be8 100644
--- a/emu/tests/test_cpu_6502.c
+++ b/emu/tests/test_cpu_6502.c
@@ -148,6 +148,68 @@ START_TEST( test_cpu_6502_txs )
}
END_TEST
+// CLI
+
+START_TEST( test_cpu_6502_cli )
+{
+ INIT_CPU_TEST
+
+ CODE_SET1( 0x58 ); // CLI
+
+ cpu.PS |= PS_I;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+1 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~PS_I, before_cpu.PS & ~PS_I );
+ ck_assert( !cpu_6502_is_interrupt( &cpu ) );
+ ck_assert_int_eq( cpu.A, before_cpu.A );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
+// SEI
+
+START_TEST( test_cpu_6502_sei )
+{
+ INIT_CPU_TEST
+
+ CODE_SET1( 0x78 ); // SEI
+
+ cpu.PS &= ~PS_I;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+1 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~PS_I, before_cpu.PS & ~PS_I );
+ ck_assert( cpu_6502_is_interrupt( &cpu ) );
+ ck_assert_int_eq( cpu.A, before_cpu.A );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
// LDA
START_TEST( test_cpu_6502_lda_flags_positive )
@@ -238,6 +300,37 @@ START_TEST( test_cpu_6502_lda_flags_zero )
}
END_TEST
+START_TEST( test_cpu_6502_lda_addr_abs )
+{
+ INIT_CPU_TEST
+
+ CODE_SET3( 0xad, 0x03, 0x01 ); // LDA #$0103
+
+ cpu.A = 0xff;
+ ram.cell[0x0103] = 0xea;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+3 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) );
+ ck_assert( !cpu_6502_is_zero( &cpu ) );
+ ck_assert( cpu_6502_is_negative( &cpu ) );
+ ck_assert_int_eq( cpu.A, 0xea );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 4 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
// LDY
START_TEST( test_cpu_6502_ldy_flags_positive )
@@ -480,6 +573,68 @@ START_TEST( test_cpu_6502_stx_addr_abs )
}
END_TEST
+// STA
+
+START_TEST( test_cpu_6502_sta_addr_zero )
+{
+ INIT_CPU_TEST
+
+ CODE_SET2( 0x85, 0x03 ); // STA $03
+
+ cpu.A = 0xea;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+2 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS, before_cpu.PS );
+ ck_assert_int_eq( cpu.A, before_cpu.A );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( &ram.cell[0x0], &before_ram.cell[0x0], 3 );
+ ck_assert_int_eq( ram.cell[0x03], 0xea );
+ ck_assert_mem_eq( &ram.cell[0x04], &before_ram.cell[0x04], 0x1FF - 0x03 );
+ ck_assert_int_eq( cpu.cycles, 3 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
+START_TEST( test_cpu_6502_sta_addr_abs )
+{
+ INIT_CPU_TEST
+
+ CODE_SET3( 0x8d, 0x03, 0x01 ); // STA #$0103
+
+ cpu.A = 0xea;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+3 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS, before_cpu.PS );
+ ck_assert_int_eq( cpu.A, before_cpu.A );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( &ram.cell[0x0], &before_ram.cell[0x0], 0x102 );
+ ck_assert_int_eq( ram.cell[0x0103], 0xea ); // modified value in memory
+ ck_assert_mem_eq( &ram.cell[0x104], &before_ram.cell[0x104], 0x1FF - 0x103 );
+ ck_assert_int_eq( cpu.cycles, 4 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
// INC
START_TEST( test_cpu_6502_inc_flags_positive )
@@ -888,6 +1043,250 @@ START_TEST( test_cpu_6502_rol_flags_accumulator_carry )
}
END_TEST
+// AND
+
+START_TEST( test_cpu_6502_and_flags_positive )
+{
+ INIT_CPU_TEST
+
+ CODE_SET2( 0x29, 0x0f ); // AND #$0f
+
+ cpu.A = 0x36;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+2 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) );
+ ck_assert( !cpu_6502_is_zero( &cpu ) );
+ ck_assert( !cpu_6502_is_negative( &cpu ) );
+ ck_assert_int_eq( cpu.A, 0x06 );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
+START_TEST( test_cpu_6502_and_flags_negative )
+{
+ INIT_CPU_TEST
+
+ CODE_SET2( 0x29, 0x8f ); // AND #$8f
+
+ cpu.A = 0xf6;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+2 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) );
+ ck_assert( !cpu_6502_is_zero( &cpu ) );
+ ck_assert( cpu_6502_is_negative( &cpu ) );
+ ck_assert_int_eq( cpu.A, 0x86 );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
+START_TEST( test_cpu_6502_and_flags_zero )
+{
+ INIT_CPU_TEST
+
+ CODE_SET2( 0x29, 0x00 ); // AND #$00
+
+ cpu.A = 0xf6;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+2 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) );
+ ck_assert( cpu_6502_is_zero( &cpu ) );
+ ck_assert( !cpu_6502_is_negative( &cpu ) );
+ ck_assert_int_eq( cpu.A, 0x00 );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
+START_TEST( test_cpu_6502_and_addr_imm )
+{
+ INIT_CPU_TEST
+
+ CODE_SET2( 0x29, 0xf0 ); // AND #$f0
+
+ cpu.A = 0xff;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+2 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) );
+ ck_assert( !cpu_6502_is_zero( &cpu ) );
+ ck_assert( cpu_6502_is_negative( &cpu ) );
+ ck_assert_int_eq( cpu.A, 0xf0 );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
+// ORA
+
+START_TEST( test_cpu_6502_ora_flags_positive )
+{
+ INIT_CPU_TEST
+
+ CODE_SET2( 0x09, 0x0f ); // ORA #$08
+
+ cpu.A = 0x37;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+2 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) );
+ ck_assert( !cpu_6502_is_zero( &cpu ) );
+ ck_assert( !cpu_6502_is_negative( &cpu ) );
+ ck_assert_int_eq( cpu.A, 0x3f );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
+START_TEST( test_cpu_6502_ora_flags_negative )
+{
+ INIT_CPU_TEST
+
+ CODE_SET2( 0x09, 0x22 ); // ORA #$22
+
+ cpu.A = 0x86;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+2 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) );
+ ck_assert( !cpu_6502_is_zero( &cpu ) );
+ ck_assert( cpu_6502_is_negative( &cpu ) );
+ ck_assert_int_eq( cpu.A, 0xa6 );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
+START_TEST( test_cpu_6502_ora_flags_zero )
+{
+ INIT_CPU_TEST
+
+ CODE_SET2( 0x09, 0x00 ); // ORA #$00
+
+ cpu.A = 0x00;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+2 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) );
+ ck_assert( cpu_6502_is_zero( &cpu ) );
+ ck_assert( !cpu_6502_is_negative( &cpu ) );
+ ck_assert_int_eq( cpu.A, 0x00 );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
+START_TEST( test_cpu_6502_ora_addr_imm )
+{
+ INIT_CPU_TEST
+
+ CODE_SET2( 0x09, 0x55 ); // ORA #$55
+
+ cpu.A = 0x1a;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+2 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) );
+ ck_assert( !cpu_6502_is_zero( &cpu ) );
+ ck_assert( !cpu_6502_is_negative( &cpu ) );
+ ck_assert_int_eq( cpu.A, 0x5f );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
// CPX
START_TEST( test_cpu_6502_cpx_flags_equals )
@@ -1267,9 +1666,12 @@ static Suite *make_cpu_6502_testsuite( void )
create_cpu_6502_testcase( suite, "NOP", test_cpu_6502_nop );
create_cpu_6502_testcase( suite, "TXS", test_cpu_6502_txs );
+ create_cpu_6502_testcase( suite, "CLI", test_cpu_6502_cli );
+ create_cpu_6502_testcase( suite, "SEI", test_cpu_6502_sei );
create_cpu_6502_testcase( suite, "LDA (flags, positive)", test_cpu_6502_lda_flags_positive );
create_cpu_6502_testcase( suite, "LDA (flags, negative)", test_cpu_6502_lda_flags_negative );
create_cpu_6502_testcase( suite, "LDA (flags, zero)", test_cpu_6502_lda_flags_zero );
+ create_cpu_6502_testcase( suite, "LDA (addr, absolute)", test_cpu_6502_lda_addr_abs );
create_cpu_6502_testcase( suite, "LDX (flags, positive)", test_cpu_6502_ldx_flags_positive );
create_cpu_6502_testcase( suite, "LDX (flags, negative)", test_cpu_6502_ldx_flags_negative );
create_cpu_6502_testcase( suite, "LDX (flags, zero)", test_cpu_6502_ldx_flags_zero );
@@ -1278,6 +1680,8 @@ static Suite *make_cpu_6502_testsuite( void )
create_cpu_6502_testcase( suite, "LDY (flags, zero)", test_cpu_6502_ldy_flags_zero );
create_cpu_6502_testcase( suite, "STX (addr, zero)", test_cpu_6502_stx_addr_zero );
create_cpu_6502_testcase( suite, "STX (addr, absolute)", test_cpu_6502_stx_addr_abs );
+ create_cpu_6502_testcase( suite, "STA (addr, zero)", test_cpu_6502_sta_addr_zero );
+ create_cpu_6502_testcase( suite, "STA (addr, absolute)", test_cpu_6502_sta_addr_abs );
create_cpu_6502_testcase( suite, "INC (flags, positive)", test_cpu_6502_inc_flags_positive );
create_cpu_6502_testcase( suite, "INC (flags, negative)", test_cpu_6502_inc_flags_negative );
create_cpu_6502_testcase( suite, "INC (flags, zero)", test_cpu_6502_inc_flags_zero );
@@ -1291,6 +1695,14 @@ static Suite *make_cpu_6502_testsuite( void )
create_cpu_6502_testcase( suite, "DEY (flags, negative)", test_cpu_6502_dey_flags_negative );
create_cpu_6502_testcase( suite, "DEY (flags, zero)", test_cpu_6502_dey_flags_zero );
create_cpu_6502_testcase( suite, "ROL (flags, carry)", test_cpu_6502_rol_flags_accumulator_carry );
+ create_cpu_6502_testcase( suite, "AND (flags, positive)", test_cpu_6502_and_flags_positive );
+ create_cpu_6502_testcase( suite, "AND (flags, negative)", test_cpu_6502_and_flags_negative );
+ create_cpu_6502_testcase( suite, "AND (flags, zero)", test_cpu_6502_and_flags_zero );
+ create_cpu_6502_testcase( suite, "AND (addr, immediate)", test_cpu_6502_and_addr_imm );
+ create_cpu_6502_testcase( suite, "ORA (flags, positive)", test_cpu_6502_ora_flags_positive );
+ create_cpu_6502_testcase( suite, "ORA (flags, negative)", test_cpu_6502_ora_flags_negative );
+ create_cpu_6502_testcase( suite, "ORA (flags, zero)", test_cpu_6502_ora_flags_zero );
+ create_cpu_6502_testcase( suite, "ORA (addr, immediate)", test_cpu_6502_ora_addr_imm );
create_cpu_6502_testcase( suite, "CPX (flags, equals)", test_cpu_6502_cpx_flags_equals );
create_cpu_6502_testcase( suite, "CPX (flags, less)", test_cpu_6502_cpx_flags_less );
create_cpu_6502_testcase( suite, "CPX (flags, greater)", test_cpu_6502_cpx_flags_greater );