mirror of
https://github.com/mrkite/regs.git
synced 2024-09-07 11:54:25 +00:00
basic blocks
This commit is contained in:
parent
54b1b4b8ce
commit
c7837da33e
317
src/65816.h
Normal file
317
src/65816.h
Normal file
@ -0,0 +1,317 @@
|
||||
/** @copyright 2020 Sean Kasun */
|
||||
#pragma once
|
||||
|
||||
#include "disasm.h"
|
||||
|
||||
enum Addressing {
|
||||
IMP, IMM, IMMM, IMMX, IMMS, ABS, ABL, ABX, ABY, ABLX, AIX,
|
||||
ZP, ZPX, ZPY, ZPS, IND, INZ, INL, INX, INY, INLY, INS, REL, RELL,
|
||||
BANK, DB, DW, DD,
|
||||
};
|
||||
|
||||
struct Opcode {
|
||||
const char *inst;
|
||||
Addressing addressing;
|
||||
InsType type;
|
||||
};
|
||||
|
||||
#define op(a, b, c) {#a, b, InsType::c}
|
||||
|
||||
static const Opcode opcodes[] = {
|
||||
op(brk, IMP, Return), // 00
|
||||
op(ora, INX, Normal), // 01
|
||||
op(cop, IMP, Normal), // 02
|
||||
op(ora, ZPS, Normal), // 03
|
||||
op(tsb, ZP, Normal), // 04
|
||||
op(ora, ZP, Normal), // 05
|
||||
op(asl, ZP, Normal), // 06
|
||||
op(ora, INL, Normal), // 07
|
||||
op(php, IMP, Normal), // 08
|
||||
op(ora, IMMM, Normal), // 09
|
||||
op(asl, IMP, Normal), // 0a
|
||||
op(phd, IMP, Normal), // 0b
|
||||
op(tsb, ABS, Normal), // 0c
|
||||
op(ora, ABS, Normal), // 0d
|
||||
op(asl, ABS, Normal), // 0e
|
||||
op(ora, ABL, Normal), // 0f
|
||||
op(bpl, REL, Branch), // 10
|
||||
op(ora, INY, Normal), // 11
|
||||
op(ora, INZ, Normal), // 12
|
||||
op(ora, INS, Normal), // 13
|
||||
op(trb, ZP, Normal), // 14
|
||||
op(ora, ZPX, Normal), // 15
|
||||
op(asl, ZPX, Normal), // 16
|
||||
op(ora, INLY, Normal), // 17
|
||||
op(clc, IMP, Normal), // 18
|
||||
op(ora, ABY, Normal), // 19
|
||||
op(inc, IMP, Normal), // 1a
|
||||
op(tcs, IMP, Normal), // 1b
|
||||
op(trb, ABS, Normal), // 1c
|
||||
op(ora, ABX, Normal), // 1d
|
||||
op(asl, ABX, Normal), // 1e
|
||||
op(ora, ABLX, Normal), // 1f
|
||||
op(jsr, ABS, Call), // 20
|
||||
op(and, INX, Normal), // 21
|
||||
op(jsl, ABL, Call), // 22
|
||||
op(and, ZPS, Normal), // 23
|
||||
op(bit, ZP, Normal), // 24
|
||||
op(and, ZP, Normal), // 25
|
||||
op(rol, ZP, Normal), // 26
|
||||
op(and, INL, Normal), // 27
|
||||
op(plp, IMP, Normal), // 28
|
||||
op(and, IMMM, Normal), // 29
|
||||
op(rol, IMP, Normal), // 2a
|
||||
op(pld, IMP, Normal), // 2b
|
||||
op(bit, ABS, Normal), // 2c
|
||||
op(and, ABS, Normal), // 2d
|
||||
op(rol, ABS, Normal), // 2e
|
||||
op(and, ABL, Normal), // 2f
|
||||
op(bmi, REL, Branch), // 30
|
||||
op(and, INY, Normal), // 31
|
||||
op(and, INZ, Normal), // 32
|
||||
op(and, INS, Normal), // 33
|
||||
op(bit, ZPX, Normal), // 34
|
||||
op(and, ZPX, Normal), // 35
|
||||
op(rol, ZPX, Normal), // 36
|
||||
op(and, INLY, Normal), // 37
|
||||
op(sec, IMP, Normal), // 38
|
||||
op(and, ABY, Normal), // 39
|
||||
op(dec, IMP, Normal), // 3a
|
||||
op(tsc, IMP, Normal), // 3b
|
||||
op(bit, ABX, Normal), // 3c
|
||||
op(and, ABX, Normal), // 3d
|
||||
op(rol, ABX, Normal), // 3e
|
||||
op(and, ABLX, Normal), // 3f
|
||||
op(rti, IMP, Return), // 40
|
||||
op(eor, INX, Normal), // 41
|
||||
op(db, DB, Invalid), // 42
|
||||
op(eor, ZPS, Normal), // 43
|
||||
op(mvp, BANK, Normal), // 44
|
||||
op(eor, ZP, Normal), // 45
|
||||
op(lsr, ZP, Normal), // 46
|
||||
op(eor, INL, Normal), // 47
|
||||
op(pha, IMP, Normal), // 48
|
||||
op(eor, IMMM, Normal), // 49
|
||||
op(lsr, IMP, Normal), // 4a
|
||||
op(phk, IMP, Normal), // 4b
|
||||
op(jmp, ABS, Jump), // 4c
|
||||
op(eor, ABS, Normal), // 4d
|
||||
op(lsr, ABS, Normal), // 4e
|
||||
op(eor, ABL, Normal), // 4f
|
||||
op(bvc, REL, Branch), // 50
|
||||
op(eor, INY, Normal), // 51
|
||||
op(eor, INZ, Normal), // 52
|
||||
op(eor, INS, Normal), // 53
|
||||
op(mvn, BANK, Normal), // 54
|
||||
op(eor, ZPX, Normal), // 55
|
||||
op(lsr, ZPX, Normal), // 56
|
||||
op(eor, INLY, Normal), // 57
|
||||
op(cli, IMP, Normal), // 58
|
||||
op(eor, ABY, Normal), // 59
|
||||
op(phy, IMP, Normal), // 5a
|
||||
op(tcd, IMP, Normal), // 5b
|
||||
op(jmp, ABL, Jump), // 5c
|
||||
op(eor, ABX, Normal), // 5d
|
||||
op(lsr, ABX, Normal), // 5e
|
||||
op(eor, ABLX, Normal), // 5f
|
||||
op(rts, IMP, Return), // 60
|
||||
op(adc, INX, Normal), // 61
|
||||
op(per, REL, Normal), // 62
|
||||
op(adc, ZPS, Normal), // 63
|
||||
op(stz, ZP, Normal), // 64
|
||||
op(adc, ZP, Normal), // 65
|
||||
op(ror, ZP, Normal), // 66
|
||||
op(adc, INL, Normal), // 67
|
||||
op(pla, IMP, Normal), // 68
|
||||
op(adc, IMMM, Normal), // 69
|
||||
op(ror, IMP, Normal), // 6a
|
||||
op(rtl, IMP, Return), // 6b
|
||||
op(jmp, IND, Jump), // 6c
|
||||
op(adc, ABS, Normal), // 6d
|
||||
op(ror, ABS, Normal), // 6e
|
||||
op(adc, ABL, Normal), // 6f
|
||||
op(bvs, REL, Branch), // 70
|
||||
op(adc, INY, Normal), // 71
|
||||
op(adc, INZ, Normal), // 72
|
||||
op(adc, INS, Normal), // 73
|
||||
op(stz, ZPX, Normal), // 74
|
||||
op(adc, ZPX, Normal), // 75
|
||||
op(ror, ZPX, Normal), // 76
|
||||
op(adc, INLY, Normal), // 77
|
||||
op(sei, IMP, Normal), // 78
|
||||
op(adc, ABY, Normal), // 79
|
||||
op(ply, IMP, Normal), // 7a
|
||||
op(tdc, IMP, Normal), // 7b
|
||||
op(jmp, AIX, Jump), // 7c
|
||||
op(adc, ABX, Normal), // 7d
|
||||
op(ror, ABX, Normal), // 7e
|
||||
op(adc, ABLX, Normal), // 7f
|
||||
op(bra, REL, Jump), // 80
|
||||
op(sta, INX, Normal), // 81
|
||||
op(brl, RELL, Jump), // 82
|
||||
op(sta, ZPS, Normal), // 83
|
||||
op(sty, ZP, Normal), // 84
|
||||
op(sta, ZP, Normal), // 85
|
||||
op(stx, ZP, Normal), // 86
|
||||
op(sta, INL, Normal), // 87
|
||||
op(dey, IMP, Normal), // 88
|
||||
op(bit, IMMM, Normal), // 89
|
||||
op(txa, IMP, Normal), // 8a
|
||||
op(phb, IMP, Normal), // 8b
|
||||
op(sty, ABS, Normal), // 8c
|
||||
op(sta, ABS, Normal), // 8d
|
||||
op(stx, ABS, Normal), // 8e
|
||||
op(sta, ABL, Normal), // 8f
|
||||
op(bcc, REL, Branch), // 90
|
||||
op(sta, INY, Normal), // 91
|
||||
op(sta, INZ, Normal), // 92
|
||||
op(sta, INS, Normal), // 93
|
||||
op(sty, ZPX, Normal), // 94
|
||||
op(sta, ZPX, Normal), // 95
|
||||
op(stx, ZPY, Normal), // 96
|
||||
op(sta, INLY, Normal), // 97
|
||||
op(tya, IMP, Normal), // 98
|
||||
op(sta, ABY, Normal), // 99
|
||||
op(txs, IMP, Normal), // 9a
|
||||
op(txy, IMP, Normal), // 9b
|
||||
op(stz, ABS, Normal), // 9c
|
||||
op(sta, ABX, Normal), // 9d
|
||||
op(stz, ABX, Normal), // 9e
|
||||
op(sta, ABLX, Normal), // 9f
|
||||
op(ldy, IMMX, Normal), // a0
|
||||
op(lda, INX, Normal), // a1
|
||||
op(ldx, IMMX, Normal), // a2
|
||||
op(lda, ZPS, Normal), // a3
|
||||
op(ldy, ZP, Normal), // a4
|
||||
op(lda, ZP, Normal), // a5
|
||||
op(ldx, ZP, Normal), // a6
|
||||
op(lda, INL, Normal), // a7
|
||||
op(tay, IMP, Normal), // a8
|
||||
op(lda, IMMM, Normal), // a9
|
||||
op(tax, IMP, Normal), // aa
|
||||
op(plb, IMP, Normal), // ab
|
||||
op(ldy, ABS, Normal), // ac
|
||||
op(lda, ABS, Normal), // ad
|
||||
op(ldx, ABS, Normal), // ae
|
||||
op(lda, ABL, Normal), // af
|
||||
op(bcs, REL, Branch), // b0
|
||||
op(lda, INY, Normal), // b1
|
||||
op(lda, INZ, Normal), // b2
|
||||
op(lda, INS, Normal), // b3
|
||||
op(ldy, ZPX, Normal), // b4
|
||||
op(lda, ZPX, Normal), // b5
|
||||
op(ldx, ZPY, Normal), // b6
|
||||
op(lda, INLY, Normal), // b7
|
||||
op(clv, IMP, Normal), // b8
|
||||
op(lda, ABY, Normal), // b9
|
||||
op(tsx, IMP, Normal), // ba
|
||||
op(tyx, IMP, Normal), // bb
|
||||
op(ldy, ABX, Normal), // bc
|
||||
op(lda, ABX, Normal), // bd
|
||||
op(ldx, ABY, Normal), // be
|
||||
op(lda, ABLX, Normal), // bf
|
||||
op(cpy, IMMX, Normal), // c0
|
||||
op(cmp, INX, Normal), // c1
|
||||
op(rep, IMM, Normal), // c2
|
||||
op(cmp, ZPS, Normal), // c3
|
||||
op(cpy, ZP, Normal), // c4
|
||||
op(cmp, ZP, Normal), // c5
|
||||
op(dec, ZP, Normal), // c6
|
||||
op(cmp, INL, Normal), // c7
|
||||
op(iny, IMP, Normal), // c8
|
||||
op(cmp, IMMM, Normal), // c9
|
||||
op(dex, IMP, Normal), // ca
|
||||
op(wai, IMP, Normal), // cb
|
||||
op(cpy, ABS, Normal), // cc
|
||||
op(cmp, ABS, Normal), // cd
|
||||
op(dec, ABS, Normal), // ce
|
||||
op(cmp, ABL, Normal), // cf
|
||||
op(bne, REL, Branch), // d0
|
||||
op(cmp, INY, Normal), // d1
|
||||
op(cmp, INZ, Normal), // d2
|
||||
op(cmp, INS, Normal), // d3
|
||||
op(pei, ZP, Normal), // d4
|
||||
op(cmp, ZPX, Normal), // d5
|
||||
op(DEC, ZPX, Normal), // d6
|
||||
op(cmp, INLY, Normal), // d7
|
||||
op(cld, IMP, Normal), // d8
|
||||
op(cmp, ABY, Normal), // d9
|
||||
op(phx, IMP, Normal), // da
|
||||
op(stp, IMP, Return), // db
|
||||
op(jmp, IND, Jump), // dc
|
||||
op(cmp, ABX, Normal), // dd
|
||||
op(dec, ABX, Normal), // de
|
||||
op(cmp, ABLX, Normal), // df
|
||||
op(cpx, IMMX, Normal), // e0
|
||||
op(sbc, INX, Normal), // e1
|
||||
op(sep, IMM, Normal), // e2
|
||||
op(sbc, ZPS, Normal), // e3
|
||||
op(cpx, ZP, Normal), // e4
|
||||
op(sbc, ZP, Normal), // e5
|
||||
op(inc, ZP, Normal), // e6
|
||||
op(sbc, INL, Normal), // e7
|
||||
op(inx, IMP, Normal), // e8
|
||||
op(sbc, IMMM, Normal), // e9
|
||||
op(nop, IMP, Normal), // ea
|
||||
op(xba, IMP, Normal), // eb
|
||||
op(cpx, ABS, Normal), // ec
|
||||
op(sbc, ABS, Normal), // ed
|
||||
op(inc, ABS, Normal), // ee
|
||||
op(sbc, ABL, Normal), // ef
|
||||
op(beq, REL, Branch), // f0
|
||||
op(sbc, INY, Normal), // f1
|
||||
op(sbc, INZ, Normal), // f2
|
||||
op(sbc, INS, Normal), // f3
|
||||
op(pea, IMMS, Normal), // f4
|
||||
op(sbc, ZPX, Normal), // f5
|
||||
op(inc, ZPX, Normal), // f6
|
||||
op(sbc, INLY, Normal), // f7
|
||||
op(sed, IMP, Normal), // f8
|
||||
op(sbc, ABY, Normal), // f9
|
||||
op(plx, IMP, Normal), // fa
|
||||
op(xce, IMP, Normal), // fb
|
||||
op(jsr, AIX, Call), // fc
|
||||
op(sbc, ABX, Normal), // fd
|
||||
op(inc, ABX, Normal), // fe
|
||||
op(sbc, ABLX, Normal), // ff
|
||||
};
|
||||
|
||||
#undef op
|
||||
|
||||
struct AddressSize {
|
||||
Addressing mode;
|
||||
int length;
|
||||
};
|
||||
|
||||
static const AddressSize addressSizes[] = {
|
||||
{IMP, 1},
|
||||
{IMM, 2},
|
||||
{IMMM, 3},
|
||||
{IMMX, 3},
|
||||
{IMMS, 3},
|
||||
{ABS, 3},
|
||||
{ABL, 4},
|
||||
{ABX, 3},
|
||||
{ABY, 3},
|
||||
{ABLX, 4},
|
||||
{AIX, 3},
|
||||
{ZP, 2},
|
||||
{ZPX, 2},
|
||||
{ZPY, 2},
|
||||
{ZPS, 2},
|
||||
{IND, 3},
|
||||
{INZ, 2},
|
||||
{INL, 2},
|
||||
{INX, 2},
|
||||
{INY, 2},
|
||||
{INLY, 2},
|
||||
{INS, 2},
|
||||
{REL, 2},
|
||||
{RELL, 3},
|
||||
{BANK, 3},
|
||||
{DB, 1},
|
||||
{DW, 2},
|
||||
{DD, 4},
|
||||
};
|
||||
|
||||
#define numAddressSizes (sizeof(addressSizes) / sizeof(addressSizes[0]))
|
336
src/disasm.cc
336
src/disasm.cc
@ -1,10 +1,20 @@
|
||||
/** @copyright 2020 Sean Kasun */
|
||||
|
||||
#include "disasm.h"
|
||||
#include "65816.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <stack>
|
||||
|
||||
Disassembler::Disassembler(std::shared_ptr<Fingerprints> prints) : fingerprints(prints) { }
|
||||
static std::map<Addressing, int> sizes;
|
||||
|
||||
Disassembler::Disassembler(std::shared_ptr<Fingerprints> prints,
|
||||
std::map<uint32_t, std::string> symbols)
|
||||
: symbols(symbols), fingerprints(prints) {
|
||||
for (int i = 0; i < numAddressSizes; i++) {
|
||||
sizes[addressSizes[i].mode] = addressSizes[i].length;
|
||||
}
|
||||
}
|
||||
|
||||
bool Disassembler::disassemble(std::vector<Segment> segments,
|
||||
std::vector<Entry> entries) {
|
||||
@ -29,7 +39,7 @@ bool Disassembler::disassemble(std::vector<Segment> segments,
|
||||
std::cerr << "Failed to open '" << fname << "' for writing" << std::endl;
|
||||
return false;
|
||||
}
|
||||
f << "Section $" << std::ios::hex << segment.segnum << " "
|
||||
f << "Section $" << hex(segment.segnum, Value) << " "
|
||||
<< segment.name << std::endl;
|
||||
if (!decode(segment.mapped, segment.mapped + segment.length)) {
|
||||
std::cerr << "Disassembly failed" << std::endl;
|
||||
@ -62,9 +72,9 @@ bool Disassembler::trace(const Entry &start) {
|
||||
int8_t len = 0;
|
||||
auto fstart = ptr->tell();
|
||||
do {
|
||||
node = node->map.value(ptr->r8(), nullptr);
|
||||
node = node->map[ptr->r8()];
|
||||
len++;
|
||||
if (node != nullptr && !node->name.isEmpty()) {
|
||||
if (node != nullptr && !node->name.empty()) {
|
||||
if (inst == nullptr) {
|
||||
inst = std::make_shared<Inst>();
|
||||
inst->type = Special;
|
||||
@ -86,7 +96,7 @@ bool Disassembler::trace(const Entry &start) {
|
||||
if (i) {
|
||||
inst->name += ", ";
|
||||
}
|
||||
inst->name += hex2(ptr->r8());
|
||||
inst->name += hex(ptr->r8(), Value);
|
||||
}
|
||||
inst->name += "}";
|
||||
inst->length += numDB;
|
||||
@ -97,18 +107,20 @@ bool Disassembler::trace(const Entry &start) {
|
||||
}
|
||||
map[addr] = inst;
|
||||
if (inst->type == Jump || inst->type == Branch || inst->type == Call) {
|
||||
auto target = target(inst, resolver);
|
||||
if (target > 0 && !labels.contains(target)) {
|
||||
workList.push({state.flags, target});
|
||||
labels.insert(target, target);
|
||||
if (inst->operType == Opr::Imm || inst->operType == Opr::Abs) {
|
||||
if (valid(inst->oper) && labels.find(inst->oper) == labels.end()) {
|
||||
workList.push({state.flags, inst->oper});
|
||||
labels.insert(std::pair<uint32_t, uint32_t>(inst->oper,
|
||||
inst->oper));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inst->type == Jump || inst->type == Branch ||
|
||||
inst->type == Return) {
|
||||
branches.insert(state.org, addr);
|
||||
branches.insert(std::pair<uint32_t, uint32_t>(state.org, addr));
|
||||
}
|
||||
if (inst->type == Invalid) {
|
||||
branches.insert(addr, addr);
|
||||
branches.insert(std::pair<uint32_t, uint32_t>(addr, addr));
|
||||
}
|
||||
} while (inst->type != Return && inst->type != Jump &&
|
||||
inst->type != Invalid);
|
||||
@ -116,6 +128,66 @@ bool Disassembler::trace(const Entry &start) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Disassembler::basicBlocks() {
|
||||
// always starts at a label
|
||||
auto address = labels.lower_bound(0)->first;
|
||||
auto block = getBlock(address);
|
||||
auto done = false;
|
||||
while (!done) {
|
||||
auto label = labels.upper_bound(address);
|
||||
auto branch = branches.upper_bound(address);
|
||||
if (label != labels.end() && (branch == branches.end() ||
|
||||
label->second < branch->second)) {
|
||||
// label was earliest
|
||||
address = label->second;
|
||||
block->length = address - block->address;
|
||||
auto next = getBlock(address);
|
||||
next->preds.append(block);
|
||||
block->succs.append(next);
|
||||
block = next;
|
||||
} else if (branch != branches.end() && (label == labels.end() ||
|
||||
branch->second <= label->second)) {
|
||||
// branch was earliest (or equal)
|
||||
auto b = map[branch->second];
|
||||
block->branchLen = b->length;
|
||||
block->length = branch->first - block->address;
|
||||
if (b->type != Return && b->type != Invalid) {
|
||||
// branch has a destination
|
||||
if (b->operType == Opr::Imm || b->operType == Opr::Abs) {
|
||||
if (valid(b->oper)) {
|
||||
auto next = getBlock(b->oper);
|
||||
next->preds.append(block);
|
||||
block->succs.append(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (b->type == Jump || b->type == Return || b->type == Invalid) {
|
||||
// branch doesn't continue
|
||||
auto next = labels.upper_bound(branch->second);
|
||||
if (next == labels.end()) {
|
||||
done = true;
|
||||
} else {
|
||||
address = next->second;
|
||||
block = getBlock(address);
|
||||
}
|
||||
} else {
|
||||
// branch continues
|
||||
auto next = getBlock(branch->first);
|
||||
next->preds.append(block);
|
||||
block->succs.append(next);
|
||||
block = next;
|
||||
address = block->address;
|
||||
}
|
||||
} else {
|
||||
// out of labels and branches, we screwed up
|
||||
block->length = map.lastKey() + map.last()->length - block->address;
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
std::sort(blocks.begin(), blocks.end(), compareBlocks);
|
||||
return true;
|
||||
}
|
||||
|
||||
Handle Disassembler::getAddress(uint32_t address) {
|
||||
for (auto &s : segments) {
|
||||
if (address >= s.mapped && address < s.mapped + s.length) {
|
||||
@ -125,3 +197,245 @@ Handle Disassembler::getAddress(uint32_t address) {
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Disassembler::valid(uint32_t address) {
|
||||
for (auto &s : segments) {
|
||||
if (address >= s.mapped && address < s.mapped + s.length) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<Inst> Disassembler::decodeInst(Handle f, Entry *entry) {
|
||||
auto inst = std::make_shared<Inst>();
|
||||
auto opcode = f->r8();
|
||||
inst->name = opcodes[opcode].inst;
|
||||
inst->type = opcodes[opcode].type;
|
||||
auto mode = opcodes[opcode].addressing;
|
||||
inst->length = sizes[mode];
|
||||
if (mode == IMMM && (entry->flags & (IsEmu | IsM8))) {
|
||||
inst->length--;
|
||||
}
|
||||
if (mode == IMMX && (entry->flags & (IsEmu | IsX8))) {
|
||||
inst->length--;
|
||||
}
|
||||
entry->org += inst->length;
|
||||
uint32_t addr = entry->org;
|
||||
entry->flags &= IsFlags; // clear changed flags
|
||||
uint32_t oldFlags = entry->flags;
|
||||
switch (mode) {
|
||||
case IMP:
|
||||
inst->operType = Opr::None;
|
||||
break;
|
||||
case IMM:
|
||||
inst->oper = f->r8();
|
||||
inst->operType = Opr::Imm;
|
||||
if (opcode == 0xe2) {
|
||||
entry->flags |= inst->oper & IsFlags;
|
||||
} else if (opcode == 0xc2) {
|
||||
entry->flags &= ~inst->oper;
|
||||
}
|
||||
if ((entry->flags ^ oldFlags) & IsX8) {
|
||||
entry->flags |= IsX8Changed;
|
||||
}
|
||||
if ((entry->flags ^ oldFlags) & IsM8) {
|
||||
entry->flags |= IsM8Changed;
|
||||
}
|
||||
break;
|
||||
case IMMM:
|
||||
if (entry->flags & (IsEmu | IsM8)) {
|
||||
inst->oper = f->r8();
|
||||
} else {
|
||||
inst->oper = f->r16();
|
||||
}
|
||||
inst->operType = Opr::Imm;
|
||||
break;
|
||||
case IMMX:
|
||||
if (entry->flags & (IsEmu | IsX8)) {
|
||||
inst->oper = f->r8();
|
||||
} else {
|
||||
inst->oper = f->r16();
|
||||
}
|
||||
inst->operType = Opr::Imm;
|
||||
break;
|
||||
case IMMS:
|
||||
inst->oper = f->r16();
|
||||
inst->operType = Opr::Imm;
|
||||
break;
|
||||
case ABS:
|
||||
inst->oper = f->r16();
|
||||
if (inst->type == InsType::Jump || inst->type == InsType::Call) {
|
||||
inst->oper |= entry->org & 0xff0000; // K
|
||||
inst->operType = Opr::Abs;
|
||||
} else {
|
||||
inst->operType = Opr::AbsB;
|
||||
}
|
||||
break;
|
||||
case ABL:
|
||||
inst->oper = f->r24();
|
||||
inst->operType = Opr::Abs;
|
||||
break;
|
||||
case ABX:
|
||||
inst->oper = f->r16();
|
||||
if (inst->type == InsType::Jump || inst->type == InsType::Call) {
|
||||
inst->oper |= entry->org & 0xff0000; // K
|
||||
inst->operType = Opr::AbsX;
|
||||
} else {
|
||||
inst->operType = Opr::AbsXB;
|
||||
}
|
||||
break;
|
||||
case ABY:
|
||||
inst->oper = f->r16();
|
||||
if (inst->type == InsType::Jump || inst->type == InsType::Call) {
|
||||
inst->oper |= entry->org & 0xff0000; // K
|
||||
inst->operType = Opr::AbsY;
|
||||
} else {
|
||||
inst->operType = Opr::AbsYB;
|
||||
}
|
||||
break;
|
||||
case ABLX:
|
||||
inst->oper = f->r24();
|
||||
inst->operType = Opr::AbsX;
|
||||
break;
|
||||
case AIX:
|
||||
inst->oper = f->r16();
|
||||
if (inst->type == InsType::Jump || inst->type == InsType::Call) {
|
||||
inst->oper |= entry->org & 0xff0000; // K
|
||||
inst->operType = Opr::IndX;
|
||||
} else {
|
||||
inst->operType = Opr::IndXB;
|
||||
}
|
||||
break;
|
||||
case ZP:
|
||||
inst->oper = f->r8();
|
||||
inst->operType = Opr::AbsD;
|
||||
break;
|
||||
case ZPX:
|
||||
inst->oper = f->r8();
|
||||
inst->operType = Opr::AbsXD;
|
||||
break;
|
||||
case ZPY:
|
||||
inst->oper = f->r8();
|
||||
inst->operType = Opr::AbsYD;
|
||||
break;
|
||||
case ZPS:
|
||||
inst->oper = f->r8();
|
||||
inst->operType = Opr::AbsS;
|
||||
break;
|
||||
case IND:
|
||||
inst->oper = f->r16();
|
||||
if (inst->type == InsType::Jump || inst->type == InsType::Call) {
|
||||
inst->oper |= entry->org & 0xff0000; // K
|
||||
inst->operType = Opr::Ind;
|
||||
} else {
|
||||
inst->operType = Opr::IndB;
|
||||
}
|
||||
break;
|
||||
case INZ:
|
||||
inst->oper = f->r8();
|
||||
inst->operType = Opr::IndD;
|
||||
break;
|
||||
case INL:
|
||||
inst->oper = f->r8();
|
||||
inst->operType = Opr::IndL;
|
||||
break;
|
||||
case INX:
|
||||
inst->oper = f->r8();
|
||||
inst->operType = Opr::IndX;
|
||||
break;
|
||||
case INY:
|
||||
inst->oper = f->r8();
|
||||
inst->operType = Opr::IndY;
|
||||
break;
|
||||
case INLY:
|
||||
inst->oper = f->r8();
|
||||
inst->operType = Opr::IndLY;
|
||||
break;
|
||||
case INS:
|
||||
inst->oper = f->r8();
|
||||
inst->operType = Opr::IndS;
|
||||
break;
|
||||
case REL:
|
||||
inst->oper = addr + static_cast<int8_t>(f->r8());
|
||||
inst->operType = Opr::Abs;
|
||||
break;
|
||||
case RELL:
|
||||
inst->oper = addr + static_cast<int16_t>(f->r16());
|
||||
inst->operType = Opr::Abs;
|
||||
break;
|
||||
case BANK:
|
||||
inst->oper = f->r16();
|
||||
inst->operType = Opr::Bank;
|
||||
break;
|
||||
case DB:
|
||||
inst->oper = opcode;
|
||||
inst->operType = Opr::Abs;
|
||||
break;
|
||||
case DW:
|
||||
inst->oper = opcode | (f->r8() << 8);
|
||||
inst->operType = Opr::Abs;
|
||||
break;
|
||||
case DD:
|
||||
inst->oper = opcode | (f->r24() << 8);
|
||||
inst->operType = Opr::Abs;
|
||||
break;
|
||||
}
|
||||
if (opcode == 0x18) {
|
||||
if (f->r8() == 0xfb) { // clc xce
|
||||
entry->flags &= 0xffffff ^ IsEmu;
|
||||
}
|
||||
f->skip(-1);
|
||||
}
|
||||
if (opcode == 0x38) {
|
||||
if (f->r8() == 0xfb) { // sec xce
|
||||
entry->flags |= IsEmu;
|
||||
}
|
||||
f->skip(-1);
|
||||
}
|
||||
if ((entry->flags ^ oldFlags) & IsEmu) {
|
||||
entry->flags |= IsEmuChanged;
|
||||
}
|
||||
inst->flags = entry->flags;
|
||||
return inst;
|
||||
}
|
||||
|
||||
std::string Disassembler::hex(uint32_t val, HexType type) {
|
||||
std::string ret;
|
||||
int width = 0;
|
||||
if (type == HexType::Address) {
|
||||
ret = symbols[val];
|
||||
}
|
||||
if (ret.empty()) {
|
||||
if ((val & ~0xff) == ~0xff) {
|
||||
ret += "$-";
|
||||
val = ~val + 1;
|
||||
width = 2;
|
||||
} else if ((val & ~0xff) == 0) {
|
||||
ret += "$";
|
||||
width = 2;
|
||||
} else if ((val & ~0xffff) == ~0xffff) {
|
||||
ret += "$-";
|
||||
val = ~val + 1;
|
||||
width = 4;
|
||||
} else if ((val & ~0xffff) == 0) {
|
||||
ret += "$";
|
||||
width = 4;
|
||||
} else if (val & 0x80000000) {
|
||||
ret += "$-";
|
||||
width = 8;
|
||||
} else {
|
||||
ret += "$";
|
||||
width = 8;
|
||||
}
|
||||
for (int i = 0; i < width; i++) {
|
||||
uint8_t ch = val >> (width - (i + 1)) * 4;
|
||||
if (ch < 10) {
|
||||
ret += static_cast<char>(ch + '0');
|
||||
} else {
|
||||
ret += static_cast<char>(ch - 10 + 'a');
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
29
src/disasm.h
29
src/disasm.h
@ -26,23 +26,44 @@ enum InsType : uint16_t {
|
||||
Invalid = 0xff,
|
||||
};
|
||||
|
||||
enum HexType {
|
||||
Value = 0x01,
|
||||
Address = 0x02,
|
||||
};
|
||||
|
||||
enum class Opr {
|
||||
None = 0, Imm, Abs, AbsB, AbsD, AbsX, AbsXB, AbsXD, AbsY, AbsYB, AbsYD, AbsS,
|
||||
Ind, IndB, IndD, IndX, IndXB, IndY, IndL, IndLY, IndS, Bank,
|
||||
};
|
||||
|
||||
struct Inst {
|
||||
std::string name;
|
||||
InsType type;
|
||||
uint16_t length;
|
||||
Opr operType;
|
||||
uint32_t oper;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
class Disassembler {
|
||||
public:
|
||||
Disassembler(std::shared_ptr<Fingerprints> prints);
|
||||
bool disassemble(std::vector<Segment> segments, std::vector<Entry> entries);
|
||||
Disassembler(std::shared_ptr<Fingerprints> prints,
|
||||
std::map<uint32_t, std::string> symbols);
|
||||
bool disassemble(std::vector<struct Segment> segments,
|
||||
std::vector<struct Entry> entries);
|
||||
|
||||
private:
|
||||
bool trace(const Entry &start);
|
||||
bool trace(const struct Entry &start);
|
||||
bool basicBlocks();
|
||||
std::shared_ptr<Inst> decodeInst(Handle f, Entry *entry);
|
||||
Handle getAddress(uint32_t address);
|
||||
bool valid(uint32_t address);
|
||||
std::string hex(uint32_t value, HexType type);
|
||||
|
||||
std::map<uint32_t, std::string> symbols;
|
||||
std::map<uint32_t, uint32_t> labels;
|
||||
std::map<uint32_t, uint32_t> branches;
|
||||
std::vector<Segment> segments;
|
||||
std::vector<struct Segment> segments;
|
||||
std::shared_ptr<Fingerprints> fingerprints;
|
||||
std::map<uint32_t, std::shared_ptr<Inst>> map;
|
||||
};
|
||||
|
24
src/main.cc
24
src/main.cc
@ -130,27 +130,33 @@ int main(int argc, char **argv) {
|
||||
|
||||
auto prints = std::make_shared<Fingerprints>();
|
||||
for (auto s : api.symbols) {
|
||||
if (s->kind == symbol::isFunction) {
|
||||
auto f = std::static_pointer_cast<symbol::Function>(s);
|
||||
if (s.second->kind == symbol::isFunction) {
|
||||
auto f = std::static_pointer_cast<symbol::Function>(s.second);
|
||||
if (f->signature.size() >= 2) {
|
||||
if (f->signature[0] >= 0) { // tool
|
||||
// ldx tool, jsl e1/0000
|
||||
std::vector<uint8_t> sig = { 0xa2, f->signature[0], f->signature[1],
|
||||
std::vector<uint8_t> sig = { 0xa2, 0x00, 0x00,
|
||||
0x22, 0x00, 0x00, 0xe1 };
|
||||
sig[1] = f->signature[0];
|
||||
sig[2] = f->signature[1];
|
||||
prints->add(sig, f->name);
|
||||
} else if (f->signature[0] == -1) { // p16/gsos
|
||||
// jsl e1/00a8
|
||||
std::vector<uint8_t> sig = { 0x22, 0xa8, 0x00, 0xe1,
|
||||
f->signature[2] & 0xff, f->signature[2] >> 8 };
|
||||
std::vector<uint8_t> sig = { 0x22, 0xa8, 0x00, 0xe1, 0x00, 0x00 };
|
||||
sig[4] = f->signature[2] & 0xff;
|
||||
sig[5] = f->signature[2] >> 8;
|
||||
prints->add(sig, f->name, f->signature[1] & 0xff);
|
||||
} else if (f->signature[0] == -2) { // p8
|
||||
// jsr bf00
|
||||
std::vector<uint8_t> sig = { 0x20, 0x00, 0xbf, f->signature[2] };
|
||||
std::vector<uint8_t> sig = { 0x20, 0x00, 0xbf, 0x00 };
|
||||
sig[3] = f->signature[2];
|
||||
prints->add(sig, f->name, f->signature[1] & 0xff);
|
||||
} else if (f->signature[0] == -3) { // smartport
|
||||
// jsr c50d
|
||||
std::vector<uint8_t> sig5 = { 0x20, 0x0d, 0xc5, f->signature[2] };
|
||||
std::vector<uint8_t> sig7 = { 0x20, 0x0d, 0xc7, f->signature[2] };
|
||||
std::vector<uint8_t> sig5 = { 0x20, 0x0d, 0xc5, 0x00 };
|
||||
std::vector<uint8_t> sig7 = { 0x20, 0x0d, 0xc7, 0x00 };
|
||||
sig5[3] = f->signature[2];
|
||||
sig7[3] = f->signature[2];
|
||||
prints->add(sig5, f->name, f->signature[1]);
|
||||
prints->add(sig7, f->name, f->signature[1]);
|
||||
}
|
||||
@ -158,6 +164,6 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
Disassembler d(prints);
|
||||
Disassembler d(prints, map.getSymbols());
|
||||
d.disassemble(segments, map.getEntries());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user