mirror of
https://github.com/mist64/perfect6502.git
synced 2025-04-08 08:37:27 +00:00
cleanup
This commit is contained in:
parent
f101c89980
commit
3ef6b7636a
2
Makefile
2
Makefile
@ -1,4 +1,4 @@
|
||||
OBJS=runtime.o plugin.o perfect6502.o console.o emu.o
|
||||
OBJS=runtime.o runtime_init.o plugin.o perfect6502.o console.o emu.o
|
||||
CFLAGS=-Wall -O3
|
||||
CC=clang
|
||||
|
||||
|
53
broken_transistors.c
Normal file
53
broken_transistors.c
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
#define MAX_CYCLES 33000
|
||||
BOOL log_rw[MAX_CYCLES];
|
||||
uint16_t log_ab[MAX_CYCLES];
|
||||
uint8_t log_db[MAX_CYCLES];
|
||||
int
|
||||
main()
|
||||
{
|
||||
setupNodesAndTransistors();
|
||||
for (int run = -1; run < transistors; run ++) {
|
||||
#if 0
|
||||
/* skip a few runs! */
|
||||
if (run == 0)
|
||||
run = 180;
|
||||
#endif
|
||||
|
||||
if (run != -1) {
|
||||
printf("testing transistor %d: ", run);
|
||||
broken_transistor = run;
|
||||
}
|
||||
|
||||
bzero(memory, 65536);
|
||||
init_monitor();
|
||||
resetChip();
|
||||
BOOL fail = NO;
|
||||
for (int c = 0; c < MAX_CYCLES; c++) {
|
||||
step();
|
||||
if (run == -1) {
|
||||
log_rw[c] = isNodeHigh(rw);
|
||||
log_ab[c] = readAddressBus();
|
||||
log_db[c] = readDataBus();
|
||||
} else {
|
||||
if (log_rw[c] != isNodeHigh(rw)) {
|
||||
printf("FAIL, RW %d instead of %d @ %d\n", isNodeHigh(rw), log_rw[c], c);
|
||||
fail = YES;
|
||||
break;
|
||||
}
|
||||
if (log_ab[c] != readAddressBus()) {
|
||||
printf("FAIL, AB 0x%04x instead of 0x%04x @ %d\n", readAddressBus(), log_ab[c], c);
|
||||
fail = YES;
|
||||
break;
|
||||
}
|
||||
if (log_db[c] != readDataBus()) {
|
||||
printf("FAIL, DB 0x%02x instead of 0x%02x @ %d\n", readDataBus(), log_db[c], c);
|
||||
fail = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (run != -1 && !fail)
|
||||
printf("PASS\n");
|
||||
}
|
||||
}
|
171
compare.c
Normal file
171
compare.c
Normal file
@ -0,0 +1,171 @@
|
||||
|
||||
void
|
||||
full_step(uint16_t *a, uint8_t *d, BOOL *r_w)
|
||||
{
|
||||
step();
|
||||
step();
|
||||
|
||||
*a = readAddressBus();
|
||||
*d = readDataBus();
|
||||
*r_w = isNodeHigh(rw);
|
||||
}
|
||||
|
||||
#define RESET 0xF000
|
||||
#define A_OUT 0xF100
|
||||
#define X_OUT 0xF101
|
||||
#define Y_OUT 0xF102
|
||||
#define S_OUT 0xF103
|
||||
#define P_OUT 0xF104
|
||||
|
||||
#define TRIGGER1 0x5555
|
||||
uint16_t trigger2;
|
||||
#define TRIGGER3 0xAAAA
|
||||
|
||||
void
|
||||
setup_memory(int length, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t A, uint8_t X, uint8_t Y, uint8_t S, uint8_t P)
|
||||
{
|
||||
bzero(memory, 65536);
|
||||
|
||||
memory[0xFFFC] = RESET & 0xFF;
|
||||
memory[0xFFFD] = RESET >> 8;
|
||||
memory[RESET + 0x00] = 0xA2; /* LDA #S */
|
||||
memory[RESET + 0x01] = S;
|
||||
memory[RESET + 0x02] = 0x9A; /* TXS */
|
||||
memory[RESET + 0x03] = 0xA9; /* LDA #P */
|
||||
memory[RESET + 0x04] = P;
|
||||
memory[RESET + 0x05] = 0x48; /* PHA */
|
||||
memory[RESET + 0x06] = 0xA9; /* LHA #A */
|
||||
memory[RESET + 0x07] = A;
|
||||
memory[RESET + 0x08] = 0xA2; /* LDX #X */
|
||||
memory[RESET + 0x09] = X;
|
||||
memory[RESET + 0x0A] = 0xA0; /* LDY #Y */
|
||||
memory[RESET + 0x0B] = Y;
|
||||
memory[RESET + 0x0C] = 0x28; /* PLP */
|
||||
memory[RESET + 0x0D] = 0x8D; /* STA TRIGGER1 */
|
||||
memory[RESET + 0x0E] = TRIGGER1 & 0xFF;
|
||||
memory[RESET + 0x0F] = TRIGGER1 >> 8;
|
||||
memory[RESET + 0x10] = b1;
|
||||
uint16_t addr = RESET + 0x11;
|
||||
if (length >= 2)
|
||||
memory[addr++] = b2;
|
||||
if (length >= 3)
|
||||
memory[addr++] = b3;
|
||||
trigger2 = addr;
|
||||
memory[addr++] = 0x08; /* PHP */
|
||||
memory[addr++] = 0x8D; /* STA A_OUT */
|
||||
memory[addr++] = A_OUT & 0xFF;
|
||||
memory[addr++] = A_OUT >> 8;
|
||||
memory[addr++] = 0x8E; /* STX X_OUT */
|
||||
memory[addr++] = X_OUT & 0xFF;
|
||||
memory[addr++] = X_OUT >> 8;
|
||||
memory[addr++] = 0x8C; /* STY Y_OUT */
|
||||
memory[addr++] = Y_OUT & 0xFF;
|
||||
memory[addr++] = Y_OUT >> 8;
|
||||
memory[addr++] = 0x68; /* PLA */
|
||||
memory[addr++] = 0x8D; /* STA P_OUT */
|
||||
memory[addr++] = P_OUT & 0xFF;
|
||||
memory[addr++] = P_OUT >> 8;
|
||||
memory[addr++] = 0xBA; /* TSX */
|
||||
memory[addr++] = 0x8E; /* STX S_OUT */
|
||||
memory[addr++] = S_OUT & 0xFF;
|
||||
memory[addr++] = S_OUT >> 8;
|
||||
memory[addr++] = 0x8D; /* STA TRIGGER3 */
|
||||
memory[addr++] = TRIGGER3 & 0xFF;
|
||||
memory[addr++] = TRIGGER3 >> 8;
|
||||
memory[addr++] = 0xA9; /* LDA #$00 */
|
||||
memory[addr++] = 0x00;
|
||||
memory[addr++] = 0xF0; /* BEQ . */
|
||||
memory[addr++] = 0xFE;
|
||||
}
|
||||
|
||||
#define IS_READ_CYCLE (isNodeHigh(clk0) && isNodeHigh(rw))
|
||||
#define IS_WRITE_CYCLE (isNodeHigh(clk0) && !isNodeHigh(rw))
|
||||
#define IS_READING(a) (IS_READ_CYCLE && readAddressBus() == (a))
|
||||
|
||||
#define MAX_CYCLES 100
|
||||
|
||||
enum {
|
||||
STATE_BEFORE_INSTRUCTION,
|
||||
STATE_DURING_INSTRUCTION,
|
||||
STATE_FIRST_FETCH
|
||||
};
|
||||
|
||||
void
|
||||
setup_perfect()
|
||||
{
|
||||
setupNodesAndTransistors();
|
||||
verbose = 0;
|
||||
}
|
||||
|
||||
uint16_t instr_ab[10];
|
||||
uint8_t instr_db[10];
|
||||
BOOL instr_rw[10];
|
||||
|
||||
int
|
||||
perfect_measure_instruction()
|
||||
{
|
||||
int state = STATE_BEFORE_INSTRUCTION;
|
||||
int c = 0;
|
||||
for (int i = 0; i < MAX_CYCLES; i++) {
|
||||
uint16_t ab;
|
||||
uint8_t db;
|
||||
BOOL r_w;
|
||||
full_step(&ab, &db, &r_w);
|
||||
|
||||
if (state == STATE_DURING_INSTRUCTION && ab > trigger2) {
|
||||
/*
|
||||
* we see the FIRST fetch of the next instruction,
|
||||
* the test instruction MIGHT be done
|
||||
*/
|
||||
state = STATE_FIRST_FETCH;
|
||||
}
|
||||
|
||||
if (state == STATE_DURING_INSTRUCTION) {
|
||||
instr_rw[c] = r_w;
|
||||
instr_ab[c] = ab;
|
||||
instr_db[c] = db;
|
||||
c++;
|
||||
}
|
||||
|
||||
if (ab == TRIGGER1) {
|
||||
state = STATE_DURING_INSTRUCTION; /* we're done writing the trigger value; now comes the instruction! */
|
||||
}
|
||||
if (ab == TRIGGER3) {
|
||||
break; /* we're done dumping the CPU state */
|
||||
}
|
||||
};
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
extern void setup_emu(void);
|
||||
void reset_emu(void);
|
||||
extern int emu_measure_instruction(void);
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
setup_perfect();
|
||||
// setup_memory(1, 0xEA, 0x00, 0x00, 0, 0, 0, 0, 0);
|
||||
// setup_memory(2, 0xA9, 0x00, 0x00, 0, 0, 0, 0, 0);
|
||||
// setup_memory(2, 0xAD, 0x00, 0x10, 0, 0, 0, 0, 0);
|
||||
// setup_memory(3, 0xFE, 0x00, 0x10, 0, 0, 0, 0, 0);
|
||||
// setup_memory(3, 0x9D, 0xFF, 0x10, 0, 2, 0, 0, 0);
|
||||
setup_memory(1, 0x28, 0x00, 0x00, 0x55, 0, 0, 0x80, 0);
|
||||
resetChip();
|
||||
int instr_cycles = perfect_measure_instruction();
|
||||
|
||||
for (int c = 0; c < instr_cycles; c++ ) {
|
||||
printf("T%d ", c+1);
|
||||
if (instr_rw[c])
|
||||
printf("R $%04X\n", instr_ab[c]);
|
||||
else
|
||||
printf("W $%04X = $%02X\n", instr_ab[c], instr_db[c]);
|
||||
}
|
||||
|
||||
setup_emu();
|
||||
setup_memory(1, 0x48, 0x00, 0x00, 0x55, 0, 0, 0x80, 0);
|
||||
reset_emu();
|
||||
int instr_cycles2 = emu_measure_instruction();
|
||||
|
||||
}
|
910
perfect6502.c
910
perfect6502.c
@ -20,11 +20,9 @@
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
//#define TEST
|
||||
//#define BROKEN_TRANSISTORS
|
||||
#define TEST_ALL
|
||||
//#define COMPARE
|
||||
|
||||
/************************************************************
|
||||
*
|
||||
@ -802,99 +800,6 @@ chipStatus()
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/************************************************************
|
||||
*
|
||||
* Interface to OS Library Code / Monitor
|
||||
*
|
||||
************************************************************/
|
||||
|
||||
extern int kernal_dispatch();
|
||||
|
||||
/* imported by runtime.c */
|
||||
uint8_t A, X, Y, S, P;
|
||||
uint16_t PC;
|
||||
BOOL N, Z, C;
|
||||
|
||||
void
|
||||
init_monitor()
|
||||
{
|
||||
FILE *f;
|
||||
f = fopen("cbmbasic.bin", "r");
|
||||
fread(memory + 0xA000, 1, 17591, f);
|
||||
fclose(f);
|
||||
|
||||
/*
|
||||
* fill the KERNAL jumptable with JMP $F800;
|
||||
* we will put code there later that loads
|
||||
* the CPU state and returns
|
||||
*/
|
||||
for (uint16_t addr = 0xFF90; addr < 0xFFF3; addr += 3) {
|
||||
memory[addr+0] = 0x4C;
|
||||
memory[addr+1] = 0x00;
|
||||
memory[addr+2] = 0xF8;
|
||||
}
|
||||
|
||||
/*
|
||||
* cbmbasic scribbles over 0x01FE/0x1FF, so we can't start
|
||||
* with a stackpointer of 0 (which seems to be the state
|
||||
* after a RESET), so RESET jumps to 0xF000, which contains
|
||||
* a JSR to the actual start of cbmbasic
|
||||
*/
|
||||
memory[0xf000] = 0x20;
|
||||
memory[0xf001] = 0x94;
|
||||
memory[0xf002] = 0xE3;
|
||||
|
||||
memory[0xfffc] = 0x00;
|
||||
memory[0xfffd] = 0xF0;
|
||||
}
|
||||
|
||||
void
|
||||
handle_monitor()
|
||||
{
|
||||
PC = readPC();
|
||||
|
||||
if (PC >= 0xFF90 && ((PC - 0xFF90) % 3 == 0) && isNodeHigh(clk0)) {
|
||||
/* get register status out of 6502 */
|
||||
A = readA();
|
||||
X = readX();
|
||||
Y = readY();
|
||||
S = readSP();
|
||||
P = readP();
|
||||
N = P >> 7;
|
||||
Z = (P >> 1) & 1;
|
||||
C = P & 1;
|
||||
|
||||
kernal_dispatch();
|
||||
|
||||
/* encode processor status */
|
||||
P &= 0x7C; /* clear N, Z, C */
|
||||
P |= (N << 7) | (Z << 1) | C;
|
||||
|
||||
/*
|
||||
* all KERNAL calls make the 6502 jump to $F800, so we
|
||||
* put code there that loads the return state of the
|
||||
* KERNAL function and returns to the caller
|
||||
*/
|
||||
memory[0xf800] = 0xA9; /* LDA #P */
|
||||
memory[0xf801] = P;
|
||||
memory[0xf802] = 0x48; /* PHA */
|
||||
memory[0xf803] = 0xA9; /* LHA #A */
|
||||
memory[0xf804] = A;
|
||||
memory[0xf805] = 0xA2; /* LDX #X */
|
||||
memory[0xf806] = X;
|
||||
memory[0xf807] = 0xA0; /* LDY #Y */
|
||||
memory[0xf808] = Y;
|
||||
memory[0xf809] = 0x28; /* PLP */
|
||||
memory[0xf80a] = 0x60; /* RTS */
|
||||
/*
|
||||
* XXX we could do RTI instead of PLP/RTS, but RTI seems to be
|
||||
* XXX broken in the chip dump - after the KERNAL call at 0xFF90,
|
||||
* XXX the 6502 gets heavily confused about its program counter
|
||||
* XXX and executes garbage instructions
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************
|
||||
*
|
||||
* Main Clock Loop
|
||||
@ -917,24 +822,10 @@ halfStep()
|
||||
}
|
||||
|
||||
void
|
||||
step_quiet()
|
||||
step()
|
||||
{
|
||||
halfStep();
|
||||
cycle++;
|
||||
// if (!(cycle % 1000))
|
||||
// printf("%d\n", cycle);
|
||||
|
||||
#ifndef TEST
|
||||
handle_monitor();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
step()
|
||||
{
|
||||
step_quiet();
|
||||
if (verbose)
|
||||
chipStatus();
|
||||
}
|
||||
|
||||
/************************************************************
|
||||
@ -981,8 +872,6 @@ setupNodesAndTransistors()
|
||||
}
|
||||
}
|
||||
transistors = j;
|
||||
if (verbose)
|
||||
printf("unique transistors: %d\n", transistors);
|
||||
|
||||
/* cross reference transistors in nodes data structures */
|
||||
for (i = 0; i < transistors; i++) {
|
||||
@ -1032,13 +921,6 @@ resetChip()
|
||||
|
||||
/* release RESET */
|
||||
setHigh(res);
|
||||
|
||||
#ifdef TEST
|
||||
for (int i = 0; i < 62; i++)
|
||||
step_quiet();
|
||||
|
||||
cycle = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/************************************************************
|
||||
@ -1047,794 +929,36 @@ resetChip()
|
||||
*
|
||||
************************************************************/
|
||||
|
||||
void init_monitor();
|
||||
void handle_monitor();
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
#define BRK_LENGTH 2 /* BRK pushes PC + 2 onto the stack */
|
||||
|
||||
#define MAX_CYCLES 100
|
||||
#define SETUP_ADDR 0xF400
|
||||
#define INSTRUCTION_ADDR 0xF800
|
||||
#define BRK_VECTOR 0xFC00
|
||||
|
||||
#define MAGIC_8 0xEA
|
||||
#define MAGIC_16 0xAB1E
|
||||
#define MAGIC_IZX 0x1328
|
||||
#define MAGIC_IZY 0x1979
|
||||
#define X_OFFSET 5
|
||||
#define Y_OFFSET 10
|
||||
|
||||
#define IS_READ_CYCLE (isNodeHigh(clk0) && isNodeHigh(rw))
|
||||
#define IS_WRITE_CYCLE (isNodeHigh(clk0) && !isNodeHigh(rw))
|
||||
#define IS_READING(a) (IS_READ_CYCLE && readAddressBus() == (a))
|
||||
|
||||
struct {
|
||||
BOOL crash;
|
||||
int length;
|
||||
int cycles;
|
||||
int addmode;
|
||||
BOOL zp;
|
||||
BOOL abs;
|
||||
BOOL zpx;
|
||||
BOOL absx;
|
||||
BOOL zpy;
|
||||
BOOL absy;
|
||||
BOOL izx;
|
||||
BOOL izy;
|
||||
BOOL reads;
|
||||
BOOL writes;
|
||||
BOOL inputa;
|
||||
BOOL inputx;
|
||||
BOOL inputy;
|
||||
BOOL inputs;
|
||||
BOOL inputp;
|
||||
BOOL outputa;
|
||||
BOOL outputx;
|
||||
BOOL outputy;
|
||||
BOOL outputs;
|
||||
BOOL outputp;
|
||||
} data[256];
|
||||
|
||||
enum {
|
||||
ADDMODE_UNKNOWN,
|
||||
ADDMODE_IZY,
|
||||
ADDMODE_IZX,
|
||||
ADDMODE_ZPY,
|
||||
ADDMODE_ZPX,
|
||||
ADDMODE_ZP,
|
||||
ADDMODE_ABSY,
|
||||
ADDMODE_ABSX,
|
||||
ADDMODE_ABS,
|
||||
};
|
||||
|
||||
uint16_t initial_s, initial_p, initial_a, initial_x, initial_y;
|
||||
|
||||
void
|
||||
setup_memory(uint8_t opcode)
|
||||
{
|
||||
bzero(memory, 65536);
|
||||
|
||||
memory[0xFFFC] = SETUP_ADDR & 0xFF;
|
||||
memory[0xFFFD] = SETUP_ADDR >> 8;
|
||||
uint16_t addr = SETUP_ADDR;
|
||||
memory[addr++] = 0xA2; /* LDA #S */
|
||||
initial_s = addr;
|
||||
memory[addr++] = 0x7F;
|
||||
memory[addr++] = 0x9A; /* TXS */
|
||||
memory[addr++] = 0xA9; /* LDA #P */
|
||||
initial_p = addr;
|
||||
memory[addr++] = 0;
|
||||
memory[addr++] = 0x48; /* PHA */
|
||||
memory[addr++] = 0xA9; /* LHA #A */
|
||||
initial_a = addr;
|
||||
memory[addr++] = 0;
|
||||
memory[addr++] = 0xA2; /* LDX #X */
|
||||
initial_x = addr;
|
||||
memory[addr++] = 0;
|
||||
memory[addr++] = 0xA0; /* LDY #Y */
|
||||
initial_y = addr;
|
||||
memory[addr++] = 0;
|
||||
memory[addr++] = 0x28; /* PLP */
|
||||
memory[addr++] = 0x4C; /* JMP */
|
||||
memory[addr++] = INSTRUCTION_ADDR & 0xFF;
|
||||
memory[addr++] = INSTRUCTION_ADDR >> 8;
|
||||
|
||||
memory[INSTRUCTION_ADDR + 0] = opcode;
|
||||
memory[INSTRUCTION_ADDR + 1] = 0;
|
||||
memory[INSTRUCTION_ADDR + 2] = 0;
|
||||
memory[INSTRUCTION_ADDR + 3] = 0;
|
||||
|
||||
memory[0xFFFE] = BRK_VECTOR & 0xFF;
|
||||
memory[0xFFFF] = BRK_VECTOR >> 8;
|
||||
memory[BRK_VECTOR] = 0x00; /* loop there */
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
/* set up data structures for efficient emulation */
|
||||
setupNodesAndTransistors();
|
||||
|
||||
verbose = 0;
|
||||
|
||||
for (int opcode = 0x00; opcode <= 0xFF; opcode++) {
|
||||
// for (int opcode = 0xA9; opcode <= 0xAA; opcode++) {
|
||||
// for (int opcode = 0x15; opcode <= 0x15; opcode++) {
|
||||
printf("$%02X: ", opcode);
|
||||
|
||||
/**************************************************
|
||||
* find out length of instruction in bytes
|
||||
**************************************************/
|
||||
setup_memory(opcode);
|
||||
resetChip();
|
||||
int i;
|
||||
for (i = 0; i < MAX_CYCLES; i++) {
|
||||
step();
|
||||
if (IS_READING(BRK_VECTOR))
|
||||
break;
|
||||
};
|
||||
|
||||
if (i == MAX_CYCLES) {
|
||||
data[opcode].crash = YES;
|
||||
} else {
|
||||
data[opcode].crash = NO;
|
||||
uint16_t brk_addr = memory[0x0100+readSP()+2] | memory[0x0100+readSP()+3]<<8;
|
||||
data[opcode].length = brk_addr - INSTRUCTION_ADDR - BRK_LENGTH;
|
||||
|
||||
/**************************************************
|
||||
* find out length of instruction in cycles
|
||||
**************************************************/
|
||||
setup_memory(opcode);
|
||||
resetChip();
|
||||
for (i = 0; i < MAX_CYCLES; i++) {
|
||||
step();
|
||||
if ((readNOTIR() ^ 0xFF) == 0x00)
|
||||
break;
|
||||
};
|
||||
data[opcode].cycles = (cycle - 1) / 2;
|
||||
|
||||
/**************************************************
|
||||
* find out zp or abs reads
|
||||
**************************************************/
|
||||
setup_memory(opcode);
|
||||
memory[initial_x] = X_OFFSET;
|
||||
memory[initial_y] = Y_OFFSET;
|
||||
memory[MAGIC_8 + X_OFFSET + 0] = MAGIC_IZX & 0xFF;
|
||||
memory[MAGIC_8 + X_OFFSET + 1] = MAGIC_IZX >> 8;
|
||||
memory[MAGIC_8 + 0] = MAGIC_IZY & 0xFF;
|
||||
memory[MAGIC_8 + 1] = MAGIC_IZY >> 8;
|
||||
resetChip();
|
||||
if (data[opcode].length == 2) {
|
||||
memory[INSTRUCTION_ADDR + 1] = MAGIC_8;
|
||||
} else if (data[opcode].length == 3) {
|
||||
memory[INSTRUCTION_ADDR + 1] = MAGIC_16 & 0xFF;
|
||||
memory[INSTRUCTION_ADDR + 2] = MAGIC_16 >> 8;
|
||||
}
|
||||
|
||||
data[opcode].zp = NO;
|
||||
data[opcode].abs = NO;
|
||||
data[opcode].zpx = NO;
|
||||
data[opcode].absx = NO;
|
||||
data[opcode].zpy = NO;
|
||||
data[opcode].absy = NO;
|
||||
data[opcode].izx = NO;
|
||||
data[opcode].izy = NO;
|
||||
|
||||
data[opcode].reads = NO;
|
||||
data[opcode].writes = NO;
|
||||
|
||||
for (i = 0; i < data[opcode].cycles * 2 + 2; i++) {
|
||||
step();
|
||||
if (IS_READ_CYCLE || IS_WRITE_CYCLE) {
|
||||
//printf("RW@ %X\n", readAddressBus());
|
||||
BOOL is_data_access = YES;
|
||||
if (readAddressBus() == MAGIC_8)
|
||||
data[opcode].zp = YES;
|
||||
else if (readAddressBus() == MAGIC_16)
|
||||
data[opcode].abs = YES;
|
||||
else if (readAddressBus() == MAGIC_8 + X_OFFSET)
|
||||
data[opcode].zpx = YES;
|
||||
else if (readAddressBus() == MAGIC_16 + X_OFFSET)
|
||||
data[opcode].absx = YES;
|
||||
else if (readAddressBus() == MAGIC_8 + Y_OFFSET)
|
||||
data[opcode].zpy = YES;
|
||||
else if (readAddressBus() == MAGIC_16 + Y_OFFSET)
|
||||
data[opcode].absy = YES;
|
||||
else if (readAddressBus() == MAGIC_IZX)
|
||||
data[opcode].izx = YES;
|
||||
else if (readAddressBus() == MAGIC_IZY + Y_OFFSET)
|
||||
data[opcode].izy = YES;
|
||||
else
|
||||
is_data_access = NO;
|
||||
if (is_data_access)
|
||||
if (IS_READ_CYCLE)
|
||||
data[opcode].reads = YES;
|
||||
if (IS_WRITE_CYCLE)
|
||||
data[opcode].writes = YES;
|
||||
}
|
||||
};
|
||||
|
||||
data[opcode].addmode = ADDMODE_UNKNOWN;
|
||||
if (data[opcode].izy) {
|
||||
data[opcode].addmode = ADDMODE_IZY;
|
||||
} else if (data[opcode].izx) {
|
||||
data[opcode].addmode = ADDMODE_IZX;
|
||||
} else if (data[opcode].zpy) {
|
||||
data[opcode].addmode = ADDMODE_ZPY;
|
||||
} else if (data[opcode].zpx) {
|
||||
data[opcode].addmode = ADDMODE_ZPX;
|
||||
} else if (data[opcode].zp) {
|
||||
data[opcode].addmode = ADDMODE_ZP;
|
||||
} else if (data[opcode].absy) {
|
||||
data[opcode].addmode = ADDMODE_ABSY;
|
||||
} else if (data[opcode].absx) {
|
||||
data[opcode].addmode = ADDMODE_ABSX;
|
||||
} else if (data[opcode].abs) {
|
||||
data[opcode].addmode = ADDMODE_ABS;
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
|
||||
uint8_t magics[] = {
|
||||
/* all 8 bit primes */
|
||||
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
|
||||
// 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
|
||||
// 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
|
||||
// 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
|
||||
// 179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
|
||||
233, 239, 241, 251,
|
||||
/* and some other interesting numbers */
|
||||
0, 1, 0x55, 0xAA, 0xFF
|
||||
};
|
||||
/**************************************************
|
||||
* find out inputs
|
||||
**************************************************/
|
||||
//printf("AAA\n");
|
||||
for (int k = 0; k < 5; k++) {
|
||||
BOOL different = NO;
|
||||
int reads, writes;
|
||||
uint16_t read[100], write[100], write_data[100];
|
||||
uint8_t end_a, end_x, end_y, end_s, end_p;
|
||||
for (int j = 0; j < sizeof(magics)/sizeof(*magics); j++) {
|
||||
setup_memory(opcode);
|
||||
if (data[opcode].length == 2) {
|
||||
memory[INSTRUCTION_ADDR + 1] = MAGIC_8;
|
||||
} else if (data[opcode].length == 3) {
|
||||
memory[INSTRUCTION_ADDR + 1] = MAGIC_16 & 0xFF;
|
||||
memory[INSTRUCTION_ADDR + 2] = MAGIC_16 >> 8;
|
||||
}
|
||||
switch (k) {
|
||||
case 0: memory[initial_a] = magics[j]; break;
|
||||
case 1: memory[initial_x] = magics[j]; break;
|
||||
case 2: memory[initial_y] = magics[j]; break;
|
||||
case 3: memory[initial_s] = magics[j]; break;
|
||||
case 4: memory[initial_p] = magics[j]; break;
|
||||
}
|
||||
#define MAGIC_DATA8 3
|
||||
switch (data[opcode].addmode) {
|
||||
case ADDMODE_IZY:
|
||||
//TODO
|
||||
break;
|
||||
case ADDMODE_IZX:
|
||||
//TODO
|
||||
break;
|
||||
case ADDMODE_ZPY:
|
||||
memory[MAGIC_8 + memory[initial_y]] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ZPX:
|
||||
memory[MAGIC_8 + memory[initial_x]] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ZP:
|
||||
memory[MAGIC_8] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ABSY:
|
||||
memory[MAGIC_16 + memory[initial_y]] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ABSX:
|
||||
memory[MAGIC_16 + memory[initial_x]] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ABS:
|
||||
memory[MAGIC_16] = MAGIC_DATA8;
|
||||
break;
|
||||
}
|
||||
resetChip();
|
||||
writes = 0;
|
||||
reads = 0;
|
||||
for (i = 0; i < data[opcode].cycles * 2 + 2; i++) {
|
||||
step();
|
||||
if (IS_READ_CYCLE) {
|
||||
if (!j)
|
||||
read[reads++] = readAddressBus();
|
||||
else
|
||||
if (read[reads++] != readAddressBus()) {
|
||||
different = YES;
|
||||
//printf("[[[%d]]]", __LINE__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (IS_WRITE_CYCLE) {
|
||||
if (!j) {
|
||||
write[writes] = readAddressBus();
|
||||
write_data[writes++] = readDataBus();
|
||||
} else {
|
||||
if (write[writes] != readAddressBus()) {
|
||||
different = YES;
|
||||
//printf("[[[%d]]]", __LINE__);
|
||||
break;
|
||||
}
|
||||
if (write_data[writes++] != readDataBus()) {
|
||||
//printf("[[[%d:k=%d;%x@%x/%x]]]", __LINE__, k, write[writes-1], write_data[writes-1], readDataBus());
|
||||
different = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if (different) /* bus cycles were different */
|
||||
break;
|
||||
/* changes A */
|
||||
if (!(k == 0)) {
|
||||
if (!j) {
|
||||
end_a = readA();
|
||||
} else {
|
||||
if (end_a != readA()) {
|
||||
different = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* changes X */
|
||||
if (!(k == 1)) {
|
||||
if (!j) {
|
||||
end_x = readX();
|
||||
} else {
|
||||
if (end_x != readX()) {
|
||||
different = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* changes Y */
|
||||
if (!(k == 2)) {
|
||||
if (!j) {
|
||||
end_y = readY();
|
||||
} else {
|
||||
if (end_y != readY()) {
|
||||
different = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* changes S */
|
||||
if (!(k == 3)) {
|
||||
if (!j) {
|
||||
end_s = readSP();
|
||||
} else {
|
||||
if (end_s != readSP()) {
|
||||
different = YES;
|
||||
//printf("[%x/%x]", end_s, readSP());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* changes P */
|
||||
if (!(k == 4)) {
|
||||
if (!j) {
|
||||
end_p = readP();
|
||||
} else {
|
||||
if (end_p != readP()) {
|
||||
different = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//printf("[%d DIFF: %d]", k, different);
|
||||
switch (k) {
|
||||
case 0: data[opcode].inputa = different; break;
|
||||
case 1: data[opcode].inputx = different; break;
|
||||
case 2: data[opcode].inputy = different; break;
|
||||
case 3: data[opcode].inputs = different; break;
|
||||
case 4: data[opcode].inputp = different; break;
|
||||
}
|
||||
}
|
||||
//printf("BBB\n");
|
||||
|
||||
/**************************************************
|
||||
* find out outputs
|
||||
**************************************************/
|
||||
data[opcode].outputa = NO;
|
||||
data[opcode].outputx = NO;
|
||||
data[opcode].outputy = NO;
|
||||
data[opcode].outputs = NO;
|
||||
data[opcode].outputp = NO;
|
||||
|
||||
for (int j = 0; j < sizeof(magics)/sizeof(*magics) - 5; j++) {
|
||||
setup_memory(opcode);
|
||||
memory[initial_a] = magics[j + 0];
|
||||
memory[initial_x] = magics[j + 1];
|
||||
memory[initial_y] = magics[j + 2];
|
||||
memory[initial_s] = magics[j + 3];
|
||||
memory[initial_p] = magics[j + 4];
|
||||
if (data[opcode].length == 2) {
|
||||
memory[INSTRUCTION_ADDR + 1] = MAGIC_8;
|
||||
} else if (data[opcode].length == 3) {
|
||||
memory[INSTRUCTION_ADDR + 1] = MAGIC_16 & 0xFF;
|
||||
memory[INSTRUCTION_ADDR + 2] = MAGIC_16 >> 8;
|
||||
}
|
||||
switch (data[opcode].addmode) {
|
||||
case ADDMODE_IZY:
|
||||
//TODO
|
||||
break;
|
||||
case ADDMODE_IZX:
|
||||
//TODO
|
||||
break;
|
||||
case ADDMODE_ZPY:
|
||||
memory[MAGIC_8 + memory[initial_y]] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ZPX:
|
||||
memory[MAGIC_8 + memory[initial_x]] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ZP:
|
||||
memory[MAGIC_8] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ABSY:
|
||||
memory[MAGIC_16 + memory[initial_y]] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ABSX:
|
||||
memory[MAGIC_16 + memory[initial_x]] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ABS:
|
||||
memory[MAGIC_16] = MAGIC_DATA8;
|
||||
break;
|
||||
}
|
||||
resetChip();
|
||||
for (i = 0; i < data[opcode].cycles * 2 + 2; i++) {
|
||||
step();
|
||||
};
|
||||
if (readA() != magics[j + 0])
|
||||
data[opcode].outputa = YES;
|
||||
if (readX() != magics[j + 1])
|
||||
data[opcode].outputx = YES;
|
||||
if (readY() != magics[j + 2])
|
||||
data[opcode].outputy = YES;
|
||||
if (readSP() != magics[j + 3])
|
||||
data[opcode].outputs = YES;
|
||||
if ((readP() & 0xCF) != (magics[j + 4] & 0xCF)) /* NV#BDIZC */
|
||||
data[opcode].outputp = YES;
|
||||
}
|
||||
}
|
||||
|
||||
if (data[opcode].absx || data[opcode].zpx || data[opcode].izx) {
|
||||
if (!data[opcode].inputx)
|
||||
printf("input X?? ");
|
||||
data[opcode].inputx = NO;
|
||||
}
|
||||
if (data[opcode].absy || data[opcode].zpy || data[opcode].izy) {
|
||||
if (!data[opcode].inputy)
|
||||
printf("input Y?? ");
|
||||
data[opcode].inputy = NO;
|
||||
}
|
||||
|
||||
if (data[opcode].crash) {
|
||||
printf("CRASH\n");
|
||||
} else {
|
||||
printf("bytes: ");
|
||||
if (data[opcode].length < 0 || data[opcode].length > 9)
|
||||
printf("X ");
|
||||
else
|
||||
printf("%d ", data[opcode].length);
|
||||
printf("cycles: %d ", data[opcode].cycles);
|
||||
if (data[opcode].inputa)
|
||||
printf("A");
|
||||
else
|
||||
printf("_");
|
||||
if (data[opcode].inputx)
|
||||
printf("X");
|
||||
else
|
||||
printf("_");
|
||||
if (data[opcode].inputy)
|
||||
printf("Y");
|
||||
else
|
||||
printf("_");
|
||||
if (data[opcode].inputs)
|
||||
printf("S");
|
||||
else
|
||||
printf("_");
|
||||
if (data[opcode].inputp)
|
||||
printf("P");
|
||||
else
|
||||
printf("_");
|
||||
|
||||
printf("=>");
|
||||
|
||||
if (data[opcode].outputa)
|
||||
printf("A");
|
||||
else
|
||||
printf("_");
|
||||
if (data[opcode].outputx)
|
||||
printf("X");
|
||||
else
|
||||
printf("_");
|
||||
if (data[opcode].outputy)
|
||||
printf("Y");
|
||||
else
|
||||
printf("_");
|
||||
if (data[opcode].outputs)
|
||||
printf("S");
|
||||
else
|
||||
printf("_");
|
||||
if (data[opcode].outputp)
|
||||
printf("P");
|
||||
else
|
||||
printf("_");
|
||||
|
||||
printf(" ");
|
||||
|
||||
if (data[opcode].reads)
|
||||
printf("R");
|
||||
else
|
||||
printf("_");
|
||||
|
||||
if (data[opcode].writes)
|
||||
printf("W");
|
||||
else
|
||||
printf("_");
|
||||
|
||||
printf(" ");
|
||||
|
||||
switch (data[opcode].addmode) {
|
||||
case ADDMODE_IZY: printf("izy"); break;
|
||||
case ADDMODE_IZX: printf("izx"); break;
|
||||
case ADDMODE_ZPY: printf("zpy"); break;
|
||||
case ADDMODE_ZPX: printf("zpx"); break;
|
||||
case ADDMODE_ZP: printf("zp"); break;
|
||||
case ADDMODE_ABSY: printf("absy"); break;
|
||||
case ADDMODE_ABSX: printf("absx"); break;
|
||||
case ADDMODE_ABS: printf("abs"); break;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#include "test.c"
|
||||
#elif defined(BROKEN_TRANSISTORS)
|
||||
|
||||
#define MAX_CYCLES 33000
|
||||
BOOL log_rw[MAX_CYCLES];
|
||||
uint16_t log_ab[MAX_CYCLES];
|
||||
uint8_t log_db[MAX_CYCLES];
|
||||
int
|
||||
main()
|
||||
{
|
||||
setupNodesAndTransistors();
|
||||
for (int run = -1; run < transistors; run ++) {
|
||||
#if 0
|
||||
/* skip a few runs! */
|
||||
if (run == 0)
|
||||
run = 180;
|
||||
#endif
|
||||
|
||||
if (run != -1) {
|
||||
printf("testing transistor %d: ", run);
|
||||
broken_transistor = run;
|
||||
}
|
||||
|
||||
bzero(memory, 65536);
|
||||
init_monitor();
|
||||
resetChip();
|
||||
BOOL fail = NO;
|
||||
for (int c = 0; c < MAX_CYCLES; c++) {
|
||||
step();
|
||||
if (run == -1) {
|
||||
log_rw[c] = isNodeHigh(rw);
|
||||
log_ab[c] = readAddressBus();
|
||||
log_db[c] = readDataBus();
|
||||
} else {
|
||||
if (log_rw[c] != isNodeHigh(rw)) {
|
||||
printf("FAIL, RW %d instead of %d @ %d\n", isNodeHigh(rw), log_rw[c], c);
|
||||
fail = YES;
|
||||
break;
|
||||
}
|
||||
if (log_ab[c] != readAddressBus()) {
|
||||
printf("FAIL, AB 0x%04x instead of 0x%04x @ %d\n", readAddressBus(), log_ab[c], c);
|
||||
fail = YES;
|
||||
break;
|
||||
}
|
||||
if (log_db[c] != readDataBus()) {
|
||||
printf("FAIL, DB 0x%02x instead of 0x%02x @ %d\n", readDataBus(), log_db[c], c);
|
||||
fail = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (run != -1 && !fail)
|
||||
printf("PASS\n");
|
||||
}
|
||||
}
|
||||
#elif defined(TEST_ALL)
|
||||
|
||||
void
|
||||
full_step(uint16_t *a, uint8_t *d, BOOL *r_w)
|
||||
{
|
||||
step();
|
||||
step();
|
||||
|
||||
*a = readAddressBus();
|
||||
*d = readDataBus();
|
||||
*r_w = isNodeHigh(rw);
|
||||
}
|
||||
|
||||
#define RESET 0xF000
|
||||
#define A_OUT 0xF100
|
||||
#define X_OUT 0xF101
|
||||
#define Y_OUT 0xF102
|
||||
#define S_OUT 0xF103
|
||||
#define P_OUT 0xF104
|
||||
|
||||
#define TRIGGER1 0x5555
|
||||
uint16_t trigger2;
|
||||
#define TRIGGER3 0xAAAA
|
||||
|
||||
void
|
||||
setup_memory(int length, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t A, uint8_t X, uint8_t Y, uint8_t S, uint8_t P)
|
||||
{
|
||||
bzero(memory, 65536);
|
||||
|
||||
memory[0xFFFC] = RESET & 0xFF;
|
||||
memory[0xFFFD] = RESET >> 8;
|
||||
memory[RESET + 0x00] = 0xA2; /* LDA #S */
|
||||
memory[RESET + 0x01] = S;
|
||||
memory[RESET + 0x02] = 0x9A; /* TXS */
|
||||
memory[RESET + 0x03] = 0xA9; /* LDA #P */
|
||||
memory[RESET + 0x04] = P;
|
||||
memory[RESET + 0x05] = 0x48; /* PHA */
|
||||
memory[RESET + 0x06] = 0xA9; /* LHA #A */
|
||||
memory[RESET + 0x07] = A;
|
||||
memory[RESET + 0x08] = 0xA2; /* LDX #X */
|
||||
memory[RESET + 0x09] = X;
|
||||
memory[RESET + 0x0A] = 0xA0; /* LDY #Y */
|
||||
memory[RESET + 0x0B] = Y;
|
||||
memory[RESET + 0x0C] = 0x28; /* PLP */
|
||||
memory[RESET + 0x0D] = 0x8D; /* STA TRIGGER1 */
|
||||
memory[RESET + 0x0E] = TRIGGER1 & 0xFF;
|
||||
memory[RESET + 0x0F] = TRIGGER1 >> 8;
|
||||
memory[RESET + 0x10] = b1;
|
||||
uint16_t addr = RESET + 0x11;
|
||||
if (length >= 2)
|
||||
memory[addr++] = b2;
|
||||
if (length >= 3)
|
||||
memory[addr++] = b3;
|
||||
trigger2 = addr;
|
||||
memory[addr++] = 0x08; /* PHP */
|
||||
memory[addr++] = 0x8D; /* STA A_OUT */
|
||||
memory[addr++] = A_OUT & 0xFF;
|
||||
memory[addr++] = A_OUT >> 8;
|
||||
memory[addr++] = 0x8E; /* STX X_OUT */
|
||||
memory[addr++] = X_OUT & 0xFF;
|
||||
memory[addr++] = X_OUT >> 8;
|
||||
memory[addr++] = 0x8C; /* STY Y_OUT */
|
||||
memory[addr++] = Y_OUT & 0xFF;
|
||||
memory[addr++] = Y_OUT >> 8;
|
||||
memory[addr++] = 0x68; /* PLA */
|
||||
memory[addr++] = 0x8D; /* STA P_OUT */
|
||||
memory[addr++] = P_OUT & 0xFF;
|
||||
memory[addr++] = P_OUT >> 8;
|
||||
memory[addr++] = 0xBA; /* TSX */
|
||||
memory[addr++] = 0x8E; /* STX S_OUT */
|
||||
memory[addr++] = S_OUT & 0xFF;
|
||||
memory[addr++] = S_OUT >> 8;
|
||||
memory[addr++] = 0x8D; /* STA TRIGGER3 */
|
||||
memory[addr++] = TRIGGER3 & 0xFF;
|
||||
memory[addr++] = TRIGGER3 >> 8;
|
||||
memory[addr++] = 0xA9; /* LDA #$00 */
|
||||
memory[addr++] = 0x00;
|
||||
memory[addr++] = 0xF0; /* BEQ . */
|
||||
memory[addr++] = 0xFE;
|
||||
}
|
||||
|
||||
#define IS_READ_CYCLE (isNodeHigh(clk0) && isNodeHigh(rw))
|
||||
#define IS_WRITE_CYCLE (isNodeHigh(clk0) && !isNodeHigh(rw))
|
||||
#define IS_READING(a) (IS_READ_CYCLE && readAddressBus() == (a))
|
||||
|
||||
#define MAX_CYCLES 100
|
||||
|
||||
enum {
|
||||
STATE_BEFORE_INSTRUCTION,
|
||||
STATE_DURING_INSTRUCTION,
|
||||
STATE_FIRST_FETCH
|
||||
};
|
||||
|
||||
void
|
||||
setup_perfect()
|
||||
{
|
||||
setupNodesAndTransistors();
|
||||
verbose = 0;
|
||||
}
|
||||
|
||||
|
||||
extern void setup_emu(void);
|
||||
|
||||
uint16_t instr_ab[10];
|
||||
uint8_t instr_db[10];
|
||||
BOOL instr_rw[10];
|
||||
|
||||
int
|
||||
perfect_measure_instruction()
|
||||
{
|
||||
int state = STATE_BEFORE_INSTRUCTION;
|
||||
int c = 0;
|
||||
for (int i = 0; i < MAX_CYCLES; i++) {
|
||||
uint16_t ab;
|
||||
uint8_t db;
|
||||
BOOL r_w;
|
||||
full_step(&ab, &db, &r_w);
|
||||
|
||||
if (state == STATE_DURING_INSTRUCTION && ab > trigger2) {
|
||||
/*
|
||||
* we see the FIRST fetch of the next instruction,
|
||||
* the test instruction MIGHT be done
|
||||
*/
|
||||
state = STATE_FIRST_FETCH;
|
||||
}
|
||||
|
||||
if (state == STATE_DURING_INSTRUCTION) {
|
||||
instr_rw[c] = r_w;
|
||||
instr_ab[c] = ab;
|
||||
instr_db[c] = db;
|
||||
c++;
|
||||
}
|
||||
|
||||
if (ab == TRIGGER1) {
|
||||
state = STATE_DURING_INSTRUCTION; /* we're done writing the trigger value; now comes the instruction! */
|
||||
}
|
||||
if (ab == TRIGGER3) {
|
||||
break; /* we're done dumping the CPU state */
|
||||
}
|
||||
};
|
||||
|
||||
return c - 1;
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
setup_perfect();
|
||||
|
||||
// setup_memory(1, 0xEA, 0x00, 0x00, 0, 0, 0, 0, 0);
|
||||
// setup_memory(2, 0xA9, 0x00, 0x00, 0, 0, 0, 0, 0);
|
||||
// setup_memory(2, 0xAD, 0x00, 0x10, 0, 0, 0, 0, 0);
|
||||
setup_memory(3, 0xFE, 0x00, 0x10, 0, 0, 0, 0, 0);
|
||||
// setup_memory(3, 0x9D, 0xFF, 0x10, 0, 2, 0, 0, 0);
|
||||
resetChip();
|
||||
|
||||
int instr_cycles = perfect_measure_instruction();
|
||||
|
||||
for (int c = 0; c < instr_cycles; c++ ) {
|
||||
printf("T%d ", c+1);
|
||||
if (instr_rw[c])
|
||||
printf("R $%04X\n", instr_ab[c]);
|
||||
else
|
||||
printf("W $%04X = $%02X\n", instr_ab[c], instr_db[c]);
|
||||
}
|
||||
|
||||
setup_emu();
|
||||
|
||||
}
|
||||
#include "broken_transistors.c"
|
||||
#elif defined(COMPARE)
|
||||
#include "compare.c"
|
||||
#else
|
||||
int
|
||||
main()
|
||||
{
|
||||
/* set up data structures for efficient emulation */
|
||||
setupNodesAndTransistors();
|
||||
|
||||
/* set up memory for user program */
|
||||
init_monitor();
|
||||
|
||||
/* set initial state of nodes, transistors, inputs; RESET chip */
|
||||
resetChip();
|
||||
|
||||
/* emulate the 6502! */
|
||||
for (;;) {
|
||||
step();
|
||||
if (verbose)
|
||||
chipStatus();
|
||||
if (isNodeHigh(clk0))
|
||||
handle_monitor();
|
||||
|
||||
//chipStatus();
|
||||
//if (!(cycle % 1000)) printf("%d\n", cycle);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
104
runtime_init.c
Normal file
104
runtime_init.c
Normal file
@ -0,0 +1,104 @@
|
||||
#include <stdio.h>
|
||||
|
||||
extern unsigned char memory[65536]; /* XXX must be hooked up with RAM[] in runtime.c */
|
||||
|
||||
extern unsigned short readPC();
|
||||
extern unsigned char readA();
|
||||
extern unsigned char readX();
|
||||
extern unsigned char readY();
|
||||
extern unsigned char readSP();
|
||||
extern unsigned char readP();
|
||||
|
||||
/************************************************************
|
||||
*
|
||||
* Interface to OS Library Code / Monitor
|
||||
*
|
||||
************************************************************/
|
||||
|
||||
extern int kernal_dispatch();
|
||||
|
||||
/* imported by runtime.c */
|
||||
unsigned char A, X, Y, S, P;
|
||||
unsigned short PC;
|
||||
int N, Z, C;
|
||||
|
||||
void
|
||||
init_monitor()
|
||||
{
|
||||
FILE *f;
|
||||
f = fopen("cbmbasic.bin", "r");
|
||||
fread(memory + 0xA000, 1, 17591, f);
|
||||
fclose(f);
|
||||
|
||||
/*
|
||||
* fill the KERNAL jumptable with JMP $F800;
|
||||
* we will put code there later that loads
|
||||
* the CPU state and returns
|
||||
*/
|
||||
for (unsigned short addr = 0xFF90; addr < 0xFFF3; addr += 3) {
|
||||
memory[addr+0] = 0x4C;
|
||||
memory[addr+1] = 0x00;
|
||||
memory[addr+2] = 0xF8;
|
||||
}
|
||||
|
||||
/*
|
||||
* cbmbasic scribbles over 0x01FE/0x1FF, so we can't start
|
||||
* with a stackpointer of 0 (which seems to be the state
|
||||
* after a RESET), so RESET jumps to 0xF000, which contains
|
||||
* a JSR to the actual start of cbmbasic
|
||||
*/
|
||||
memory[0xf000] = 0x20;
|
||||
memory[0xf001] = 0x94;
|
||||
memory[0xf002] = 0xE3;
|
||||
|
||||
memory[0xfffc] = 0x00;
|
||||
memory[0xfffd] = 0xF0;
|
||||
}
|
||||
|
||||
void
|
||||
handle_monitor()
|
||||
{
|
||||
PC = readPC();
|
||||
|
||||
if (PC >= 0xFF90 && ((PC - 0xFF90) % 3 == 0)) {
|
||||
/* get register status out of 6502 */
|
||||
A = readA();
|
||||
X = readX();
|
||||
Y = readY();
|
||||
S = readSP();
|
||||
P = readP();
|
||||
N = P >> 7;
|
||||
Z = (P >> 1) & 1;
|
||||
C = P & 1;
|
||||
|
||||
kernal_dispatch();
|
||||
|
||||
/* encode processor status */
|
||||
P &= 0x7C; /* clear N, Z, C */
|
||||
P |= (N << 7) | (Z << 1) | C;
|
||||
|
||||
/*
|
||||
* all KERNAL calls make the 6502 jump to $F800, so we
|
||||
* put code there that loads the return state of the
|
||||
* KERNAL function and returns to the caller
|
||||
*/
|
||||
memory[0xf800] = 0xA9; /* LDA #P */
|
||||
memory[0xf801] = P;
|
||||
memory[0xf802] = 0x48; /* PHA */
|
||||
memory[0xf803] = 0xA9; /* LHA #A */
|
||||
memory[0xf804] = A;
|
||||
memory[0xf805] = 0xA2; /* LDX #X */
|
||||
memory[0xf806] = X;
|
||||
memory[0xf807] = 0xA0; /* LDY #Y */
|
||||
memory[0xf808] = Y;
|
||||
memory[0xf809] = 0x28; /* PLP */
|
||||
memory[0xf80a] = 0x60; /* RTS */
|
||||
/*
|
||||
* XXX we could do RTI instead of PLP/RTS, but RTI seems to be
|
||||
* XXX broken in the chip dump - after the KERNAL call at 0xFF90,
|
||||
* XXX the 6502 gets heavily confused about its program counter
|
||||
* XXX and executes garbage instructions
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
559
test.c
Normal file
559
test.c
Normal file
@ -0,0 +1,559 @@
|
||||
|
||||
#define BRK_LENGTH 2 /* BRK pushes PC + 2 onto the stack */
|
||||
|
||||
#define MAX_CYCLES 100
|
||||
#define SETUP_ADDR 0xF400
|
||||
#define INSTRUCTION_ADDR 0xF800
|
||||
#define BRK_VECTOR 0xFC00
|
||||
|
||||
#define MAGIC_8 0xEA
|
||||
#define MAGIC_16 0xAB1E
|
||||
#define MAGIC_IZX 0x1328
|
||||
#define MAGIC_IZY 0x1979
|
||||
#define X_OFFSET 5
|
||||
#define Y_OFFSET 10
|
||||
|
||||
#define IS_READ_CYCLE (isNodeHigh(clk0) && isNodeHigh(rw))
|
||||
#define IS_WRITE_CYCLE (isNodeHigh(clk0) && !isNodeHigh(rw))
|
||||
#define IS_READING(a) (IS_READ_CYCLE && readAddressBus() == (a))
|
||||
|
||||
struct {
|
||||
BOOL crash;
|
||||
int length;
|
||||
int cycles;
|
||||
int addmode;
|
||||
BOOL zp;
|
||||
BOOL abs;
|
||||
BOOL zpx;
|
||||
BOOL absx;
|
||||
BOOL zpy;
|
||||
BOOL absy;
|
||||
BOOL izx;
|
||||
BOOL izy;
|
||||
BOOL reads;
|
||||
BOOL writes;
|
||||
BOOL inputa;
|
||||
BOOL inputx;
|
||||
BOOL inputy;
|
||||
BOOL inputs;
|
||||
BOOL inputp;
|
||||
BOOL outputa;
|
||||
BOOL outputx;
|
||||
BOOL outputy;
|
||||
BOOL outputs;
|
||||
BOOL outputp;
|
||||
} data[256];
|
||||
|
||||
enum {
|
||||
ADDMODE_UNKNOWN,
|
||||
ADDMODE_IZY,
|
||||
ADDMODE_IZX,
|
||||
ADDMODE_ZPY,
|
||||
ADDMODE_ZPX,
|
||||
ADDMODE_ZP,
|
||||
ADDMODE_ABSY,
|
||||
ADDMODE_ABSX,
|
||||
ADDMODE_ABS,
|
||||
};
|
||||
|
||||
uint16_t initial_s, initial_p, initial_a, initial_x, initial_y;
|
||||
|
||||
void
|
||||
setup_memory(uint8_t opcode)
|
||||
{
|
||||
bzero(memory, 65536);
|
||||
|
||||
memory[0xFFFC] = SETUP_ADDR & 0xFF;
|
||||
memory[0xFFFD] = SETUP_ADDR >> 8;
|
||||
uint16_t addr = SETUP_ADDR;
|
||||
memory[addr++] = 0xA2; /* LDA #S */
|
||||
initial_s = addr;
|
||||
memory[addr++] = 0x7F;
|
||||
memory[addr++] = 0x9A; /* TXS */
|
||||
memory[addr++] = 0xA9; /* LDA #P */
|
||||
initial_p = addr;
|
||||
memory[addr++] = 0;
|
||||
memory[addr++] = 0x48; /* PHA */
|
||||
memory[addr++] = 0xA9; /* LHA #A */
|
||||
initial_a = addr;
|
||||
memory[addr++] = 0;
|
||||
memory[addr++] = 0xA2; /* LDX #X */
|
||||
initial_x = addr;
|
||||
memory[addr++] = 0;
|
||||
memory[addr++] = 0xA0; /* LDY #Y */
|
||||
initial_y = addr;
|
||||
memory[addr++] = 0;
|
||||
memory[addr++] = 0x28; /* PLP */
|
||||
memory[addr++] = 0x4C; /* JMP */
|
||||
memory[addr++] = INSTRUCTION_ADDR & 0xFF;
|
||||
memory[addr++] = INSTRUCTION_ADDR >> 8;
|
||||
|
||||
memory[INSTRUCTION_ADDR + 0] = opcode;
|
||||
memory[INSTRUCTION_ADDR + 1] = 0;
|
||||
memory[INSTRUCTION_ADDR + 2] = 0;
|
||||
memory[INSTRUCTION_ADDR + 3] = 0;
|
||||
|
||||
memory[0xFFFE] = BRK_VECTOR & 0xFF;
|
||||
memory[0xFFFF] = BRK_VECTOR >> 8;
|
||||
memory[BRK_VECTOR] = 0x00; /* loop there */
|
||||
}
|
||||
|
||||
void
|
||||
resetChip_test()
|
||||
{
|
||||
resetChip();
|
||||
for (int i = 0; i < 62; i++)
|
||||
step();
|
||||
|
||||
cycle = -1;
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
/* set up data structures for efficient emulation */
|
||||
setupNodesAndTransistors();
|
||||
|
||||
verbose = 0;
|
||||
|
||||
for (int opcode = 0x00; opcode <= 0xFF; opcode++) {
|
||||
// for (int opcode = 0xA9; opcode <= 0xAA; opcode++) {
|
||||
// for (int opcode = 0x15; opcode <= 0x15; opcode++) {
|
||||
printf("$%02X: ", opcode);
|
||||
|
||||
/**************************************************
|
||||
* find out length of instruction in bytes
|
||||
**************************************************/
|
||||
setup_memory(opcode);
|
||||
resetChip_test();
|
||||
int i;
|
||||
for (i = 0; i < MAX_CYCLES; i++) {
|
||||
step();
|
||||
if (IS_READING(BRK_VECTOR))
|
||||
break;
|
||||
};
|
||||
|
||||
if (i == MAX_CYCLES) {
|
||||
data[opcode].crash = YES;
|
||||
} else {
|
||||
data[opcode].crash = NO;
|
||||
uint16_t brk_addr = memory[0x0100+readSP()+2] | memory[0x0100+readSP()+3]<<8;
|
||||
data[opcode].length = brk_addr - INSTRUCTION_ADDR - BRK_LENGTH;
|
||||
|
||||
/**************************************************
|
||||
* find out length of instruction in cycles
|
||||
**************************************************/
|
||||
setup_memory(opcode);
|
||||
resetChip_test();
|
||||
for (i = 0; i < MAX_CYCLES; i++) {
|
||||
step();
|
||||
if ((readNOTIR() ^ 0xFF) == 0x00)
|
||||
break;
|
||||
};
|
||||
data[opcode].cycles = (cycle - 1) / 2;
|
||||
|
||||
/**************************************************
|
||||
* find out zp or abs reads
|
||||
**************************************************/
|
||||
setup_memory(opcode);
|
||||
memory[initial_x] = X_OFFSET;
|
||||
memory[initial_y] = Y_OFFSET;
|
||||
memory[MAGIC_8 + X_OFFSET + 0] = MAGIC_IZX & 0xFF;
|
||||
memory[MAGIC_8 + X_OFFSET + 1] = MAGIC_IZX >> 8;
|
||||
memory[MAGIC_8 + 0] = MAGIC_IZY & 0xFF;
|
||||
memory[MAGIC_8 + 1] = MAGIC_IZY >> 8;
|
||||
resetChip_test();
|
||||
if (data[opcode].length == 2) {
|
||||
memory[INSTRUCTION_ADDR + 1] = MAGIC_8;
|
||||
} else if (data[opcode].length == 3) {
|
||||
memory[INSTRUCTION_ADDR + 1] = MAGIC_16 & 0xFF;
|
||||
memory[INSTRUCTION_ADDR + 2] = MAGIC_16 >> 8;
|
||||
}
|
||||
|
||||
data[opcode].zp = NO;
|
||||
data[opcode].abs = NO;
|
||||
data[opcode].zpx = NO;
|
||||
data[opcode].absx = NO;
|
||||
data[opcode].zpy = NO;
|
||||
data[opcode].absy = NO;
|
||||
data[opcode].izx = NO;
|
||||
data[opcode].izy = NO;
|
||||
|
||||
data[opcode].reads = NO;
|
||||
data[opcode].writes = NO;
|
||||
|
||||
for (i = 0; i < data[opcode].cycles * 2 + 2; i++) {
|
||||
step();
|
||||
if (IS_READ_CYCLE || IS_WRITE_CYCLE) {
|
||||
//printf("RW@ %X\n", readAddressBus());
|
||||
BOOL is_data_access = YES;
|
||||
if (readAddressBus() == MAGIC_8)
|
||||
data[opcode].zp = YES;
|
||||
else if (readAddressBus() == MAGIC_16)
|
||||
data[opcode].abs = YES;
|
||||
else if (readAddressBus() == MAGIC_8 + X_OFFSET)
|
||||
data[opcode].zpx = YES;
|
||||
else if (readAddressBus() == MAGIC_16 + X_OFFSET)
|
||||
data[opcode].absx = YES;
|
||||
else if (readAddressBus() == MAGIC_8 + Y_OFFSET)
|
||||
data[opcode].zpy = YES;
|
||||
else if (readAddressBus() == MAGIC_16 + Y_OFFSET)
|
||||
data[opcode].absy = YES;
|
||||
else if (readAddressBus() == MAGIC_IZX)
|
||||
data[opcode].izx = YES;
|
||||
else if (readAddressBus() == MAGIC_IZY + Y_OFFSET)
|
||||
data[opcode].izy = YES;
|
||||
else
|
||||
is_data_access = NO;
|
||||
if (is_data_access)
|
||||
if (IS_READ_CYCLE)
|
||||
data[opcode].reads = YES;
|
||||
if (IS_WRITE_CYCLE)
|
||||
data[opcode].writes = YES;
|
||||
}
|
||||
};
|
||||
|
||||
data[opcode].addmode = ADDMODE_UNKNOWN;
|
||||
if (data[opcode].izy) {
|
||||
data[opcode].addmode = ADDMODE_IZY;
|
||||
} else if (data[opcode].izx) {
|
||||
data[opcode].addmode = ADDMODE_IZX;
|
||||
} else if (data[opcode].zpy) {
|
||||
data[opcode].addmode = ADDMODE_ZPY;
|
||||
} else if (data[opcode].zpx) {
|
||||
data[opcode].addmode = ADDMODE_ZPX;
|
||||
} else if (data[opcode].zp) {
|
||||
data[opcode].addmode = ADDMODE_ZP;
|
||||
} else if (data[opcode].absy) {
|
||||
data[opcode].addmode = ADDMODE_ABSY;
|
||||
} else if (data[opcode].absx) {
|
||||
data[opcode].addmode = ADDMODE_ABSX;
|
||||
} else if (data[opcode].abs) {
|
||||
data[opcode].addmode = ADDMODE_ABS;
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
|
||||
uint8_t magics[] = {
|
||||
/* all 8 bit primes */
|
||||
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
|
||||
// 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
|
||||
// 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
|
||||
// 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
|
||||
// 179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
|
||||
233, 239, 241, 251,
|
||||
/* and some other interesting numbers */
|
||||
0, 1, 0x55, 0xAA, 0xFF
|
||||
};
|
||||
/**************************************************
|
||||
* find out inputs
|
||||
**************************************************/
|
||||
//printf("AAA\n");
|
||||
for (int k = 0; k < 5; k++) {
|
||||
BOOL different = NO;
|
||||
int reads, writes;
|
||||
uint16_t read[100], write[100], write_data[100];
|
||||
uint8_t end_a, end_x, end_y, end_s, end_p;
|
||||
for (int j = 0; j < sizeof(magics)/sizeof(*magics); j++) {
|
||||
setup_memory(opcode);
|
||||
if (data[opcode].length == 2) {
|
||||
memory[INSTRUCTION_ADDR + 1] = MAGIC_8;
|
||||
} else if (data[opcode].length == 3) {
|
||||
memory[INSTRUCTION_ADDR + 1] = MAGIC_16 & 0xFF;
|
||||
memory[INSTRUCTION_ADDR + 2] = MAGIC_16 >> 8;
|
||||
}
|
||||
switch (k) {
|
||||
case 0: memory[initial_a] = magics[j]; break;
|
||||
case 1: memory[initial_x] = magics[j]; break;
|
||||
case 2: memory[initial_y] = magics[j]; break;
|
||||
case 3: memory[initial_s] = magics[j]; break;
|
||||
case 4: memory[initial_p] = magics[j]; break;
|
||||
}
|
||||
#define MAGIC_DATA8 3
|
||||
switch (data[opcode].addmode) {
|
||||
case ADDMODE_IZY:
|
||||
//TODO
|
||||
break;
|
||||
case ADDMODE_IZX:
|
||||
//TODO
|
||||
break;
|
||||
case ADDMODE_ZPY:
|
||||
memory[MAGIC_8 + memory[initial_y]] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ZPX:
|
||||
memory[MAGIC_8 + memory[initial_x]] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ZP:
|
||||
memory[MAGIC_8] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ABSY:
|
||||
memory[MAGIC_16 + memory[initial_y]] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ABSX:
|
||||
memory[MAGIC_16 + memory[initial_x]] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ABS:
|
||||
memory[MAGIC_16] = MAGIC_DATA8;
|
||||
break;
|
||||
}
|
||||
resetChip_test();
|
||||
writes = 0;
|
||||
reads = 0;
|
||||
for (i = 0; i < data[opcode].cycles * 2 + 2; i++) {
|
||||
step();
|
||||
if (IS_READ_CYCLE) {
|
||||
if (!j)
|
||||
read[reads++] = readAddressBus();
|
||||
else
|
||||
if (read[reads++] != readAddressBus()) {
|
||||
different = YES;
|
||||
//printf("[[[%d]]]", __LINE__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (IS_WRITE_CYCLE) {
|
||||
if (!j) {
|
||||
write[writes] = readAddressBus();
|
||||
write_data[writes++] = readDataBus();
|
||||
} else {
|
||||
if (write[writes] != readAddressBus()) {
|
||||
different = YES;
|
||||
//printf("[[[%d]]]", __LINE__);
|
||||
break;
|
||||
}
|
||||
if (write_data[writes++] != readDataBus()) {
|
||||
//printf("[[[%d:k=%d;%x@%x/%x]]]", __LINE__, k, write[writes-1], write_data[writes-1], readDataBus());
|
||||
different = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if (different) /* bus cycles were different */
|
||||
break;
|
||||
/* changes A */
|
||||
if (!(k == 0)) {
|
||||
if (!j) {
|
||||
end_a = readA();
|
||||
} else {
|
||||
if (end_a != readA()) {
|
||||
different = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* changes X */
|
||||
if (!(k == 1)) {
|
||||
if (!j) {
|
||||
end_x = readX();
|
||||
} else {
|
||||
if (end_x != readX()) {
|
||||
different = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* changes Y */
|
||||
if (!(k == 2)) {
|
||||
if (!j) {
|
||||
end_y = readY();
|
||||
} else {
|
||||
if (end_y != readY()) {
|
||||
different = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* changes S */
|
||||
if (!(k == 3)) {
|
||||
if (!j) {
|
||||
end_s = readSP();
|
||||
} else {
|
||||
if (end_s != readSP()) {
|
||||
different = YES;
|
||||
//printf("[%x/%x]", end_s, readSP());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* changes P */
|
||||
if (!(k == 4)) {
|
||||
if (!j) {
|
||||
end_p = readP();
|
||||
} else {
|
||||
if (end_p != readP()) {
|
||||
different = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//printf("[%d DIFF: %d]", k, different);
|
||||
switch (k) {
|
||||
case 0: data[opcode].inputa = different; break;
|
||||
case 1: data[opcode].inputx = different; break;
|
||||
case 2: data[opcode].inputy = different; break;
|
||||
case 3: data[opcode].inputs = different; break;
|
||||
case 4: data[opcode].inputp = different; break;
|
||||
}
|
||||
}
|
||||
//printf("BBB\n");
|
||||
|
||||
/**************************************************
|
||||
* find out outputs
|
||||
**************************************************/
|
||||
data[opcode].outputa = NO;
|
||||
data[opcode].outputx = NO;
|
||||
data[opcode].outputy = NO;
|
||||
data[opcode].outputs = NO;
|
||||
data[opcode].outputp = NO;
|
||||
|
||||
for (int j = 0; j < sizeof(magics)/sizeof(*magics) - 5; j++) {
|
||||
setup_memory(opcode);
|
||||
memory[initial_a] = magics[j + 0];
|
||||
memory[initial_x] = magics[j + 1];
|
||||
memory[initial_y] = magics[j + 2];
|
||||
memory[initial_s] = magics[j + 3];
|
||||
memory[initial_p] = magics[j + 4];
|
||||
if (data[opcode].length == 2) {
|
||||
memory[INSTRUCTION_ADDR + 1] = MAGIC_8;
|
||||
} else if (data[opcode].length == 3) {
|
||||
memory[INSTRUCTION_ADDR + 1] = MAGIC_16 & 0xFF;
|
||||
memory[INSTRUCTION_ADDR + 2] = MAGIC_16 >> 8;
|
||||
}
|
||||
switch (data[opcode].addmode) {
|
||||
case ADDMODE_IZY:
|
||||
//TODO
|
||||
break;
|
||||
case ADDMODE_IZX:
|
||||
//TODO
|
||||
break;
|
||||
case ADDMODE_ZPY:
|
||||
memory[MAGIC_8 + memory[initial_y]] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ZPX:
|
||||
memory[MAGIC_8 + memory[initial_x]] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ZP:
|
||||
memory[MAGIC_8] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ABSY:
|
||||
memory[MAGIC_16 + memory[initial_y]] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ABSX:
|
||||
memory[MAGIC_16 + memory[initial_x]] = MAGIC_DATA8;
|
||||
break;
|
||||
case ADDMODE_ABS:
|
||||
memory[MAGIC_16] = MAGIC_DATA8;
|
||||
break;
|
||||
}
|
||||
resetChip_test();
|
||||
for (i = 0; i < data[opcode].cycles * 2 + 2; i++) {
|
||||
step();
|
||||
};
|
||||
if (readA() != magics[j + 0])
|
||||
data[opcode].outputa = YES;
|
||||
if (readX() != magics[j + 1])
|
||||
data[opcode].outputx = YES;
|
||||
if (readY() != magics[j + 2])
|
||||
data[opcode].outputy = YES;
|
||||
if (readSP() != magics[j + 3])
|
||||
data[opcode].outputs = YES;
|
||||
if ((readP() & 0xCF) != (magics[j + 4] & 0xCF)) /* NV#BDIZC */
|
||||
data[opcode].outputp = YES;
|
||||
}
|
||||
}
|
||||
|
||||
if (data[opcode].absx || data[opcode].zpx || data[opcode].izx) {
|
||||
if (!data[opcode].inputx)
|
||||
printf("input X?? ");
|
||||
data[opcode].inputx = NO;
|
||||
}
|
||||
if (data[opcode].absy || data[opcode].zpy || data[opcode].izy) {
|
||||
if (!data[opcode].inputy)
|
||||
printf("input Y?? ");
|
||||
data[opcode].inputy = NO;
|
||||
}
|
||||
|
||||
if (data[opcode].crash) {
|
||||
printf("CRASH\n");
|
||||
} else {
|
||||
printf("bytes: ");
|
||||
if (data[opcode].length < 0 || data[opcode].length > 9)
|
||||
printf("X ");
|
||||
else
|
||||
printf("%d ", data[opcode].length);
|
||||
printf("cycles: %d ", data[opcode].cycles);
|
||||
if (data[opcode].inputa)
|
||||
printf("A");
|
||||
else
|
||||
printf("_");
|
||||
if (data[opcode].inputx)
|
||||
printf("X");
|
||||
else
|
||||
printf("_");
|
||||
if (data[opcode].inputy)
|
||||
printf("Y");
|
||||
else
|
||||
printf("_");
|
||||
if (data[opcode].inputs)
|
||||
printf("S");
|
||||
else
|
||||
printf("_");
|
||||
if (data[opcode].inputp)
|
||||
printf("P");
|
||||
else
|
||||
printf("_");
|
||||
|
||||
printf("=>");
|
||||
|
||||
if (data[opcode].outputa)
|
||||
printf("A");
|
||||
else
|
||||
printf("_");
|
||||
if (data[opcode].outputx)
|
||||
printf("X");
|
||||
else
|
||||
printf("_");
|
||||
if (data[opcode].outputy)
|
||||
printf("Y");
|
||||
else
|
||||
printf("_");
|
||||
if (data[opcode].outputs)
|
||||
printf("S");
|
||||
else
|
||||
printf("_");
|
||||
if (data[opcode].outputp)
|
||||
printf("P");
|
||||
else
|
||||
printf("_");
|
||||
|
||||
printf(" ");
|
||||
|
||||
if (data[opcode].reads)
|
||||
printf("R");
|
||||
else
|
||||
printf("_");
|
||||
|
||||
if (data[opcode].writes)
|
||||
printf("W");
|
||||
else
|
||||
printf("_");
|
||||
|
||||
printf(" ");
|
||||
|
||||
switch (data[opcode].addmode) {
|
||||
case ADDMODE_IZY: printf("izy"); break;
|
||||
case ADDMODE_IZX: printf("izx"); break;
|
||||
case ADDMODE_ZPY: printf("zpy"); break;
|
||||
case ADDMODE_ZPX: printf("zpx"); break;
|
||||
case ADDMODE_ZP: printf("zp"); break;
|
||||
case ADDMODE_ABSY: printf("absy"); break;
|
||||
case ADDMODE_ABSX: printf("absx"); break;
|
||||
case ADDMODE_ABS: printf("abs"); break;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user