#include #include #include "perfect6502.h" typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int BOOL; extern uint8_t memory[65536]; #define YES 1 #define NO 0 #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 ((cycle & 1) && readRW(state)) #define IS_WRITE_CYCLE ((cycle & 1) && !readRW(state)) #define IS_READING(a) (IS_READ_CYCLE && readAddressBus(state) == (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 *state; void resetChip_test() { state = initAndResetChip(); for (int i = 0; i < 62; i++) step(state); cycle = -1; } int main() { state = initAndResetChip(); 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(state); 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(state)+2] | memory[0x0100+readSP(state)+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(state); // chipStatus(); //printf("cycle = %d %x\n", cycle, readIR()); if (readIR(state) == 0x00) break; }; if (cycle) data[opcode].cycles = cycle / 2; else data[opcode].cycles = 0; /************************************************** * 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(state); if (IS_READ_CYCLE || IS_WRITE_CYCLE) { //printf("RW@ %X\n", readAddressBus(state)); BOOL is_data_access = YES; if (readAddressBus(state) == MAGIC_8) data[opcode].zp = YES; else if (readAddressBus(state) == MAGIC_16) data[opcode].abs = YES; else if (readAddressBus(state) == MAGIC_8 + X_OFFSET) data[opcode].zpx = YES; else if (readAddressBus(state) == MAGIC_16 + X_OFFSET) data[opcode].absx = YES; else if (readAddressBus(state) == MAGIC_8 + Y_OFFSET) data[opcode].zpy = YES; else if (readAddressBus(state) == MAGIC_16 + Y_OFFSET) data[opcode].absy = YES; else if (readAddressBus(state) == MAGIC_IZX) data[opcode].izx = YES; else if (readAddressBus(state) == 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(state); if (IS_READ_CYCLE) { if (!j) read[reads++] = readAddressBus(state); else if (read[reads++] != readAddressBus(state)) { different = YES; //printf("[[[%d]]]", __LINE__); break; } } if (IS_WRITE_CYCLE) { if (!j) { write[writes] = readAddressBus(state); write_data[writes++] = readDataBus(state); } else { if (write[writes] != readAddressBus(state)) { different = YES; //printf("[[[%d]]]", __LINE__); break; } if (write_data[writes++] != readDataBus(state)) { //printf("[[[%d:k=%d;%x@%x/%x]]]", __LINE__, k, write[writes-1], write_data[writes-1], readDataBus(state)); different = YES; break; } } } }; if (different) /* bus cycles were different */ break; /* changes A */ if (!(k == 0)) { if (!j) { end_a = readA(state); } else { if (end_a != readA(state)) { different = YES; break; } } } /* changes X */ if (!(k == 1)) { if (!j) { end_x = readX(state); } else { if (end_x != readX(state)) { different = YES; break; } } } /* changes Y */ if (!(k == 2)) { if (!j) { end_y = readY(state); } else { if (end_y != readY(state)) { different = YES; break; } } } /* changes S */ if (!(k == 3)) { if (!j) { end_s = readSP(state); } else { if (end_s != readSP(state)) { different = YES; //printf("[%x/%x]", end_s, readSP(state)); break; } } } /* changes P */ if (!(k == 4)) { if (!j) { end_p = readP(state); } else { if (end_p != readP(state)) { 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(state); }; if (readA(state) != magics[j + 0]) data[opcode].outputa = YES; if (readX(state) != magics[j + 1]) data[opcode].outputx = YES; if (readY(state) != magics[j + 2]) data[opcode].outputy = YES; if (readSP(state) != magics[j + 3]) data[opcode].outputs = YES; if ((readP(state) & 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"); } } }