#include "opcode.h" #include #include #define debug 1 #define SETOP(num, _mne, _IMM, _ZM, _ZMX, _ZMY, _IND, _INX, _INY, _ABS, _IMPL) \ {opcodes[num].mnemonic[3] = '\0'; strncpy(opcodes[num].mnemonic, _mne, 3); \ opcodes[num].imm = _IMM; \ opcodes[num].zm = _ZM; opcodes[num].zmx = _ZMX; opcodes[num].zmy = _ZMY; \ opcodes[num].ind = _IND; opcodes[num].inx = _INX; opcodes[num].iny = _INY; \ opcodes[num].abs = _ABS; opcodes[num].impl = _IMPL;} struct fixup { struct fixup *nxt; struct label *l; uint64_t adr; }; struct label { struct label* nxt; uint64_t adr; uint8_t def; char name[1]; }; static char tstr[2048]; struct label *labels = 0; struct fixup *fixups = 0; uint8_t defined = 0; struct label *mklabel(const char *name, uint64_t adr, uint8_t def) { struct label *l; for (l = labels; l; l = l->nxt) { if (!strcasecmp(name, l->name)) { if (def) { if (l->def) { printf("oof, you cannot redefine the label: %s\n", name); defined = 1; } else { defined = 0; } l->def = def; l->adr = adr; } return l; } } l = malloc(sizeof(*l) + strlen(name)); l->def = def; l->adr = adr; strcpy(l->name, name); l->nxt = labels; labels = l; defined = 0; return l; } uint64_t use_label(const char *name, uint64_t adr) { struct label *l = mklabel(name, 0, 0); adr++; if (l->def) { return l->adr; } else { printf("oof, label %s, does not exist, yet.\n", name); struct fixup *f = malloc(sizeof(*f)); f->nxt = fixups; f->adr = adr; f->l = l; fixups = f; return adr-1; } } void reslv_fixups(void) { struct fixup *f; for (f = fixups; f; f = f->nxt) { if (f->l->def) { addr[f->adr] = f->l->adr & 0xFF; if (f->l->adr & 0xFF00) addr[f->adr+1] = f->l->adr >> 8; if (f->l->adr & 0xFF000000) { addr[f->adr+2] = f->l->adr >> 16; addr[f->adr+3] = f->l->adr >> 24; } if (f->l->adr & 0xFF00000000000000) { addr[f->adr+4] = f->l->adr >> 32; addr[f->adr+5] = f->l->adr >> 40; addr[f->adr+6] = f->l->adr >> 48; addr[f->adr+7] = f->l->adr >> 56; } } else { printf("oof, undefined reference to '%s', at $%016llX.\n", f->l->name, f->adr); } } } void viewmem(uint64_t address) { printf("\t\t\t"); for (int ind = 0; ind < 0x10; ind++) { printf("%02X", ind); if (ind < 0x0F) printf(" "); } printf("\n\n"); for (int hi = 0; hi < 0x10; hi++) { printf("%016llX:\t", (address & ~0xF)+(hi*0x10)); for (int lo = 0; lo < 0x10; lo++) { printf("%02X", addr[(address & ~0xF)+lo+(hi*0x10)]); if (lo < 0x0F) printf(" "); } printf("\n"); } } void usage() { puts("SuBAsm for CISC-0.2"); puts("Commands:"); puts("\tviewmem, vm, v\t\tGet the contents of memory\n" "\t\t\t\t(Displays 256 bytes of memory\n" "\t\t\t\t starting from where the program counter\n" "\t\t\t\t currently is)."); puts("\trelsv, rf, r\t\tResolve any currently unknown labels."); puts("\tdisasm, dis,\n" "\td [start-][end]\t\tDisassemble from starting address, to\n" "\t\t\t\tending address."); puts("\tinst, i [inst]\t\tGet a descriptions of that instruction.\n" "\t\t\t\tIf no argument is specified, or the\n" "\t\t\t\targument specified is \"all\", list all\n" "\t\t\t\tinstructions, along with a description\n" "\t\t\t\tfor each of them."); puts("\tquit, q\t\t\tQuit the emulator."); puts("\thelp, h\t\t\tDisplays this mesage."); } void instinfo(const char *inst) { for(int i = 0; i < OPNUM; i++) { if (!strcasecmp(inst, mne[i])) { printf("%s\t%s\n", mne[i], instdesc[i]); break; } else if (!strcasecmp(inst, "all")) { printf("%s\t%s\n", mne[i], instdesc[i]); } } } void disasm(uint8_t prefix, uint8_t opcode, uint64_t value) { char postfix[3]; char op[4]; uint8_t addrsize = (prefix & 8) >> 3; uint8_t rs = (prefix & 0x30) >> 4; uint8_t regsize = (1 << rs); op[0] = opname[opcode][0]; op[1] = opname[opcode][1]; op[2] = opname[opcode][2]; op[3] = '\0'; if (regsize == 1) { postfix[0] = '\0'; postfix[1] = '\0'; postfix[2] = '\0'; } else { postfix[0] = '.'; if (regsize == 2) postfix[1] = 'W'; else if (regsize == 4) postfix[1] = 'D'; else if (regsize == 8) postfix[1] = 'Q'; else { postfix[0] = '\0'; postfix[1] = '\0'; } postfix[2] = '\0'; } switch (optype[opcode]) { case IMPL: printf("%s\n" , opname[opcode]); break; case IMM: if (regsize == 1) printf("%s #$%02x\n" , op, value); if (regsize == 2) printf("%s%s #$%04x\n" , op, postfix, value); if (regsize == 4) printf("%s%s #$%08x\n" , op, postfix, value); if (regsize == 8) printf("%s%s #$%016llx\n" , op, postfix, value); break; case ZM: case ZMX: case ZMY: if (addrsize) printf("%s%s $%08x%s\n" , op, postfix, value, (optype[opcode] == ZM) ? "" : ((optype[opcode] == ZMX) ? ", x" : ", y")); else printf("%s%s $%02x%s\n" , op, postfix, value, (optype[opcode] == ZM) ? "" : ((optype[opcode] == ZMX) ? ", x" : ", y")); break; case IND: case INDX: case INDY: if (addrsize) printf("%s%s ($%08x%s\n" , op, postfix, value, (optype[opcode] == IND) ? ")" : ((optype[opcode] == INDX) ? ", x)" : "), y")); else printf("%s%s ($%02x%s\n" , op, postfix, value, (optype[opcode] == IND) ? ")" : ((optype[opcode] == INDX) ? ", x)" : "), y")); break; case ABS: if (addrsize) printf("%s%s $%016llx\n" , op, postfix, value); else printf("%s%s $%04x\n" , op, postfix, value); break; } } int asmmon(const char *fn) { /* mne IMM ZM ZMX ZMY IND INX INY ABS IMPL*/ SETOP( 0, "CPS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); SETOP( 1, "ADC", 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00); SETOP( 2, "AAB", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02); SETOP( 3, "PHP", 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); SETOP( 4, "CPB", 0x09, 0x2D, 0x00, 0x00, 0x55, 0xAD, 0xAC, 0x2C, 0x00); SETOP( 5, "PHB", 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); SETOP( 6, "DEC", 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xE5); SETOP( 7, "JMP", 0x00, 0x0E, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x10, 0x00); SETOP( 8, "SBC", 0x11, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00); SETOP( 9, "SAB", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12); SETOP(10, "ENT", 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); SETOP(11, "CPY", 0x19, 0x3D, 0x00, 0x00, 0x85, 0x00, 0x00, 0x4C, 0x00); SETOP(12, "PLB", 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); SETOP(13, "INC", 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xF5); SETOP(14, "JSR", 0x00, 0x1E, 0x00, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x00); SETOP(15, "JSL", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00); SETOP(16, "AND", 0x21, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00); SETOP(17, "ABA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22); SETOP(18, "PLP", 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); SETOP(19, "CPX", 0x29, 0x4D, 0x00, 0x00, 0xB5, 0x00, 0x00, 0x3C, 0x00); SETOP(20, "PHY", 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); SETOP(21, "BPO", 0x00, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00); SETOP(22, "ORA", 0x31, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00); SETOP(23, "OAB", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32); SETOP(24, "STT", 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); SETOP(25, "PLY", 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); SETOP(26, "BNG", 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00); SETOP(27, "XOR", 0x41, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00); SETOP(28, "XAB", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42); SETOP(29, "PHA", 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); SETOP(30, "PHX", 0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); SETOP(31, "BCS", 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00); SETOP(32, "LSL", 0x51, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00); SETOP(33, "LLB", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52); SETOP(34, "CLC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58); SETOP(35, "PLX", 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); SETOP(36, "BCC", 0x00, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00); SETOP(37, "LSR", 0x61, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00); SETOP(38, "LRB", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62); SETOP(39, "PLA", 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); SETOP(40, "TAB", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6A); SETOP(41, "BEQ", 0x00, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00); SETOP(42, "ROL", 0x71, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00); SETOP(43, "RLB", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72); SETOP(44, "SEC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78); SETOP(45, "TBA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7A); SETOP(46, "BNE", 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00); SETOP(47, "ROR", 0x81, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00); SETOP(48, "RRB", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82); SETOP(49, "DEY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88); SETOP(50, "TAY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A); SETOP(51, "BVS", 0x00, 0x8E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00); SETOP(52, "MUL", 0x91, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x00); SETOP(53, "MAB", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92); SETOP(54, "CLI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98); SETOP(55, "TYA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A); SETOP(56, "BVC", 0x00, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x00); SETOP(57, "DIV", 0xA1, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x00); SETOP(58, "DAB", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2); SETOP(59, "INY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8); SETOP(60, "TAX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA); SETOP(61, "RTS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAE); SETOP(62, "RTL", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0); SETOP(63, "CMP", 0xB1, 0xB6, 0x00, 0x00, 0x25, 0x7D, 0x7C, 0xB4, 0x00); SETOP(64, "CAB", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB2); SETOP(65, "SEI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB8); SETOP(66, "LDX", 0xB9, 0xBD, 0x00, 0xC9, 0x95, 0x00, 0x00, 0xBC, 0x00); SETOP(67, "TXA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBA); SETOP(68, "RTI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0); SETOP(69, "LDA", 0xC1, 0xC6, 0x79, 0x39, 0x05, 0x5D, 0x5C, 0xC4, 0x00); SETOP(70, "DEX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC5); SETOP(71, "CLV", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8); SETOP(72, "TYX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA); SETOP(73, "STA", 0x00, 0xCD, 0x89, 0x49, 0x15, 0x6D, 0x6C, 0xCC, 0x00); SETOP(74, "TSX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0); SETOP(75, "LDB", 0xD1, 0xD6, 0x99, 0x59, 0x35, 0x8D, 0x8C, 0xD4, 0x00); SETOP(76, "INX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5); SETOP(77, "WAI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8); SETOP(78, "TXY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDA); SETOP(79, "STB", 0x00, 0xDD, 0xA9, 0x69, 0x45, 0x9D, 0x9C, 0xDC, 0x00); SETOP(80, "TXS", 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); SETOP(81, "LDY", 0xE1, 0xE6, 0xE9, 0x00, 0x65, 0x00, 0x00, 0xE4, 0x00); SETOP(82, "BRK", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8); SETOP(83, "NOP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA); SETOP(84, "STY", 0x00, 0xED, 0xF9, 0x00, 0x75, 0x00, 0x00, 0xEC, 0x00); SETOP(85, "DEB", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE); SETOP(86, "ASR", 0xF1, 0xF6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x00); SETOP(87, "ARB", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2); SETOP(88, "STX", 0x00, 0xFD, 0x00, 0xD9, 0xA5, 0x00, 0x00, 0xFC, 0x00); SETOP(89, "INB", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE); FILE *fp; if (strcasecmp(fn, "stdin") != 0) { fp = fopen(fn, "r"); if (fp == NULL) return 2; } uint8_t done = 0; uint64_t address = 0x0000; uint64_t bytecount = 0; uint64_t start, end; uint8_t prefix, opcode; while (!(done & 1)) { char *buf = NULL; char *ins; char *postfix; char mode[3]; opent op; uint8_t addrmode = IMPL; uint8_t addrtok = 0; uint64_t value = 0; uint64_t val2 = 0; char *oprand; char *oprand2; char *cmd; char ir[2] = ""; /* Index register. */ int a = 0; int b = 0; char *tmp = malloc(sizeof(char *)*128); char *tmp2; size_t size; prefix = 0; done = 0; if (!strcasecmp(fn, "stdin")) { getline(&buf, &size, stdin); } else { getline(&buf, &size, fp); } cmd = strtok_r(buf, "\n", &tmp); if (cmd != NULL) { if (strcasecmp(cmd, "done") == 0) { done |= 1; } else { ins = strtok(buf, "\t\n "); if (ins != NULL) { oprand = strtok(NULL, "\t\n"); strtok_r(ins, ".", &postfix); if (oprand != NULL) { for (int i = 0; i < strlen(oprand); i++) { switch (oprand[i]) { case '(': addrmode = IND; break; case '+': addrtok = 1; break; case '-': addrtok = 2; } if (oprand[i] == '"') break; if (a && oprand[a] == ',') { if (oprand[i] == 'x' || oprand[i] == 'X') { ir[0] = 'x'; ir[1] = '\0'; } if (oprand[i] == 'y' || oprand[i+1] == 'Y') { ir[0] = 'y'; ir[1] = '\0'; } if (b && ir[0] == 'y') oprand[b] = '\0'; } if (oprand[i] == ')' && oprand[i+1] == ',') b = i; else if (oprand[i] == ')') oprand[i] = '\0'; if (oprand[i] == ',' || oprand[i] == ';') a = i; } if (a) oprand[a] = '\0'; } } if (!strcasecmp(cmd, "quit") || !strcasecmp(cmd, "q")) { printf("The total size of the program code is, %llu bytes in decimal, and $%llX bytes in hex.\n", bytecount, bytecount); return 2; } if (!strcasecmp(cmd, "viewmem") || !strcasecmp(cmd, "vm") || !strcasecmp(cmd, "v")) { done |= 4; viewmem(address); } if (!strcasecmp(cmd, "reslv") || !strcasecmp(cmd, "rf") || !strcasecmp(cmd, "r")) { done |= 4; puts("Resolving unknown labels."); reslv_fixups(); puts("Finished resolving unknown labels."); } if (!strcasecmp(cmd, "help") || !strcasecmp(cmd, "h")) { done |= 4; usage(); } if (oprand == NULL && ins == NULL && postfix == NULL) { done |= 2; } cmd = strtok(cmd, " \n"); if (!strcasecmp(cmd, "inst") || !strcasecmp(cmd, "i")) { done |= 64; done |= 6; if (oprand != NULL) { instinfo(oprand); } else { instinfo("all"); } } if (!strcasecmp(cmd, "disasm") || !strcasecmp(cmd, "dis") || !strcasecmp(cmd, "d")) { done |= 64; done |= 6; if (oprand != NULL) { cmd = strtok_r(oprand, " -", &tmp); if (cmd != NULL) { for (int i = 0; i < strlen(cmd); i++) { if ((isalnum(cmd[i]) || cmd[i] == '_') && cmd[i] != '"') { value = use_label(tmp, address); sprintf(tmp, "%llx", value); break; } if (cmd[i] == '$') { cmd = strtok(cmd, "$"); value = strtoull(cmd, NULL, 16); break; } if (cmd[i] == ';') { done |= 16; break; } } start = value; for (int i = 0; i < strlen(tmp); i++) { if ((isalnum(tmp[i]) || tmp[i] == '_') && tmp[i] != '"') { value = use_label(tmp, address); sprintf(tmp, "%llx", value); break; } if (tmp[i] == '$') { tmp = strtok(tmp, "$"); value = strtoull(tmp, NULL, 16); break; } if (tmp[i] == ';') { done |= 16; break; } } (!strlen(tmp)) ? (end = address) : (end = value); } else { start = value; end = address; } } else { start = 0; end = address; } while (start < end) { uint8_t rs; uint8_t regsize; uint8_t addrsize; if (start < 0xFF) printf("$%02llx: ", start); else if (start < 0xFFFF) printf("$%04llx: ", start); else if (start < 0xFFFFFFFF) printf("$%08llx: ", start); else if (start < 0xFFFFFFFFFFFFFFFF) printf("$%016llx: ", start); prefix = addr[start]; if ((prefix & 0x03) == 0x03) { start+=1; addrsize = (prefix & 0x0C) >> 2; rs = (prefix & 0x30) >> 4; regsize = (1 << rs); } else { prefix = 0; regsize = 1; addrsize = 0; } opcode = addr[start]; start+=1; switch (optype[opcode]) { case IMPL: break; case IMM: value = addr[start]; switch (regsize) { case 8: value |= (uint64_t)addr[start+7] << 56; value |= (uint64_t)addr[start+6] << 48; value |= (uint64_t)addr[start+5] << 40; value |= (uint64_t)addr[start+4] << 32; case 4: value |= addr[start+3] << 24; value |= addr[start+2] << 16; case 2: value |= addr[start+1] << 8; } start += regsize; break; case ZM: case ZMX: case ZMY: case IND: case INDX: case INDY: value = addr[start]; switch (addrsize) { case 0: start+=1; break; case 1: value |= addr[start+1] << 8; value |= addr[start+2] << 16; start+=3; break; case 2: value |= addr[start+1] << 8; value |= addr[start+2] << 16; value |= addr[start+3] << 24; value |= (uint64_t)addr[start+4] << 32; value |= (uint64_t)addr[start+5] << 40; start+=6; break; case 3: value |= addr[start+1] << 8; value |= addr[start+2] << 16; value |= addr[start+3] << 24; start+=4; break; } break; case ABS: value = addr[start]; value |= addr[start+1] << 8; switch (addrsize) { case 0: start+=2; break; case 1: value |= addr[start+2] << 16; value |= addr[start+3] << 24; value |= (uint64_t)addr[start+4] << 32; start+=5; break; case 2: value |= addr[start+2] << 16; value |= addr[start+3] << 24; value |= (uint64_t)addr[start+4] << 32; value |= (uint64_t)addr[start+5] << 40; value |= (uint64_t)addr[start+6] << 48; start+=7; break; case 3: value |= addr[start+2] << 16; value |= addr[start+3] << 24; value |= (uint64_t)addr[start+4] << 32; value |= (uint64_t)addr[start+5] << 40; value |= (uint64_t)addr[start+6] << 48; value |= (uint64_t)addr[start+7] << 56; start+=8; break; } break; } disasm(prefix, opcode, value); } } if (!(done & 64)) { if (ins != NULL) { for (int i = 0; i < strlen(ins); i++) { if (i && ins[i] == ':') { ins[i] = '\0'; mklabel(ins, address, 1); #if debug printf("Created label with the name %s, at address: $%llx\n", ins, address); #endif done |= 6; break; } if (i && ins[i] == '=') { /*ins = strtok_r(oprand2)*/ } if (ins[i] == ';') { if (i && (ins[i-1] == ' ' || ins[i-1] == '\t')) ins[i] = '\0'; else done |=6; break; } } if (!(done & 6)) { if (oprand != NULL) { if (!strcasecmp(ins, ".org")) { done |= 6; oprand = strtok(oprand, "$"); address = strtoull(oprand, NULL, 16); #if debug printf("Origin for program code is now at address $%llx.\n", address); #endif } if (!strcasecmp(ins, ".byte") || !strcasecmp(ins, ".word") || !strcasecmp(ins, ".dword") || !strcasecmp(ins, ".qword")) { done |= 6; uint8_t qstr = 0; uint64_t staddr = address; uint16_t slen = 0; char *tmpstr = tstr; char c; for (int i = 0; i < strlen(oprand); i++) { if (!qstr) { if ((isalnum(oprand[i]) || oprand[i] == '_') && oprand[i] != '"') { qstr = 0; value = use_label(oprand, address); sprintf(oprand, "%llx", value); break; } if (!strcasecmp(ins, ".byte")) { if (oprand[i] == '"') { qstr = 1; continue; } else if (oprand[i] == '\'') { qstr = 2; continue; } } if (oprand[i] == '$') { qstr = 0; oprand = strtok(oprand, "$"); value = strtoull(oprand, NULL, 16); break; } if (oprand[i] == ';') { qstr = 0; done |= 16; break; } } else if (qstr == 1) { switch (oprand[i]) { case 0: puts("oof, unterminated string."); qstr = 4; break; case '"': value = '\0'; c = '\0'; tmpstr[slen++] = '\0'; qstr = 3; break; case '\\': switch (oprand[i+1]) { case 'n': value = '\n'; c = '\n'; tmpstr[slen++] = '\\'; tmpstr[slen++] = 'n'; break; case 't': value = '\t'; c = '\t'; tmpstr[slen++] = '\\'; tmpstr[slen++] = 't'; break; case 'r': value = '\r'; c = '\r'; tmpstr[slen++] = '\\'; tmpstr[slen++] = 'r'; break; case '0': break; default: value = oprand[i]; tmpstr[slen++] = '\\'; tmpstr[slen++] = oprand[i]; break; } i++; break; default: value = oprand[i]; c = oprand[i]; tmpstr[slen++] = c; break; } addr[address++] = (uint8_t)value & 0xFF; } else if (qstr == 2) { switch (oprand[i]) { case 0: puts("oof, unterminated string."); qstr = 4; break; case '\'': c = '\0'; tmpstr[slen++] = '\0'; qstr = 3; break; case '\\': switch (oprand[i+1]) { case 'n': value = '\n'; c = '\n'; tmpstr[slen++] = '\\'; tmpstr[slen++] = 'n'; break; case 't': value = '\t'; c = '\t'; tmpstr[slen++] = '\\'; tmpstr[slen++] = 't'; break; case 'r': value = '\r'; c = '\r'; tmpstr[slen++] = '\\'; tmpstr[slen++] = 'r'; break; case '0': break; default: value = oprand[i]; tmpstr[slen++] = '\\'; tmpstr[slen++] = oprand[i]; break; } i++; break; default: value = oprand[i]; c = oprand[i]; tmpstr[slen++] = c; break; } if (qstr != 3) addr[address++] = (uint8_t)value & 0xFF; } } if (!strcasecmp(ins, ".byte") && !qstr) addr[address++] = value & 0xFF; if (!strcasecmp(ins, ".word")) { addr[address] = (uint8_t)value & 0xFF; addr[address+1] = value >> 8; address+=2; } if (!strcasecmp(ins, ".dword")) { addr[address] = (uint8_t)value & 0xFF; addr[address+1] = value >> 8; addr[address+2] = value >> 16; addr[address+3] = value >> 24; address+=4; } if (!strcasecmp(ins, ".qword")) { addr[address] = (uint8_t)value & 0xFF; addr[address+1] = value >> 8; addr[address+2] = value >> 16; addr[address+3] = value >> 24; addr[address+4] = value >> 32; addr[address+5] = value >> 40; addr[address+6] = value >> 48; addr[address+7] = value >> 56; address+=8; } #if debug if (!qstr) { printf("The value $%llx was placed at address%s ", value, (staddr != address-1) ? "es" : ""); if (staddr == address-1) printf("$%llx.\n", staddr); else printf("$%llx-$%llx.\n", staddr, address-1); } else { printf("The string \"%s\", was placed at address%s ", tmpstr, (staddr != address-1) ? "es" : ""); if (staddr == address-1) printf("$%llx.\n", staddr); else printf("$%llx-$%llx.\n", staddr, address-1); } #endif } } } } } if (oprand == NULL && !strcasecmp(ins, "TXS")) { addrmode = IMM; done |= 32; } else if (oprand != NULL && !strcasecmp(ins, "TXS")) prefix = 0x13; if (!(done & 2) && oprand != NULL) { mode[0] = oprand[0]; mode[1] = oprand[1]; strtok_r(oprand, "+-", &oprand2); if (ir[0] == 'x' || ir[0] == 'y') { oprand2 = strtok_r(oprand2, ",)", &tmp2); } if (oprand2 != NULL) { int i = 0; for (; (oprand2[i] == '$' || oprand2[i] == '%') || isxdigit(oprand2[i]); i++); if (i) { oprand2[i] = '\0'; } } uint8_t isimm = oprand[0] == '#'; /* This flag is used for checking if there is a secondary token. */ uint8_t issectok = (oprand[1] == '$' || oprand[1] == '%' || isdigit(oprand[1])); if (oprand[0] == '$' || (isimm && issectok) || (oprand[0] == '(' && issectok)) { oprand = strtok(oprand, "#($%"); if (isimm) { addrmode = IMM; done |= 32; if (mode[1] == '$') value = strtoull(oprand, NULL, 16); else if (mode[1] == '%') value = strtoull(oprand, NULL, 2); else value = strtoull(oprand, NULL, 10); } else { if (mode[0] == '$' || mode[1] == '$') value = strtoull(oprand, NULL, 16); else if (mode[0] == '%' || mode[1] == '%') value = strtoull(oprand, NULL, 2); else value = strtoull(oprand, NULL, 10); if (mode[0] != '(') { if ((value & 0xFF0000 || value & 0xFFFF00000000 || value & 0xFFFF0000 || !(value & 0xFF00))) { addrmode = ZM; } else if (value & 0xFF00000000 || value & 0xFF000000000000 || value & 0xFF00000000000000 || (value & 0xFF00)) { if (ir[0] == 'x' || ir[0] == 'y') { addrmode = ZM; } else { addrmode = ABS; } } } if (addrmode == ZM || addrmode == IND) { if (value & 0xFFFF00) prefix |= 0x7; else if (value & 0xFFFF00000000) prefix |= 0xB; else if (value & 0xFFFF000000) prefix |= 0xF; } if (addrmode == ABS) { if (value & 0xFF00000000) prefix |= 0x7; else if (value & 0xFF000000000000) prefix |= 0xB; else if (value & 0xFF00000000000000) prefix |= 0xF; } if ((addrmode == 2 || addrmode == 6) && ir != NULL) { switch (ir[0]) { case 'x': if (addrmode == ZM) addrmode = ZMX; else if (addrmode == IND) addrmode = INDX; break; case 'y': if (addrmode == ZM) addrmode = ZMY; else if (addrmode == IND) addrmode = INDY; break; default: done |= 32; break; } } } } else { if (mode[0] == '(') { oprand = strtok(oprand, "#($%"); } else if (isimm) { oprand = strtok(oprand, "#"); addrmode = IMM; done |= 32; } for (int i = 0; i < strlen(oprand); i++) { if (oprand[i] == ';') { done |= 16; break; } if ((isalnum(oprand[i]) || oprand[i] == '_') && oprand[i] != '"') { value = use_label(oprand, address); if (!isimm) { if (mode[0] != '(') { if ((value & 0xFF0000 || value & 0xFFFF00000000 || value & 0xFFFF0000 || !(value & 0xFF00))) { addrmode = ZM; } else if (value & 0xFF00000000 || value & 0xFF000000000000 || value & 0xFF00000000000000 || (value & 0xFF00)) { if (ir[0] == 'x' || ir[0] == 'y') { addrmode = ZM; } else { addrmode = ABS; } } } if (addrmode == ZM || addrmode == IND) { if (value & 0xFFFF00) prefix |= 0x7; else if (value & 0xFFFF00000000) prefix |= 0xB; else if (value & 0xFFFF000000) prefix |= 0xF; } if (addrmode == ABS) { if (value & 0xFF00000000) prefix |= 0x7; else if (value & 0xFF000000000000) prefix |= 0xB; else if (value & 0xFF00000000000000) prefix |= 0xF; } if ((addrmode == ZM || addrmode == IND) && ir != NULL && a) { switch (ir[0]) { case 'x': if (addrmode == ZM) addrmode = ZMX; else if (addrmode == IND) addrmode = INDX; break; case 'y': if (addrmode == ZM) addrmode = ZMY; else if (addrmode == IND) addrmode = INDY; break; default: done |= 32; break; } } } sprintf(oprand, "%llx", value); break; } } } if (oprand2 != NULL && (addrtok == 1 || addrtok == 2)) { mode[0] = oprand2[0]; if (mode[0] == '$' || mode[0] == '%') { oprand2++; printf("mode[0]: %i, oprand2: %s\n", mode[0], oprand2); switch (mode[0]) { case '$': val2 = strtoull(oprand2, NULL, 16); break; case '%': val2 = strtoull(oprand2, NULL, 2); break; } } else { val2 = strtoull(oprand2, NULL, 10); } switch (addrtok) { case 1: value += val2; break; case 2: value -= val2; break; } } } if (ins != NULL && !(done & 6)) { uint8_t i; for (i = 0; i < OPNUM; i++) { if (strcasecmp(opcodes[i].mnemonic, ins) == 0) { if (addrmode == IMPL && (opcodes[i].impl || opcodes[i].impl == CPS)) { done |= 8; } else if (addrmode == IMM) { switch (opcodes[i].imm) { case PHB: case PHP: case PHA: case PHY: case PHX: case PLB: case PLP: case PLA: case PLY: case PLX: case STT: case TXS: case LSL: case LSR: case ROL: case ROR: case ASR: case ENT: done |= 8; break; } } else { if (strcasecmp(ins, "JMP") == 0) done |=8; if (strcasecmp(ins, "JSR") == 0) done |=8; if (strcasecmp(ins, "JSL") == 0) done |=8; if (strcasecmp(ins, "INC") == 0) done |=8; if (strcasecmp(ins, "BPO") == 0) done |=8; if (strcasecmp(ins, "BNG") == 0) done |=8; if (strcasecmp(ins, "BCS") == 0) done |=8; if (strcasecmp(ins, "BCC") == 0) done |=8; if (strcasecmp(ins, "BEQ") == 0) done |=8; if (strcasecmp(ins, "BNE") == 0) done |=8; if (strcasecmp(ins, "BVS") == 0) done |=8; if (strcasecmp(ins, "BVC") == 0) done |=8; } op = opcodes[i]; break; } } if (postfix != NULL && !(done & 8)) { if (!strcasecmp(postfix, "w") || !strcasecmp(postfix, "2")) { prefix |= 0x13; } else if (!strcasecmp(postfix, "d") || !strcasecmp(postfix, "4")) { prefix |= 0x23; } else if (!strcasecmp(postfix, "q") || !strcasecmp(postfix, "8")) { prefix |= 0x33; } else if (!prefix) { done |=8; } } else if (postfix == NULL && (!(done & 8) && !prefix)) { done |=8; } uint8_t r; uint8_t r2; if (!(done & 8)) { r = prefix; addr[address] = prefix; address += 1; bytecount+=1; } else { r = 0; } r2 = 1 << ((prefix & 0x30) >> 4); switch (addrmode) { case IMPL: if (op.impl || op.impl == CPS) { addr[address++] = op.impl; bytecount+=1; break; } else { fprintf(stderr, "oof, %s requires an operand.\n", op.mnemonic); } break; case IMM: if (op.imm) { if ((prefix & 0x30) == 0x10 && op.imm == TXS) r = prefix; addr[address++] = op.imm; bytecount+=1; switch (op.imm) { case PHP: case PHA: case PHY: case PHX: case PLP: case PLA: case PLY: case PLX: case STT: case LSL: case LSR: case ROL: case ROR: case ASR: case ENT: addr[address++] = value & 0xFF; bytecount+=1; break; case TXS: if ((r & 0x30) == 0x10) { addr[address] = value & 0xFF; addr[address+2] = value >> 8; address+=2; bytecount+=2; } break; default: addr[address] = value & 0xFF; if (r & 0x10) { addr[address+1] = value >> 8; } if (r & 0x20) { addr[address+2] = value >> 16; addr[address+3] = value >> 24; } if (r & 0x30) { addr[address+4] = value >> 32; addr[address+5] = value >> 40; addr[address+6] = value >> 48; addr[address+7] = value >> 56; } address+=r2; bytecount+=r2; break; } break; } else { fprintf(stderr, "oof, %s does not use Immediate data.\n", op.mnemonic); } break; case ZM: if (op.zm) { addr[address++] = op.zm; bytecount+=1; addr[address] = value & 0xFF; switch ((r & 0x0C) >> 2) { case 2: addr[address+5] = (uint64_t)value >> 40; addr[address+4] = (uint64_t)value >> 32; address += 2; bytecount+=2; case 3: addr[address+3] = value >> 24; address += 1; bytecount+=1; case 1: addr[address+2] = value >> 16; addr[address+1] = value >> 8; address += 2; bytecount+=2; } address += 1; bytecount+=1; break; } else { fprintf(stderr, "oof, %s does not use Zero Matrix.\n", op.mnemonic); } break; case ZMX: if (op.zmx) { addr[address++] = op.zmx; bytecount+=1; addr[address] = value & 0xFF; switch ((r & 0x0C) >> 2) { case 2: addr[address+5] = (uint64_t)value >> 40; addr[address+4] = (uint64_t)value >> 32; address += 2; bytecount+=2; case 3: addr[address+3] = value >> 24; address += 1; bytecount+=1; case 1: addr[address+2] = value >> 16; addr[address+1] = value >> 8; address += 2; bytecount+=2; } address += 1; bytecount+=1; break; } else { fprintf(stderr, "oof, %s does not use Zero Matrix, indexed with x.\n", op.mnemonic); } break; case ZMY: if (op.zmy) { addr[address++] = op.zmy; bytecount+=1; addr[address] = value & 0xFF; switch ((r & 0x0C) >> 2) { case 2: addr[address+5] = (uint64_t)value >> 40; addr[address+4] = (uint64_t)value >> 32; address += 2; bytecount+=2; case 3: addr[address+3] = value >> 24; address += 1; bytecount+=1; case 1: addr[address+2] = value >> 16; addr[address+1] = value >> 8; address += 2; bytecount+=2; } address += 1; bytecount+=1; break; } else { fprintf(stderr, "oof, %s does not use Zero Matrix, indexed with y.\n", op.mnemonic); } break; case ABS: if (op.abs) { addr[address++] = op.abs; bytecount+=1; addr[address] = value & 0xFF; addr[address+1] = value >> 8; switch ((r & 0x0C) >> 2) { case 3: addr[address+7] = value >> 56; address += 1; bytecount+=1; case 2: addr[address+6] = (uint64_t)value >> 48; addr[address+5] = (uint64_t)value >> 40; address += 2; bytecount+=2; case 1: addr[address+4] = (uint64_t)value >> 32; addr[address+3] = value >> 24; addr[address+2] = value >> 16; address += 3; bytecount+=3; } address += 2; bytecount+=2; break; } else { fprintf(stderr, "oof, %s cannot be an absolute dictator.\n", op.mnemonic); } break; case IND: if (op.ind) { addr[address++] = op.ind; bytecount+=1; addr[address] = value & 0xFF; switch ((r & 0x0C) >> 2) { case 2: addr[address+5] = (uint64_t)value >> 40; addr[address+4] = (uint64_t)value >> 32; address += 2; bytecount+=2; case 3: addr[address+3] = value >> 24; address += 1; bytecount+=1; case 1: addr[address+2] = value >> 16; addr[address+1] = value >> 8; address += 2; bytecount+=2; } address += 1; bytecount+=1; break; } else { fprintf(stderr, "oof, %s cannot use pointers.\n", op.mnemonic); } break; case INDX: if (op.inx) { addr[address++] = op.inx; bytecount+=1; addr[address] = value & 0xFF; switch ((r & 0x0C) >> 2) { case 2: addr[address+5] = (uint64_t)value >> 40; addr[address+4] = (uint64_t)value >> 32; address += 2; bytecount+=2; case 3: addr[address+3] = value >> 24; address += 1; bytecount+=1; case 1: addr[address+2] = value >> 16; addr[address+1] = value >> 8; address += 2; bytecount+=2; } address += 1; bytecount+=1; break; } else { fprintf(stderr, "oof, %s does not use Indexed Indirect.\n", op.mnemonic); } break; case INDY: if (op.iny) { addr[address++] = op.iny; bytecount+=1; addr[address] = value & 0xFF; switch ((r & 0x0C) >> 2) { case 2: addr[address+5] = (uint64_t)value >> 40; addr[address+4] = (uint64_t)value >> 32; address += 2; bytecount+=2; case 3: addr[address+3] = value >> 24; address += 1; bytecount+=1; case 1: addr[address+2] = value >> 16; addr[address+1] = value >> 8; address += 2; bytecount+=2; } address += 1; bytecount+=1; break; } else { fprintf(stderr, "oof, %s does not use Indirect Indexed.\n", op.mnemonic); } break; } #if debug if (!(done & 6)) { printf("Instruction: %s, ", ins); printf("Addressing Mode: %s,", adrmode[addrmode]); switch (addrmode) { case ZM: printf(" "); break; case IMM: case ABS: case ZMX: case ZMY: case IND: printf(" "); break; case IMPL: case INDX: case INDY: printf(" "); break; } printf("Address: $%llX", address); #if (!__GLIBC__) || (__TINYC__) if (postfix != NULL) { #else if (postfix[0] != '\0') { #endif printf(", Suffix: %s", postfix); } if (prefix) { printf(", Prefix: $%02X", prefix); } if (oprand != NULL && !(done & 16)) { printf(", Operand: %s", oprand); } if (addrtok) { printf(",\tArithmetic mode, and operand: %s, $%llX", (addrtok == 1) ? "+" : "-", val2); } if (ir[0] != '\0' && !(done & 32)) { printf(",\tIndex Register: %s", ir); } puts(""); } #endif } } } } reslv_fixups(); return 0; }