mirror of
https://github.com/jborza/emu6502.git
synced 2025-02-19 07:30:57 +00:00
introduced test6502 module for tests
This commit is contained in:
parent
c4cdce70c5
commit
65f7f959f9
21
cpu.c
21
cpu.c
@ -2,6 +2,7 @@
|
||||
#include "cpu.h"
|
||||
#include "opcodes.h"
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
|
||||
void* unimplemented_instruction(State6502* state) {
|
||||
printf("Error: unimplemented instruction\n");
|
||||
@ -28,7 +29,6 @@ void clear_state(State6502* state) {
|
||||
state->y = 0;
|
||||
state->pc = 0;
|
||||
state->sp = 0;
|
||||
//state -> flags = (Flags)0;
|
||||
clear_flags(state);
|
||||
state->running = 1;
|
||||
}
|
||||
@ -37,23 +37,6 @@ byte pop_byte(State6502* state) {
|
||||
return state->memory[state->pc++];
|
||||
}
|
||||
|
||||
void print_state(State6502* state) {
|
||||
printf("\tC=%d,Z=%d,I=%d,D=%d,B=%d,V=%d,N=%d\n", state->flags.c, state->flags.z, state->flags.i, state->flags.d, state->flags.b, state->flags.v, state->flags.n);
|
||||
printf("\tA $%02x X $%02x Y $%02x SP $%02x PC $%04x\n", state->a, state->x, state->y, state->sp, state->pc);
|
||||
}
|
||||
|
||||
void print_memory(State6502* state, word offset) {
|
||||
printf("$%04x: ", offset);
|
||||
for (byte i = 0; i < 32; i++) {
|
||||
printf("%02x", state->memory[offset + i]);
|
||||
if (i % 8 == 7)
|
||||
printf("|");
|
||||
else
|
||||
printf(" ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
//bitwise or with accumulator
|
||||
void ORA(State6502 * state, byte operand) {
|
||||
byte result = state->a | operand;
|
||||
@ -184,7 +167,9 @@ int emulate_6502_op(State6502 * state) {
|
||||
case LDA_INDY:
|
||||
{
|
||||
//post-indexed indirect
|
||||
//zero-page address as an argument
|
||||
byte indirect_address = pop_byte(state);
|
||||
//the address and the following byte is read as a word, adding Y register
|
||||
word address = read_word(state, indirect_address) + state->y;
|
||||
LDA(state, state->memory[address]);
|
||||
break;
|
||||
|
3
cpu.h
3
cpu.h
@ -3,7 +3,6 @@
|
||||
|
||||
void* unimplemented_instruction(State6502* state);
|
||||
int emulate_6502_op(State6502* state);
|
||||
void print_memory(State6502* state, word offset);
|
||||
void print_state(State6502* state);
|
||||
|
||||
void clear_flags(State6502* state);
|
||||
void clear_state(State6502* state);
|
@ -1,3 +1,2 @@
|
||||
#pragma once
|
||||
#include <stdio.h>
|
||||
void disassemble_6502(byte* buffer, word pc);
|
||||
void disassemble_6502(byte* buffer, word pc);
|
262
emu6502.c
262
emu6502.c
@ -3,11 +3,12 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include "state.h"
|
||||
#include "cpu.h"
|
||||
#include "disassembler.h"
|
||||
#include <memory.h>
|
||||
#include "opcodes.h"
|
||||
#include "test6502.h"
|
||||
|
||||
byte* read_game() {
|
||||
FILE* file = fopen("..\\bins\\tetris.bin", "r");
|
||||
@ -17,236 +18,37 @@ byte* read_game() {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void print_all(State6502* state) {
|
||||
print_state(state);
|
||||
print_memory(state, 0);
|
||||
//print_memory(state, 0x20);
|
||||
//print_memory(state, 0x40);
|
||||
//print_memory(state, 0x80);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void test_step(State6502* state) {
|
||||
print_all(state);
|
||||
disassemble_6502(state->memory, state->pc);
|
||||
emulate_6502_op(state);
|
||||
print_all(state);
|
||||
}
|
||||
|
||||
void test_cleanup(State6502* state) {
|
||||
free(state->memory);
|
||||
}
|
||||
|
||||
State6502 create_blank_state() {
|
||||
State6502 state;
|
||||
clear_state(&state);
|
||||
state.memory = malloc(4096);
|
||||
memset(state.memory, 0, sizeof(byte) * 4096);
|
||||
return state;
|
||||
}
|
||||
|
||||
void assertA(State6502* state, byte expected) {
|
||||
if (state->a != expected) {
|
||||
printf("Unexpected value in A, was %02x, expected %02x", expected, state->a);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void test_LDA_IMM() {
|
||||
//initialize
|
||||
State6502 state = create_blank_state();
|
||||
|
||||
//arrange
|
||||
char program[] = { LDA_IMM, 0xAA }; //LDA #$AA
|
||||
memcpy(state.memory, program, sizeof(program));
|
||||
|
||||
//act
|
||||
test_step(&state);
|
||||
|
||||
//assert
|
||||
assertA(&state, 0xAA);
|
||||
|
||||
test_cleanup(&state);
|
||||
}
|
||||
|
||||
void test_LDA_ZP() {
|
||||
//initialize
|
||||
State6502 state = create_blank_state();
|
||||
|
||||
//arrange
|
||||
char program[] = { LDA_ZP, 0x03, 0x00, 0xAA }; //LDA $3
|
||||
memcpy(state.memory, program, sizeof(program));
|
||||
|
||||
//act
|
||||
test_step(&state);
|
||||
|
||||
//assert
|
||||
assertA(&state, 0xAA);
|
||||
|
||||
//cleanup
|
||||
test_cleanup(&state);
|
||||
}
|
||||
|
||||
void test_LDA_ZPX() {
|
||||
//initialize
|
||||
State6502 state = create_blank_state();
|
||||
state.x = 0x01;
|
||||
|
||||
//arrange
|
||||
char program[] = { LDA_ZPX, 0x02, 0x00, 0xAA }; //LDA $2,x
|
||||
memcpy(state.memory, program, sizeof(program));
|
||||
|
||||
//act
|
||||
test_step(&state);
|
||||
|
||||
//assert
|
||||
assertA(&state, 0xAA);
|
||||
|
||||
//cleanup
|
||||
test_cleanup(&state);
|
||||
}
|
||||
|
||||
void test_LDA_ABS() {
|
||||
//initialize
|
||||
State6502 state = create_blank_state();
|
||||
|
||||
//arrange
|
||||
char program[] = { LDA_ABS, 0x01, 0x04, 0xAA }; //LDA $0401
|
||||
memcpy(state.memory, program, sizeof(program));
|
||||
state.memory[0x401] = 0xAA;
|
||||
|
||||
//act
|
||||
test_step(&state);
|
||||
|
||||
//assert
|
||||
assertA(&state, 0xAA);
|
||||
|
||||
//cleanup
|
||||
test_cleanup(&state);
|
||||
}
|
||||
|
||||
void test_LDA_ABSX() {
|
||||
//initialize
|
||||
State6502 state = create_blank_state();
|
||||
state.x = 0x02;
|
||||
|
||||
//arrange
|
||||
char program[] = { LDA_ABSX, 0x01, 0x04, 0xAA }; //LDA $0401,x
|
||||
memcpy(state.memory, program, sizeof(program));
|
||||
state.memory[0x403] = 0xAA;
|
||||
|
||||
//act
|
||||
test_step(&state);
|
||||
|
||||
//assert
|
||||
assertA(&state, 0xAA);
|
||||
|
||||
//cleanup
|
||||
test_cleanup(&state);
|
||||
}
|
||||
|
||||
void test_LDA_ABSY() {
|
||||
//initialize
|
||||
State6502 state = create_blank_state();
|
||||
state.y = 0x02;
|
||||
|
||||
//arrange
|
||||
char program[] = { LDA_ABSY, 0x01, 0x04, 0xAA }; //LDA $0401,y
|
||||
memcpy(state.memory, program, sizeof(program));
|
||||
state.memory[0x403] = 0xAA;
|
||||
|
||||
//act
|
||||
test_step(&state);
|
||||
|
||||
//assert
|
||||
assertA(&state, 0xAA);
|
||||
|
||||
//cleanup
|
||||
test_cleanup(&state);
|
||||
}
|
||||
|
||||
void test_LDA_INDX() {
|
||||
//initialize
|
||||
State6502 state = create_blank_state();
|
||||
state.x = 0x05;
|
||||
|
||||
//arrange
|
||||
char program[] = { LDA_INDX, 0x3E }; //LDA ($3E, x)
|
||||
memcpy(state.memory, program, sizeof(program));
|
||||
state.memory[0x0043] = 0xA9;
|
||||
state.memory[0x0044] = 0x04;
|
||||
state.memory[0x04A9] = 0xAA;
|
||||
|
||||
//act
|
||||
test_step(&state);
|
||||
|
||||
//assert
|
||||
assertA(&state, 0xAA);
|
||||
|
||||
//cleanup
|
||||
test_cleanup(&state);
|
||||
}
|
||||
|
||||
void test_LDA_INDY() {
|
||||
//initialize
|
||||
State6502 state = create_blank_state();
|
||||
state.y = 0x05;
|
||||
|
||||
//arrange
|
||||
char program[] = { LDA_INDY, 0x3E, 0x04, 0xAA }; //LDA ($3E),y
|
||||
memcpy(state.memory, program, sizeof(program));
|
||||
state.memory[0x3E] = 0xA0; //0x04A0
|
||||
state.memory[0x3F] = 0x04;
|
||||
state.memory[0x04A5] = 0xAA; //address 0x04A0 + 0x05 = 0x04A5
|
||||
|
||||
//act
|
||||
test_step(&state);
|
||||
|
||||
//assert
|
||||
assertA(&state, 0xAA);
|
||||
|
||||
//cleanup
|
||||
test_cleanup(&state);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_LDA_IMM();
|
||||
test_LDA_ZP();
|
||||
test_LDA_ZPX();
|
||||
test_LDA_ABS();
|
||||
test_LDA_ABSX();
|
||||
test_LDA_ABSY();
|
||||
test_LDA_INDX();
|
||||
test_LDA_INDY();
|
||||
run_tests();
|
||||
}
|
||||
|
||||
int emulate() {
|
||||
State6502 state;
|
||||
memset(&state.memory, 0, sizeof(State6502));
|
||||
print_state(&state);
|
||||
clear_state(&state);
|
||||
byte* memory = read_game();
|
||||
//state.memory = read_game();
|
||||
state.memory = malloc(4096);
|
||||
memset(state.memory, 0, sizeof(byte) * 4096);
|
||||
state.memory[0] = 0xEA;
|
||||
state.memory[1] = 0x05; //ORA $a0
|
||||
state.memory[2] = 0xA0;
|
||||
state.memory[3] = 0xEA; //NOP
|
||||
state.memory[4] = 0x09; //ORA #$ff
|
||||
state.memory[5] = 0xff;
|
||||
state.memory[6] = 0xA9; //LDA
|
||||
state.memory[7] = 0x00; //0
|
||||
state.memory[8] = 0x0D; //ORA $1234
|
||||
state.memory[9] = 0x34;
|
||||
state.memory[10] = 0x02;
|
||||
state.memory[0xA0] = 0x13;
|
||||
state.memory[0x0234] = 0xAA;
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
print_all(&state);
|
||||
disassemble_6502(state.memory, state.pc);
|
||||
emulate_6502_op(&state);
|
||||
}
|
||||
}
|
||||
//void emulate() {
|
||||
// State6502 state;
|
||||
// memset(&state.memory, 0, sizeof(State6502));
|
||||
// print_state(&state);
|
||||
// clear_state(&state);
|
||||
// byte* memory = read_game();
|
||||
// //state.memory = read_game();
|
||||
// state.memory = malloc(4096);
|
||||
// memset(state.memory, 0, sizeof(byte) * 4096);
|
||||
// state.memory[0] = 0xEA;
|
||||
// state.memory[1] = 0x05; //ORA $a0
|
||||
// state.memory[2] = 0xA0;
|
||||
// state.memory[3] = 0xEA; //NOP
|
||||
// state.memory[4] = 0x09; //ORA #$ff
|
||||
// state.memory[5] = 0xff;
|
||||
// state.memory[6] = 0xA9; //LDA
|
||||
// state.memory[7] = 0x00; //0
|
||||
// state.memory[8] = 0x0D; //ORA $1234
|
||||
// state.memory[9] = 0x34;
|
||||
// state.memory[10] = 0x02;
|
||||
// state.memory[0xA0] = 0x13;
|
||||
// state.memory[0x0234] = 0xAA;
|
||||
//
|
||||
// for (int i = 0; i < 10; i++) {
|
||||
// print_all(&state);
|
||||
// disassemble_6502(state.memory, state.pc);
|
||||
// emulate_6502_op(&state);
|
||||
// }
|
||||
//}
|
237
test6502.c
Normal file
237
test6502.c
Normal file
@ -0,0 +1,237 @@
|
||||
#include <memory.h>
|
||||
#include "types.h"
|
||||
#include "test6502.h"
|
||||
#include "opcodes.h"
|
||||
#include "state.h"
|
||||
#include "disassembler.h"
|
||||
|
||||
void print_state(State6502* state) {
|
||||
printf("\tC=%d,Z=%d,I=%d,D=%d,B=%d,V=%d,N=%d\n", state->flags.c, state->flags.z, state->flags.i, state->flags.d, state->flags.b, state->flags.v, state->flags.n);
|
||||
printf("\tA $%02x X $%02x Y $%02x SP $%02x PC $%04x\n", state->a, state->x, state->y, state->sp, state->pc);
|
||||
}
|
||||
|
||||
void print_memory(State6502* state, word offset) {
|
||||
printf("$%04x: ", offset);
|
||||
for (byte i = 0; i < 32; i++) {
|
||||
printf("%02x", state->memory[offset + i]);
|
||||
if (i % 8 == 7)
|
||||
printf("|");
|
||||
else
|
||||
printf(" ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void print_all(State6502* state) {
|
||||
print_state(state);
|
||||
print_memory(state, 0);
|
||||
//print_memory(state, 0x20);
|
||||
//print_memory(state, 0x40);
|
||||
//print_memory(state, 0x80);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void test_step(State6502* state) {
|
||||
print_all(state);
|
||||
disassemble_6502(state->memory, state->pc);
|
||||
emulate_6502_op(state);
|
||||
print_all(state);
|
||||
}
|
||||
|
||||
void test_cleanup(State6502* state) {
|
||||
free(state->memory);
|
||||
}
|
||||
|
||||
State6502 create_blank_state() {
|
||||
State6502 state;
|
||||
clear_state(&state);
|
||||
state.memory = malloc(4096);
|
||||
memset(state.memory, 0, sizeof(byte) * 4096);
|
||||
return state;
|
||||
}
|
||||
|
||||
void assertA(State6502* state, byte expected) {
|
||||
if (state->a != expected) {
|
||||
printf("Unexpected value in A, was %02x, expected %02x", expected, state->a);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
|
||||
//
|
||||
|
||||
void test_LDA_IMM() {
|
||||
//initialize
|
||||
State6502 state = create_blank_state();
|
||||
|
||||
//arrange
|
||||
char program[] = { LDA_IMM, 0xAA }; //LDA #$AA
|
||||
memcpy(state.memory, program, sizeof(program));
|
||||
|
||||
//act
|
||||
test_step(&state);
|
||||
|
||||
//assert
|
||||
assertA(&state, 0xAA);
|
||||
|
||||
test_cleanup(&state);
|
||||
}
|
||||
|
||||
void test_LDA_ZP() {
|
||||
//initialize
|
||||
State6502 state = create_blank_state();
|
||||
|
||||
//arrange
|
||||
char program[] = { LDA_ZP, 0x03, 0x00, 0xAA }; //LDA $3
|
||||
memcpy(state.memory, program, sizeof(program));
|
||||
|
||||
//act
|
||||
test_step(&state);
|
||||
|
||||
//assert
|
||||
assertA(&state, 0xAA);
|
||||
|
||||
//cleanup
|
||||
test_cleanup(&state);
|
||||
}
|
||||
|
||||
void test_LDA_ZPX() {
|
||||
//initialize
|
||||
State6502 state = create_blank_state();
|
||||
state.x = 0x01;
|
||||
|
||||
//arrange
|
||||
char program[] = { LDA_ZPX, 0x02, 0x00, 0xAA }; //LDA $2,x
|
||||
memcpy(state.memory, program, sizeof(program));
|
||||
|
||||
//act
|
||||
test_step(&state);
|
||||
|
||||
//assert
|
||||
assertA(&state, 0xAA);
|
||||
|
||||
//cleanup
|
||||
test_cleanup(&state);
|
||||
}
|
||||
|
||||
void test_LDA_ABS() {
|
||||
//initialize
|
||||
State6502 state = create_blank_state();
|
||||
|
||||
//arrange
|
||||
char program[] = { LDA_ABS, 0x01, 0x04, 0xAA }; //LDA $0401
|
||||
memcpy(state.memory, program, sizeof(program));
|
||||
state.memory[0x401] = 0xAA;
|
||||
|
||||
//act
|
||||
test_step(&state);
|
||||
|
||||
//assert
|
||||
assertA(&state, 0xAA);
|
||||
|
||||
//cleanup
|
||||
test_cleanup(&state);
|
||||
}
|
||||
|
||||
void test_LDA_ABSX() {
|
||||
//initialize
|
||||
State6502 state = create_blank_state();
|
||||
state.x = 0x02;
|
||||
|
||||
//arrange
|
||||
char program[] = { LDA_ABSX, 0x01, 0x04, 0xAA }; //LDA $0401,x
|
||||
memcpy(state.memory, program, sizeof(program));
|
||||
state.memory[0x403] = 0xAA;
|
||||
|
||||
//act
|
||||
test_step(&state);
|
||||
|
||||
//assert
|
||||
assertA(&state, 0xAA);
|
||||
|
||||
//cleanup
|
||||
test_cleanup(&state);
|
||||
}
|
||||
|
||||
void test_LDA_ABSY() {
|
||||
//initialize
|
||||
State6502 state = create_blank_state();
|
||||
state.y = 0x02;
|
||||
|
||||
//arrange
|
||||
char program[] = { LDA_ABSY, 0x01, 0x04, 0xAA }; //LDA $0401,y
|
||||
memcpy(state.memory, program, sizeof(program));
|
||||
state.memory[0x403] = 0xAA;
|
||||
|
||||
//act
|
||||
test_step(&state);
|
||||
|
||||
//assert
|
||||
assertA(&state, 0xAA);
|
||||
|
||||
//cleanup
|
||||
test_cleanup(&state);
|
||||
}
|
||||
|
||||
void test_LDA_INDX() {
|
||||
//initialize
|
||||
State6502 state = create_blank_state();
|
||||
state.x = 0x05;
|
||||
|
||||
//arrange
|
||||
char program[] = { LDA_INDX, 0x3E }; //LDA ($3E, x)
|
||||
memcpy(state.memory, program, sizeof(program));
|
||||
state.memory[0x0043] = 0xA9;
|
||||
state.memory[0x0044] = 0x04;
|
||||
state.memory[0x04A9] = 0xAA;
|
||||
|
||||
//act
|
||||
test_step(&state);
|
||||
|
||||
//assert
|
||||
assertA(&state, 0xAA);
|
||||
|
||||
//cleanup
|
||||
test_cleanup(&state);
|
||||
}
|
||||
|
||||
void test_LDA_INDY() {
|
||||
//initialize
|
||||
State6502 state = create_blank_state();
|
||||
state.y = 0x05;
|
||||
|
||||
//arrange
|
||||
char program[] = { LDA_INDY, 0x3E, 0x04, 0xAA }; //LDA ($3E),y
|
||||
memcpy(state.memory, program, sizeof(program));
|
||||
state.memory[0x3E] = 0xA0; //0x04A0
|
||||
state.memory[0x3F] = 0x04;
|
||||
state.memory[0x04A5] = 0xAA; //address 0x04A0 + 0x05 = 0x04A5
|
||||
|
||||
//act
|
||||
test_step(&state);
|
||||
|
||||
//assert
|
||||
assertA(&state, 0xAA);
|
||||
|
||||
//cleanup
|
||||
test_cleanup(&state);
|
||||
}
|
||||
|
||||
/////////////////////
|
||||
typedef void fp();
|
||||
fp* tests[4] = { test_LDA_IMM, test_LDA_ZP, test_LDA_ZPX, test_LDA_ABS };
|
||||
|
||||
void run_tests() {
|
||||
for(int i = 0; i < sizeof(tests)/sizeof(fp*); i++)
|
||||
tests[i]();
|
||||
test_LDA_IMM();
|
||||
test_LDA_ZP();
|
||||
test_LDA_ZPX();
|
||||
test_LDA_ABS();
|
||||
test_LDA_ABSX();
|
||||
test_LDA_ABSY();
|
||||
test_LDA_INDX();
|
||||
test_LDA_INDY();
|
||||
}
|
6
test6502.h
Normal file
6
test6502.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include "state.h"
|
||||
void run_tests();
|
||||
void print_memory(State6502* state, word offset);
|
||||
void print_state(State6502* state);
|
Loading…
x
Reference in New Issue
Block a user