diff --git a/src/65c02isa.csv b/src/65c02isa.csv index 4ee8c59..606bc94 100644 --- a/src/65c02isa.csv +++ b/src/65c02isa.csv @@ -217,7 +217,7 @@ OP_SMB5_ZP,"smb5",ZP,2,NULL OP_CLD,"cld",IMPLIED,1,NULL OP_CMP_ABSY,"cmp",ABSOLUTEY,3,NULL OP_PHX,"phx",IMPLIED,1,NULL -OP_STP,"stp",IMPLIED,1,NULL +OP_STP,"stp",IMPLIED,1,emul_stp OP_NOPI,"nop",ABSOLUTE,3,NULL OP_CMP_ABSX,"cmp",ABSOLUTEX,3,NULL OP_DEC_ABSX,"dec",ABSOLUTEX,3,NULL diff --git a/src/emulation.c b/src/emulation.c index 2477812..0f72e46 100644 --- a/src/emulation.c +++ b/src/emulation.c @@ -3,8 +3,15 @@ #include "emulation.h" void -emul_nop(void) +emul_nop(rk65c02emu_t *e, instruction_t *i) { printf("nop!\n"); + printf("nop!\n"); + printf("nop!\n"); } +void +emul_stp(rk65c02emu_t *e, instruction_t *i) +{ + e->state = STOPPED; +} diff --git a/src/emulation.h b/src/emulation.h index 9382eb8..e65562c 100644 --- a/src/emulation.h +++ b/src/emulation.h @@ -1,7 +1,11 @@ #ifndef _EMULATION_H_ #define _EMULATION_H_ -void emul_nop(void); +#include "rk65c02.h" +#include "instruction.h" + +void emul_nop(rk65c02emu_t *, instruction_t *); +void emul_stp(rk65c02emu_t *, instruction_t *); #endif /* _EMULATION_H_*/ diff --git a/src/instruction.c b/src/instruction.c index e806163..b3f4849 100644 --- a/src/instruction.c +++ b/src/instruction.c @@ -7,6 +7,7 @@ #include #include "bus.h" +#include "rk65c02.h" #include "65c02isa.h" #include "instruction.h" @@ -14,15 +15,15 @@ instruction_t instruction_fetch(bus_t *b, uint16_t addr) { instruction_t i; - uint8_t op; + instrdef_t id; - op = bus_read_1(b, addr); - i.def = instrdef_get(op); + i.opcode = bus_read_1(b, addr); + id = instruction_decode(i.opcode); //assert(i.def.opcode != OP_UNIMPL); /* handle operands */ - switch (i.def.mode) { + switch (id.mode) { case IMMEDIATE: case ZP: case ZPX: @@ -49,54 +50,64 @@ instruction_fetch(bus_t *b, uint16_t addr) return i; } +/*void +instruction_execute(rk65c02emu_t *e, instruction_t *i) +{ + id.emul(); + e->regs.PC += id.size; +}*/ + void instruction_print(instruction_t *i) { - switch (i->def.mode) { + instrdef_t id; + + id = instruction_decode(i->opcode); + switch (id.mode) { case IMPLIED: - printf("%s", i->def.mnemonic); + printf("%s", id.mnemonic); break; case ACCUMULATOR: - printf("%s A", i->def.mnemonic); + printf("%s A", id.mnemonic); break; case IMMEDIATE: - printf("%s #%X", i->def.mnemonic, i->op1); + printf("%s #%X", id.mnemonic, i->op1); break; case ZP: - printf("%s %X", i->def.mnemonic, i->op1); + printf("%s %X", id.mnemonic, i->op1); break; case ZPX: - printf("%s %X,X", i->def.mnemonic, i->op1); + printf("%s %X,X", id.mnemonic, i->op1); break; case ZPY: - printf("%s %X,Y", i->def.mnemonic, i->op1); + printf("%s %X,Y", id.mnemonic, i->op1); break; case IZP: - printf("%s (%X)", i->def.mnemonic, i->op1); + printf("%s (%X)", id.mnemonic, i->op1); break; case IZPX: - printf("%s (%X,X)", i->def.mnemonic, i->op1); + printf("%s (%X,X)", id.mnemonic, i->op1); break; case IZPY: - printf("%s (%X),Y", i->def.mnemonic, i->op1); + printf("%s (%X),Y", id.mnemonic, i->op1); break; case ABSOLUTE: - printf("%s %02X%02X", i->def.mnemonic, i->op2, i->op1); + printf("%s %02X%02X", id.mnemonic, i->op2, i->op1); break; case ABSOLUTEX: - printf("%s %02X%02X,X", i->def.mnemonic, i->op2, i->op1); + printf("%s %02X%02X,X", id.mnemonic, i->op2, i->op1); break; case ABSOLUTEY: - printf("%s %02X%02X,Y", i->def.mnemonic, i->op2, i->op1); + printf("%s %02X%02X,Y", id.mnemonic, i->op2, i->op1); break; case IABSOLUTE: - printf("%s (%02X%02X)", i->def.mnemonic, i->op2, i->op1); + printf("%s (%02X%02X)", id.mnemonic, i->op2, i->op1); break; case IABSOLUTEX: - printf("%s (%02X%02X,X)", i->def.mnemonic, i->op2, i->op1); + printf("%s (%02X%02X,X)", id.mnemonic, i->op2, i->op1); break; case RELATIVE: - printf("%s %02X%02X", i->def.mnemonic, i->op2, i->op1); + printf("%s %02X%02X", id.mnemonic, i->op2, i->op1); break; } } @@ -105,17 +116,19 @@ void disassemble(bus_t *b, uint16_t addr) { instruction_t i; + instrdef_t id; i = instruction_fetch(b, addr); + id = instruction_decode(i.opcode); printf("%X:\t", addr); instruction_print(&i); - printf("\t\t// %X", i.def.opcode); + printf("\t\t// %X", id.opcode); printf("\n"); } instrdef_t -instrdef_get(uint8_t opcode) +instruction_decode(uint8_t opcode) { instrdef_t id; diff --git a/src/instruction.h b/src/instruction.h index 52b86aa..3038820 100644 --- a/src/instruction.h +++ b/src/instruction.h @@ -1,6 +1,8 @@ #ifndef _INSTRUCTION_H_ #define _INSTRUCTION_H_ +#include "rk65c02.h" + typedef enum { IMPLIED, IMMEDIATE, @@ -19,27 +21,28 @@ typedef enum { ACCUMULATOR } addressing_t; -struct instrdef { - uint8_t opcode; - const char *mnemonic; - addressing_t mode; - uint8_t size; - void (*emul)(void); -}; - -typedef struct instrdef instrdef_t; - struct instruction { - instrdef_t def; + uint8_t opcode; uint8_t op1; uint8_t op2; }; typedef struct instruction instruction_t; +struct instrdef { + uint8_t opcode; + const char *mnemonic; + addressing_t mode; + uint8_t size; + void (*emul)(rk65c02emu_t *e, instruction_t *i); +}; + +typedef struct instrdef instrdef_t; + instruction_t instruction_fetch(bus_t *, uint16_t); +instrdef_t instruction_decode(uint8_t); void instruction_print(instruction_t *); void disassemble(bus_t *, uint16_t); -instrdef_t instrdef_get(uint8_t); +//void instruction_execute(rk65c02emu_t *, instruction_t *); #endif /* _INSTRUCTION_H_ */ diff --git a/src/rk65c02.c b/src/rk65c02.c index 161c740..db07f4d 100644 --- a/src/rk65c02.c +++ b/src/rk65c02.c @@ -10,29 +10,40 @@ #include "instruction.h" #include "rk65c02.h" -static bool run = false; - -void -rk6502_start(bus_t *b, uint16_t addr) { - instruction_t i; - reg_state_t r; +rk65c02emu_t +rk65c02_init(bus_t *b) +{ rk65c02emu_t e; e.bus = b; - e.regs = &r; - e.regs->PC = addr; + e.state = STOPPED; - run = true; - while (run) { - disassemble(e.bus, e.regs->PC); - i = instruction_fetch(e.bus, e.regs->PC); + return e; +} - //execute(i, r); +void +rk65c02_start(rk65c02emu_t *e) { + instruction_t i; + instrdef_t id; - if (i.def.opcode == 0xDB) // STP - run = false; + e->state = RUNNING; + while (e->state == RUNNING) { + disassemble(e->bus, e->regs.PC); + i = instruction_fetch(e->bus, e->regs.PC); + id = instruction_decode(i.opcode); + +// instruction_execute(e, i); + if (id.emul != NULL) + id.emul(e, &i); + else + printf("unimplemented opcode %X\n", i.opcode); + + +/* if (i.opcode == 0xDB) // STP + e->state = STOPPED;*/ + + e->regs.PC += id.size; - e.regs->PC += i.def.size; } } /* diff --git a/src/rk65c02.h b/src/rk65c02.h index cb8f930..b55a9f4 100644 --- a/src/rk65c02.h +++ b/src/rk65c02.h @@ -2,11 +2,10 @@ #define _RK6502_H_ #include "bus.h" -#include "instruction.h" typedef enum { STOPPED, - RUNNIG, + RUNNING, STEPPING } emu_state_t; @@ -25,9 +24,13 @@ typedef struct reg_state reg_state_t; struct rk65c02emu { emu_state_t state; bus_t *bus; - reg_state_t *regs; + reg_state_t regs; }; typedef struct rk65c02emu rk65c02emu_t; +rk65c02emu_t rk65c02_init(bus_t *); +void rk65c02_start(rk65c02emu_t *); + #endif + diff --git a/test/Makefile b/test/Makefile index 2ae1d7e..bf21e3e 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,11 +1,20 @@ -CFLAGS=-Wall -I../src +CFLAGS=-Wall -I../src -g LDFLAGS=-latf-c RK6502LIB=../src/librk65c02.a +TESTS=test_bus test_emulation -test_bus : test_bus.o +all : $(TESTS) + +test_bus : test_bus.o $(CC) -o test_bus $(LDFLAGS) $< $(RK6502LIB) +test_emulation : test_emulation.o + $(CC) -o test_emulation $(LDFLAGS) $< $(RK6502LIB) + %.o : %.c $(CC) $(CFLAGS) -c $< +clean : + rm -f *.o + rm -f $(TESTS) diff --git a/test/test_bus.c b/test/test_bus.c index e8333f7..c7c31b8 100644 --- a/test/test_bus.c +++ b/test/test_bus.c @@ -20,7 +20,7 @@ ATF_TC_BODY(bus__init, tc) ATF_TC_WITHOUT_HEAD(bus__foo); ATF_TC_BODY(bus__foo, tc) { - bus_t b; +// bus_t b; } ATF_TP_ADD_TCS(tp) diff --git a/test/test_emulation.c b/test/test_emulation.c new file mode 100644 index 0000000..2771cee --- /dev/null +++ b/test/test_emulation.c @@ -0,0 +1,36 @@ +#include + +#include +#include + +#include "bus.h" +#include "rk65c02.h" + +ATF_TC_WITHOUT_HEAD(emulation_nop); +ATF_TC_BODY(emulation_nop, tc) +{ + rk65c02emu_t e; + bus_t b; + + b = bus_init(); + e = rk65c02_init(&b); + + e.regs.PC = 0; + + bus_write_1(&b, 0, 0xEA); + bus_write_1(&b, 1, 0xDB); + + rk65c02_start(&e); + + ATF_CHECK(e.regs.PC == 2); + + bus_finish(&b); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, emulation_nop); + + return (atf_no_error()); +} +