diff --git a/Makefile b/Makefile index 63080f5..e774089 100644 --- a/Makefile +++ b/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 diff --git a/broken_transistors.c b/broken_transistors.c new file mode 100644 index 0000000..772b908 --- /dev/null +++ b/broken_transistors.c @@ -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"); + } +} diff --git a/compare.c b/compare.c new file mode 100644 index 0000000..1009229 --- /dev/null +++ b/compare.c @@ -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(); + +} diff --git a/perfect6502.c b/perfect6502.c index dbb3b86..a903f98 100644 --- a/perfect6502.c +++ b/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 diff --git a/runtime_init.c b/runtime_init.c new file mode 100644 index 0000000..c071d1d --- /dev/null +++ b/runtime_init.c @@ -0,0 +1,104 @@ +#include + +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 + */ + } +} + diff --git a/test.c b/test.c new file mode 100644 index 0000000..eeb48a5 --- /dev/null +++ b/test.c @@ -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"); + } + } +}