This commit is contained in:
Michael Steil 2010-10-05 16:18:28 +00:00
parent f101c89980
commit 3ef6b7636a
6 changed files with 905 additions and 894 deletions

View File

@ -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
View 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
View 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();
}

View File

@ -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
View 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
View 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");
}
}
}