1
0
mirror of https://github.com/rkujawa/rk65c02.git synced 2025-04-13 08:37:02 +00:00

Preliminary support for emulation of instructions.

Some refactoring while here.
This commit is contained in:
Radosław Kujawa 2017-01-18 17:18:19 +01:00
parent f106e227cd
commit 52ce9bff8c
10 changed files with 145 additions and 59 deletions

View File

@ -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

1 OP_BRK brk IMPLIED 1 NULL
217 OP_CLD cld IMPLIED 1 NULL
218 OP_CMP_ABSY cmp ABSOLUTEY 3 NULL
219 OP_PHX phx IMPLIED 1 NULL
220 OP_STP stp IMPLIED 1 NULL emul_stp
221 OP_NOPI nop ABSOLUTE 3 NULL
222 OP_CMP_ABSX cmp ABSOLUTEX 3 NULL
223 OP_DEC_ABSX dec ABSOLUTEX 3 NULL

View File

@ -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;
}

View File

@ -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_*/

View File

@ -7,6 +7,7 @@
#include <string.h>
#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;

View File

@ -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_ */

View File

@ -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;
}
}
/*

View File

@ -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

View File

@ -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)

View File

@ -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)

36
test/test_emulation.c Normal file
View File

@ -0,0 +1,36 @@
#include <atf-c.h>
#include <stdio.h>
#include <string.h>
#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());
}