#include "asm.h" #include "psuedo.h" #define CLASS T65816Asm void CLASS::setOpcode(MerlinLine &line, uint8_t op) { if (pass > 0) { //printf("cpumode=%d\n",cpumode); if (cpumode < MODE_65816) // instructions are valid if we are in 65816 { uint8_t m = opCodeCompatibility[op]; if ((m > 0) && (cpumode < MODE_65C02)) // if the instruction is non-zero, and we are in 6502 base mode, error { //printf("incompatable: %02X %02X\n",op,m); if (line.errorcode == 0) // don't replace other errors { line.setError(errIncompatibleOpcode); } } } } line.outbytes.push_back(op); } int CLASS::doPSEUDO(MerlinLine &line, TSymbol &sym) { UNUSED(sym); int res; res = psuedoops->ProcessOpcode(*this, line, sym); return (res); } int CLASS::doXC(MerlinLine &line, TSymbol &sym) { UNUSED(sym); std::string s; int res = 0; if (options.isMerlin()) // in merlin8 mode we don't support XC psuedoop { if (line.errorcode == 0) // don't replace other errors { line.setError(errIncompatibleOpcode); } return(res); } if (cpumode < MODE_65816) { cpumode++; } if (line.operand.length() > 0) { s = Poco::toUpper(line.operand); if (s == "OFF") { mx = 0x03; cpumode = MODE_6502; } } return (res); } int CLASS::doMX(MerlinLine &line, TSymbol &sym) { UNUSED(sym); if (cpumode < MODE_65816) { line.setError(errIncompatibleOpcode); } else { mx = (uint8_t)(line.expr_value & 0x03); line.linemx = mx; } return (0); } int CLASS::doEQU(MerlinLine &line, TSymbol &sym) { UNUSED(sym); int res = 0; TSymbol *s; if (line.lable.length() > 0) { //printf("EQU: |%s|\n",line.operand.c_str()); bool isvar = (line.lable[0] == ']') ? true : false; if ((pass == 0) && (!isvar)) { res = -1; //printf("EQU: |%s| %08X\n", line.lable.c_str(), line.expr_value); s = addSymbol(line.lable, line.expr_value, true); if (s != NULL) { res = 0; } } else if (isvar) { res = -1; #if 1 char buff[32]; sprintf(buff, "$%08X", line.expr_value); std::string s1 = buff; s = addVariable(line.lable, s1, variables,true); #else // do this if you want to do this more as a #define s = addVariable(line.lable, line.operand, variables,true); #endif if (s != NULL) { res = 0; } } } return (res); } int CLASS::doUNK(MerlinLine &line, TSymbol &sym) { int res = -1; UNUSED(sym); res = 0; if (pass > 0) { line.setError(errIncomplete); //line.outbytes.push_back(0x00); line.outbytect = res; } return (res); } // PER is a special case because it does strange address calcs int CLASS::doPER(MerlinLine &line, TSymbol &sym) { int res; int32_t value = 0;; UNUSED(sym); res = 0; if ((line.addressmode == syn_abs) || (line.addressmode == syn_imm)) { res = 3; if (pass > 0) { // SGQ should check under/over flows value = line.expr_value; value -= line.startpc + 3; //printf("addr calc=%08X %08X %08X\n",line.expr_value,line.startpc+3,value); setOpcode(line, sym.opcode); line.outbytes.push_back(value & 0xFF); line.outbytes.push_back((value >> 8) & 0xFF); line.outbytect = res; } } if (res == 0) { line.setError(errBadAddressMode); } return (res); } int CLASS::doMVN(MerlinLine &line, TSymbol &sym) { int res; uint8_t op; UNUSED(sym); if (line.addressmode == syn_bm) { res = 3; if (pass > 0) { if (sym.opcode == 0) { op = 0x54; // MVN } else { op = 0x44; // MVP } int64_t value = -1; int x = evaluate(line, line.operand_expr2, value); if (x == 0) { value &= 0xFFFFFFFF; } else { value = 0xFFFFFFFF; line.setError(errBadOperand); //line.errorText = line.operand_expr2; } uint32_t v=(value & 0xFFFFFFFF); //printf("val1 %08X\n",v); //printf("val1 %08X\n",line.expr_value); setOpcode(line, op); // these bytes are the two bank registers if (options.isMerlin32() && (v<256)) //if (((line.syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) && (v<256)) { // merlin32 uses the low byte of the two operands line.outbytes.push_back((v) & 0xFF); line.outbytes.push_back((line.expr_value) & 0xFF); } else { // merlin16 uses the high byte (bank) as the opcode line.outbytes.push_back((v>>16) & 0xFF); line.outbytes.push_back((line.expr_value>>16) & 0xFF); } line.outbytect = res; } } else { line.setError(errBadAddressMode); res = 0; } return (res); } int CLASS::doNoPattern(MerlinLine &line, TSymbol &sym) { // this handles a few opcodes that don't fit mathmatically in the opcode table // the 'sym.opcode' table identifies what each is: // STZ = 1 // TSB = 2 // TRB = 3 UNUSED(sym); int res, i; uint8_t err; uint8_t op; uint8_t m = line.addressmode; res = 1; op = 0x00; err = errBadAddressMode; switch (sym.opcode) { case 1: // STZ res++; op = (m == syn_abs ? 0x64 : op); op = (m == syn_absx ? 0x74 : op); if ((op != 0) && ((line.expr_value >= 0x100) || (line.flags & FLAG_FORCEABS))) { res++; op = (op == 0x64) ? 0x9C : op; op = (op == 0x74) ? 0x9E : op; } break; case 2: // TSB res++; op = (m == syn_abs ? 0x04 : op); if ((op != 0) && ((line.expr_value >= 0x100) || (line.flags & FLAG_FORCEABS))) { res++; op = 0x0C; } break; case 3: // TRB res++; op = (m == syn_abs ? 0x14 : op); if ((op != 0) && ((line.expr_value >= 0x100) || (line.flags & FLAG_FORCEABS))) { res++; op = 0x1C; } break; default: op = 0; err = errBadOpcode; break; } if (op == 0x00) { res = 0; line.setError(err); } if ((pass > 0) && (res > 0)) { setOpcode(line, op); for (i = 0; i < (res - 1); i++) { line.outbytes.push_back(line.expr_value >> (8 * i)); } line.outbytect = res; } return (res); } int CLASS::doAddress(MerlinLine &line, TSymbol &sym) { // this routine uses the 'opcode' specifed in the sym.opcode field. // it also adds the number of bytes stored in the sym.stype field after doing an evaluation int res, i; res = 1 + sym.stype; if (pass > 0) { //if (isMerlin816()) //{ //} switch(line.expr_shift) { case '^': line.expr_value=(line.expr_value>>16)&0xFFFF; break; case '<': line.expr_value=(line.expr_value)&0xFF; break; case '>': line.expr_value=(line.expr_value>>8)&0xFFFF; break; } //line.setError(errIncomplete); setOpcode(line, sym.opcode); for (i = 0; i < (res - 1); i++) { line.outbytes.push_back(line.expr_value >> (i * 8)); } line.outbytect = res; } // if these are REP or SEP, see if we need to track if ((trackrep) && ((sym.opcode == 0xC2) || (sym.opcode == 0xE2))) { if (cpumode >= MODE_65816) { //printf("trackrep: %02X\n",line.expr_value&0xFF); // SGQ - if evaluation has errors, this must cause an error here // because expr_value won't be valid during pass 0 and will screw // up MX uint8_t newmx = (line.expr_value & 0x30) >> 4; switch (sym.opcode) { case 0xC2: // REP mx &= ~newmx; break; case 0xE2: // SEP mx |= newmx; break; } line.linemx = mx; } } return (res); } int CLASS::doJMP(MerlinLine &line, TSymbol &sym) { int res, i; bool err = false; uint8_t op; uint8_t optype = sym.opcode; uint8_t m = line.addressmode; res = 3; op = 0; if (optype & 0x02) // these are SUBROUTINES { op = (m == syn_abs ? 0x20 : op); op = (m == syn_diix ? 0xFC : op); if (!(optype & 0x01)) // jsl? { res++; op = 0x22; } } else { op = (m == syn_abs ? 0x4C : op); op = (m == syn_di ? 0x6C : op); op = (m == syn_diix ? 0x7C : op); op = (m == syn_dil ? 0xDC : op); if (!(optype & 0x01)) // JML? { op = (m == syn_abs ? 0x5C : op); } if ((op == 0xDC) || (op == 0x5C)) { if (cpumode < MODE_65816) { op = 0; // can't do these without an '816 } if (op == 0x5C) { res++; } } } if (op == 0) { err = true; } if (err) { res = 0; line.setError(errBadAddressMode); } if ((pass > 0) && (res > 0)) { setOpcode(line, op); for (i = 0; i < (res - 1); i++) { line.outbytes.push_back((line.expr_value >> (8 * i)) & 0xFF); } line.outbytect = res; } return (res); } int CLASS::doBRANCH(MerlinLine & line, TSymbol & sym) { int res, i; res = 2; uint8_t op = (sym.opcode << 6) & 0xC0; op |= 0x10; // make it a branch opcode if (sym.opcode & 0x80) { op |= 0x20; } if (sym.opcode & 0x40) // BRA { op = 0x80; } if (sym.opcode & 0x20) // BRL { op = 0x82; res++; } if ((pass > 0) && (res > 0)) { int64_t o64 = line.expr_value; int32_t o32 = (int32_t)(o64 & 0xFFFFFFFF); int32_t offset = o32 - line.startpc - res; bool err = false; if (res == 2) // short branch { if ((offset < -128) || (offset > 127)) { err = true; op = 0x00; // merlin does this } } else if (res == 3) // long branch { if ((offset < -32768) || (offset > 32767)) { err = true; // for BRL, merlin DOES NOT kill the opcode //op=0x00; // merlin does this } } //printf("offset %d\n", offset); setOpcode(line, op); for (i = 0; i < (res - 1); i++) { uint8_t v = (offset >> (i * 8)); v = err ? 0x00 : v; line.outbytes.push_back(v); } line.outbytect = res; if (err) { line.setError(errBadBranch); } } return (res); } // aaabbbcc int CLASS::doBase6502(MerlinLine & line, TSymbol & sym) { int res = 1; int i; uint8_t bytelen = 1; uint8_t cc; uint8_t op, amode; uint16_t opflags; bool err = false; uint16_t m = line.addressmode; //std::string opcode = Poco::toUpper(line.opcode); line.opflags = opflags = sym.stype; op = (sym.opcode << 5) & 0xE0; cc = (sym.stype >> 8) & 0x03; amode = 0xFF; if ((sym.stype & OP_C0) == OP_C0) { uint8_t cc = 0; uint8_t bbb = 0xFF; bbb = (m == syn_imm ? 0 : bbb); bbb = (m == syn_abs ? 1 : bbb); bbb = (m == syn_absx ? 5 : bbb); //printf("expr_value=%08X\n",line.expr_value); if ((sym.opcode == 1) && (m == syn_imm)) //BIT special case { cc = 0x01; op = 0x80; bbb = 0x02; } else if ((bbb > 0) && ((line.expr_value >= 0x100) || (line.flags & FLAG_FORCEABS))) { bbb |= 0x02; bytelen++; } op |= (bbb << 2) | cc; if (m == syn_imm) { int add = 0; switch (sym.opcode) { case 7: // CPX case 6: // CPY case 5: // LDY case 4: // STY if ((mx & 0x01) == 0) { add = 1; } break; case 1: // BIT if ((mx & 0x02) == 0) { add = 1; } break; } bytelen += add; } goto out; } if (cc == 0x01) { switch (m) { case syn_diix: amode = 0; break; case syn_abs: amode = 1; break; case syn_imm: amode = 2; break; case syn_diiy: amode = 4; break; case syn_absx: amode = 5; break; case syn_absy: amode = 6; break; //case syn_none: // printf("syn_none on ROR OP_A\n"); // break; default: err = true; break; } } else if (cc == 0x02) { switch (m) { case syn_imm: amode = 0; break; case syn_abs: amode = 1; break; case syn_implied: amode = 2; bytelen = 0; break; case syn_absy: if ((opflags & OP_STX) == OP_STX) { amode = 5; } break; case syn_absx: amode = 5; break; // this is actually Y addressing because X register is used default: err = true; break; } if ((opflags & OP_STX) == OP_STX) { if (m == syn_implied) { err = true; } if (m == syn_imm) { if ((mx & 0x01) == 0) { bytelen++; } } if ( ((m == syn_absx) || (m == syn_diix)) && ((sym.opcode == 4) || (sym.opcode == 5))) // these are STX,LDX { err = true; } if ((m == syn_absx) || (m == syn_abs) || (m == syn_absy)) { if ((line.flags & FLAG_FORCEABS) || (line.expr_value >= 0x100) ) { bytelen++; amode += 2; } } if (cpumode >= MODE_65C02) { if (m == syn_implied) { if ((opflags & (OP_STX | OP_SPECIAL)) == (OP_STX | OP_SPECIAL)) { if (sym.opcode == 0x07) // INC { err = false; op = 0x1A; bytelen = 0; goto out; } if (sym.opcode == 0x06) // DEC { err = false; op = 0x3A; bytelen = 0; goto out; } } } } } else { if ((m == syn_absx) || (m == syn_abs)) { if ((line.flags & FLAG_FORCEABS) || (line.expr_value >= 0x100)) { bytelen++; amode += 2; } } } if (line.flags & FLAG_FORCELONG) { //err = errBadAddressMode; err=true; line.setError(errBadAddressMode); } goto outop; } if (m == syn_imm) { uint8_t mask = 0x02; if (cc == 0x02) // the non accumulator { mask = 0x01; } if ((mx & mask) == 0) { bytelen++; } } else if ((m == syn_abs) || (m == syn_absx) || (m == syn_absy)) { if ((((line.flags & FLAG_DP) == 0) && ((line.flags & FLAG_FORCEDP) == 0)) || (line.flags & FLAG_FORCEABS) || (m==syn_absy) ) { bytelen++; if (amode != 6) { amode += 2; } } if (line.flags & FLAG_FORCELONG) { // we are in 65C02/02 mode, so long addressing not supported err = true; } } if (err) // not a 6502 address mode { //if (cpumode >= MODE_65816) if (cpumode >= MODE_65C02) { cc = 0x03; err = false; switch (m) { case syn_s: amode = 0; break; case syn_sy: amode = 4; break; case syn_di: cc = 0x02; amode = 4; break; case syn_iyl: amode = 5; break; case syn_dil: amode = 1; break; case syn_absx: amode = 7; break; case syn_abs: amode = 3; break; default: //printf("bad syn_mode=%d\n", m); err = true; break; } if (!err) { if ((m == syn_abs) || (m == syn_absx)) { if (line.flags & FLAG_FORCELONG) { bytelen = 3; } } } } } outop: op |= (amode & 0x07) << 2; op |= cc; out: if (err) { line.setError(errBadAddressMode); printf("bad address mode %d\n",line.addressmode); op = 0x00; res = 0; bytelen = 0; } res += bytelen; if ((pass > 0) && (res > 0)) { int pidx=0; uint8_t *ptr=(uint8_t *)&line.expr_value; setOpcode(line, op); if (line.shiftchar!=0) { if (m==syn_imm) { switch(line.shiftchar) { case '>': pidx+=1; break; case '^': pidx+=2; break; } } else { switch(line.shiftchar) { case '>': { if ((line.flags&FLAG_FORCELONG)!=FLAG_FORCELONG) { pidx+=1; } } break; case '^': { } break; } } } for (i = 0; i < (res - 1); i++) { if (pidx>3) // don't over index into 32 bit int { line.outbytes.push_back(0x00); } else { line.outbytes.push_back(ptr[pidx]); pidx++; } } line.outbytect = res; } return (res); } int CLASS::doEND(MerlinLine & line, TSymbol & sym) { UNUSED(sym); UNUSED(line); int res = 0; passcomplete = true; return (res); } int CLASS::doBYTE(MerlinLine & line, TSymbol & sym) { UNUSED(sym); int res = 1; if (pass > 0) { setOpcode(line, sym.opcode); line.outbytect = res; } // SGQ merlin32 apparently tracks XCE instructions when tracking MX status // who knows how they determine this. I am assuming the NEXT instruction // after a SEC/CLC instruction must be an XCE if (options.isMerlin32()) { if (sym.opcode == 0x38) // SEC { lastcarry = true; } else if (sym.opcode == 0x18) // CLC { lastcarry = false; } else if (sym.opcode == 0xFB) // XCE { if (trackrep) { if (lastcarry) { mx = 0x03; } } } } return (res); } int CLASS::doBRK(MerlinLine & line, TSymbol & sym) { UNUSED(sym); int res = 1; int bytes = 0; if (line.operand_expr != "") { bytes++; } if (pass > 0) { setOpcode(line, sym.opcode); for (int i = 0; i < bytes; i++) { line.outbytes.push_back((line.expr_value >> (8 * i)) & 0xFF); } line.outbytect = res + bytes; } return (res + bytes); } void CLASS::insertOpcodes(void) { pushopcode("=", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doEQU)); pushopcode("EQU", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doEQU)); pushopcode("END", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doEND)); pushopcode("MX", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doMX)); pushopcode("XC", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doXC)); pushopcode("EXT", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("ENT", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("ORG", P_ORG, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("DSK", P_SAV, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("SAV", P_SAV, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("DS", P_DS, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("REL", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("OBJ", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("PUT", P_PUT, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("USE", P_USE, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("VAR", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("TYP", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("DUM", P_DUM, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("DEND", P_DEND, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("AST", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("CAS", P_CAS, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("CYC", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("DAT", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("EXP", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("LST", P_LST, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("LSTDO", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("PAG", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("TTL", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("SKP", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("PAU", P_PAU, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("TR", P_TR, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("ASC", P_ASC, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("DCI", P_ASC, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("INV", P_ASC, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("FLS", P_ASC, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("REV", P_ASC, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("STR", P_ASC, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("STRL", P_ASC, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("DA", P_DATA, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("DW", P_DATA, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("DDB", P_DATA, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("DFB", P_DATA, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("DB", P_DATA, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("ADR", P_DATA, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("ADRL", P_DATA, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("HEX", P_HEX, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("DO", P_DO, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("ELSE", P_DO, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("IF", P_DO, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("FIN", P_DO, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("CHK", P_CHK, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("ERR", P_ERR, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("KBD", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("LUP", P_LUP, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("--^", P_LUP, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("SW", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("USR", P_USR, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("MAC", P_MAC, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("EOM", P_MAC, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("<<<", P_MAC, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode(">>>", P_MAC, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("ADC", 0x03, OP_STD | OP_A, OPHANDLER(&CLASS::doBase6502)); pushopcode("AND", 0x01, OP_STD | OP_A, OPHANDLER(&CLASS::doBase6502)); pushopcode("ASL", 0x00, OP_ASL | OP_A, OPHANDLER(&CLASS::doBase6502)); pushopcode("BCC", 0x02, 0, OPHANDLER(&CLASS::doBRANCH)); pushopcode("BLT", 0x02, 0, OPHANDLER(&CLASS::doBRANCH)); pushopcode("BCS", 0x82, 0, OPHANDLER(&CLASS::doBRANCH)); pushopcode("BGE", 0x82, 0, OPHANDLER(&CLASS::doBRANCH)); pushopcode("BEQ", 0x83, 0, OPHANDLER(&CLASS::doBRANCH)); pushopcode("BIT", 0x01, OP_C0, OPHANDLER(&CLASS::doBase6502)); pushopcode("BMI", 0x80, 0, OPHANDLER(&CLASS::doBRANCH)); pushopcode("BNE", 0x03, 0, OPHANDLER(&CLASS::doBRANCH)); pushopcode("BPL", 0x00, 0, OPHANDLER(&CLASS::doBRANCH)); pushopcode("BRA", 0x40, 0, OPHANDLER(&CLASS::doBRANCH)); pushopcode("BRK", 0x00, 1, OPHANDLER(&CLASS::doBRK)); pushopcode("BRL", 0x20, 0, OPHANDLER(&CLASS::doBRANCH)); pushopcode("BVC", 0x01, 0, OPHANDLER(&CLASS::doBRANCH)); pushopcode("BVS", 0x81, 0, OPHANDLER(&CLASS::doBRANCH)); pushopcode("CLC", 0x18, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("CLD", 0xD8, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("CLI", 0x58, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("CLV", 0xB8, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("CMP", 0x06, OP_STD | OP_A, OPHANDLER(&CLASS::doBase6502)); pushopcode("COP", 0x02, 1, OPHANDLER(&CLASS::doAddress)); pushopcode("CPX", 0x07, OP_C0 | OP_XY, OPHANDLER(&CLASS::doBase6502)); pushopcode("CPY", 0x06, OP_C0 | OP_XY, OPHANDLER(&CLASS::doBase6502)); pushopcode("DEC", 0x06, OP_STX | OP_SPECIAL | OP_A, OPHANDLER(&CLASS::doBase6502)); pushopcode("DEX", 0xCA, OP_XY, OPHANDLER(&CLASS::doBYTE)); pushopcode("DEY", 0x88, OP_XY, OPHANDLER(&CLASS::doBYTE)); pushopcode("EOR", 0x02, OP_STD | OP_A, OPHANDLER(&CLASS::doBase6502)); pushopcode("INC", 0x07, OP_STX | OP_A | OP_SPECIAL, OPHANDLER(&CLASS::doBase6502)); pushopcode("INX", 0xE8, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("INY", 0xC8, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("JML", 0x00, 0, OPHANDLER(&CLASS::doJMP)); pushopcode("JMP", 0x01, 0, OPHANDLER(&CLASS::doJMP)); pushopcode("JSL", 0x02, 0, OPHANDLER(&CLASS::doJMP)); pushopcode("JSR", 0x03, 0, OPHANDLER(&CLASS::doJMP)); pushopcode("LDA", 0x05, OP_STD | OP_A, OPHANDLER(&CLASS::doBase6502)); pushopcode("LDX", 0x05, OP_STX | OP_XY, OPHANDLER(&CLASS::doBase6502)); pushopcode("LDY", 0x05, OP_C0 | OP_XY, OPHANDLER(&CLASS::doBase6502)); pushopcode("LSR", 0x02, OP_ASL | OP_A, OPHANDLER(&CLASS::doBase6502)); pushopcode("MVN", 0x00, 0, OPHANDLER(&CLASS::doMVN)); pushopcode("MVP", 0x01, 0, OPHANDLER(&CLASS::doMVN)); pushopcode("NOP", 0xEA, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("ORA", 0x00, OP_STD | OP_A, OPHANDLER(&CLASS::doBase6502)); pushopcode("PEA", 0xF4, 2, OPHANDLER(&CLASS::doAddress)); pushopcode("PEI", 0xD4, 1, OPHANDLER(&CLASS::doAddress)); pushopcode("PER", 0x62, 2, OPHANDLER(&CLASS::doPER)); pushopcode("PHA", 0x48, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("PHB", 0x8B, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("PHD", 0x0B, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("PHK", 0x4B, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("PHP", 0x08, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("PHX", 0xDA, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("PHY", 0x5A, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("PLA", 0x68, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("PLB", 0xAB, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("PLD", 0x2B, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("PLP", 0x28, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("PLX", 0xFA, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("PLY", 0x7A, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("REP", 0xC2, 1, OPHANDLER(&CLASS::doAddress)); pushopcode("ROL", 0x01, OP_ASL | OP_A, OPHANDLER(&CLASS::doBase6502)); pushopcode("ROR", 0x03, OP_ASL | OP_A, OPHANDLER(&CLASS::doBase6502)); pushopcode("RTI", 0x40, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("RTL", 0x6B, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("RTS", 0x60, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("SBC", 0x07, OP_STD | OP_A, OPHANDLER(&CLASS::doBase6502)); pushopcode("SEC", 0x38, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("SED", 0xF8, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("SEI", 0x78, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("SEP", 0xE2, 1, OPHANDLER(&CLASS::doAddress)); pushopcode("STP", 0xDB, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("STA", 0x04, OP_STD | OP_A, OPHANDLER(&CLASS::doBase6502)); pushopcode("STX", 0x04, OP_STX | OP_XY, OPHANDLER(&CLASS::doBase6502)); pushopcode("STY", 0x04, OP_C0 | OP_XY, OPHANDLER(&CLASS::doBase6502)); pushopcode("STZ", 0x01, OP_A, OPHANDLER(&CLASS::doNoPattern)); pushopcode("TAX", 0xAA, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("TAY", 0xA8, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("TCD", 0x5B, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("TAD", 0x5B, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("TCS", 0x1B, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("TAS", 0x1B, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("TDC", 0x7B, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("TDA", 0x7B, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("TRB", 0x03, OP_A, OPHANDLER(&CLASS::doNoPattern)); pushopcode("TSB", 0x02, OP_A, OPHANDLER(&CLASS::doNoPattern)); pushopcode("TSC", 0x3B, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("TSA", 0x3B, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("TSX", 0xBA, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("TXA", 0x8A, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("TXS", 0x9A, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("TXY", 0x9B, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("TYA", 0x98, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("TYX", 0xBB, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("WAI", 0xCB, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("WDM", 0x42, 1, OPHANDLER(&CLASS::doAddress)); pushopcode("XBA", 0xEB, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("SWA", 0xEB, 0, OPHANDLER(&CLASS::doBYTE)); pushopcode("XCE", 0xFB, 0, OPHANDLER(&CLASS::doBYTE)); } #undef CLASS