offs_t cop420_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) { uint8_t opcode = opcodes.r8(pc); uint8_t next_opcode = opcodes.r8(pc+1); uint16_t address; uint32_t flags = 0; int bytes = 1; if ((opcode >= 0x80 && opcode <= 0xBE) || (opcode >= 0xC0 && opcode <= 0xFE)) { int page = pc >> 6; if (page == 2 || page == 3) //JP pages 2,3 { address = (uint16_t)((pc & 0x380) | (opcode & 0x7F)); util::stream_format(stream, "JP %03X", address); } else { if ((opcode & 0xC0) == 0xC0) //JP other pages { address = (uint16_t)((pc & 0x3C0) | (opcode & 0x3F)); util::stream_format(stream, "JP %03X", address); } else //JSRP { address = (uint16_t)(0x80 | (opcode & 0x3F)); util::stream_format(stream, "JSRP %03X", address); flags = STEP_OVER; } } }
offs_t capricorn_disassembler::param_dr_lit(std::ostream &stream, offs_t pc, const data_buffer &opcodes) { stream << "DR,="; // Here we assume that multi-byte instructions operate on 2 bytes because we // have no way of knowing how many they are (the actual number of bytes is // dynamically determined by the value of DRP register at run-time) unsigned bytes = BIT(opcodes.r8(pc), 0) ? 2 : 1; for (unsigned i = 1; i <= bytes; i++) { util::stream_format(stream, "$%02x ", opcodes.r8(pc+i)); } return bytes; }
offs_t capricorn_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) { const dis_entry_t *p; uint8_t opcode = opcodes.r8(pc); for (p = dis_table; p->m_op_mask; p++) { if ((opcode & p->m_op_mask) == p->m_opcode) { offs_t res = 1 | p->m_dasm_flags | SUPPORTED; stream << p->m_mnemonic; if (p->m_has_mb) { stream << (BIT(opcode, 0) ? 'M' : 'B'); } if (p->m_addr_mode != '\0') { stream << p->m_addr_mode; } if (p->m_param_fn != nullptr) { stream << " "; res += (this->*(p->m_param_fn))(stream, pc, opcodes); } return res; } } // Unknown opcode stream << "???"; return 1 | SUPPORTED; }
offs_t capricorn_disassembler::param_jmp_off(std::ostream &stream, offs_t pc, const data_buffer &opcodes) { uint16_t off = opcodes.r8(pc+1); if (BIT(off, 7)) { off -= 0x100; } util::stream_format(stream, "$%04x", (pc + 2 + off) & 0xffff); return 1; }
offs_t capricorn_disassembler::param_dr_id_ar(std::ostream &stream, offs_t pc, const data_buffer &opcodes) { stream << "DR," << (BIT(opcodes.r8(pc), 1) ? '-' : '+') << "AR"; return 0; }
offs_t capricorn_disassembler::param_arp_drp(std::ostream &stream, offs_t pc, const data_buffer &opcodes) { stream << "R"; util::stream_format(stream, "%02o", opcodes.r8(pc) & 0x3f); return 0; }
offs_t saturn_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) { int adr=0; int cont=1; // operation still not complete disassembled char bin[10]; int binsize=0; // protocollizing fetched nibbles char number[17]; const OPCODE *level=opcs[0]; //pointer to current digit int op; // currently fetched nibble offs_t pos = pc; int i,c,v; int mnemonics_bank = m_config->get_nonstandard_mnemonics_mode() ? 1 : 0; while (cont) { op = opcodes.r8(pos++) & 0xf; level+=op; switch (level->sel) { case Illegal: cont=0; bin[binsize++]=number_2_hex[op]; bin[binsize]=0; util::stream_format(stream, "???%s",bin); break; default: bin[binsize++]=number_2_hex[op]; switch (level->adr) { case AdrNone: break; case AdrA: adr=field_adr_a[op]; break; case AdrAF: adr=field_adr_af[op]; break; case AdrB: adr=field_adr_b[op&7]; break; default: cont = 0; bin[binsize++]=number_2_hex[op]; bin[binsize]=0; util::stream_format(stream, "???%s",bin); break; } break; case Complete: cont=0; switch (level->adr==AdrNone?adr:level->adr) { case AdrNone: stream << mnemonics[level->mnemonic][mnemonics_bank]; break; case Imm: util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], opcodes.r8(pos++)); break; case ImmCount: util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], opcodes.r8(pos++)+1); break; case AdrImmCount: util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], field_2_string(adr), opcodes.r8(pos++)+1); break; case AdrCount: // mnemonics have string %s for address field snprintf(number,sizeof(number),"%x",opcodes.r8(pos++)+1); util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], number); break; case Imm2: v=opcodes.r8(pos++); v|=opcodes.r8(pos++)<<4; util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], v); break; case Imm4: v=opcodes.r8(pos++); v|=opcodes.r8(pos++)<<4; v|=opcodes.r8(pos++)<<8; v|=opcodes.r8(pos++)<<12; util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], v); break; case Imm5: v=opcodes.r8(pos++); v|=opcodes.r8(pos++)<<4; v|=opcodes.r8(pos++)<<8; v|=opcodes.r8(pos++)<<12; v|=opcodes.r8(pos++)<<16; util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], v); break; case ImmCload: c=i=opcodes.r8(pos++) & 0xf; number[i+1]=0; for (;i>=0; i--) number[i]=number_2_hex[opcodes.r8(pos++) & 0xf]; util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], c+1, number); break; case Dis3: SATURN_PEEKOP_DIS12(v); c=(pc+pos-3+v)&0xfffff; util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], c ); break; case Dis3Call: SATURN_PEEKOP_DIS12(v); c=(pc+pos+v)&0xfffff; util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], c ); break; case Dis4: SATURN_PEEKOP_DIS16(v); c=(pc+pos-4+v)&0xfffff; util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], c ); break; case Dis4Call: SATURN_PEEKOP_DIS16(v); c=(pc+pos+v)&0xfffff; util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], c ); break; case Abs: SATURN_PEEKOP_ADR(v); util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], v ); break; case BranchReturn: SATURN_PEEKOP_DIS8(v); if (v==0) { stream << mnemonics[level->mnemonic+1][mnemonics_bank]; } else { c=(pc+pos-2+v)&0xfffff; util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], c); } break; case ABranchReturn: SATURN_PEEKOP_DIS8(v); if (v==0) { util::stream_format(stream, mnemonics[level->mnemonic+1][mnemonics_bank], A); } else { c=(pc+pos-2+v)&0xfffff; util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], A, c); } break; case xBranchReturn: SATURN_PEEKOP_DIS8(v); if (v==0) { util::stream_format(stream, mnemonics[level->mnemonic+1][mnemonics_bank], field_2_string(adr)); } else { c=(pc+pos-2+v)&0xfffff; util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], field_2_string(adr), c); } break; case TestBranchRet: i=opcodes.r8(pos++); SATURN_PEEKOP_DIS8(v); if (v==0) { util::stream_format(stream, mnemonics[level->mnemonic+1][mnemonics_bank], i); } else { c=(pc+pos-2+v)&0xfffff; util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], i, c); } break; case ImmBranch: i=opcodes.r8(pos++); SATURN_PEEKOP_DIS8(v); c=(pc+pos-2+v)&0xfffff; util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], i, c); break; case FieldP: util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], P ); break; case FieldWP: util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], WP ); break; case FieldXS: util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], XS ); break; case FieldX: util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], X ); break; case FieldS: util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], S ); break; case FieldM: util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], M ); break; case FieldB: util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], B ); break; case FieldA: util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], A ); break; case FieldW: util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], W ); break; case AdrA: util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], adr_a[opcodes.r8(pos++) & 0x7] ); break; case AdrAF: util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], adr_af[opcodes.r8(pos++) & 0xf] ); break; case AdrB: util::stream_format(stream, mnemonics[level->mnemonic][mnemonics_bank], adr_b[opcodes.r8(pos++) & 0x7] ); break; } break; } level = opcs[level->sel]; } return pos - pc; }