Major fixes to disassembler
This commit is contained in:
parent
570b87dfd5
commit
e75ed40ce0
|
@ -8,14 +8,17 @@ Disassembler::Disassembler(QByteArray memimage)
|
||||||
{
|
{
|
||||||
m_memimage = memimage, makeOpcodeTable();
|
m_memimage = memimage, makeOpcodeTable();
|
||||||
m_memusagemap.clearData();
|
m_memusagemap.clearData();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QList<DisassembledItem> Disassembler::disassemble(quint16 from, quint16 to,
|
QList<DisassembledItem> Disassembler::disassemble(quint16 from, quint16 to,
|
||||||
QList<quint16> entryPoints,
|
QList<quint16> entryPoints,
|
||||||
bool processRecursively) {
|
bool processRecursively) {
|
||||||
QList<DisassembledItem> retval;
|
QList<DisassembledItem> retval;
|
||||||
qDebug() << "Disassemble: From"<<uint16ToHex(from)<<"to"<<uint16ToHex(to);
|
qDebug() << "\n\n*****************\n\nDisassemble: From"<<uint16ToHex(from)<<"to"<<uint16ToHex(to);
|
||||||
//#define OLDDISSEM
|
//#define OLDDISSEM
|
||||||
|
|
||||||
#ifdef OLDDISSEM
|
#ifdef OLDDISSEM
|
||||||
for (int idx = from; idx <= to; )
|
for (int idx = from; idx <= to; )
|
||||||
{
|
{
|
||||||
|
@ -34,10 +37,11 @@ QList<DisassembledItem> Disassembler::disassemble(quint16 from, quint16 to,
|
||||||
|
|
||||||
bool stopping = false;
|
bool stopping = false;
|
||||||
quint16 next = from;
|
quint16 next = from;
|
||||||
if (entryPoints.count())
|
while (entryPoints.count())
|
||||||
{
|
{
|
||||||
next = entryPoints.takeFirst();
|
next = entryPoints.takeFirst();
|
||||||
m_jumps.append(entryPoints);
|
//m_jumps.append(entryPoints);
|
||||||
|
m_stack.push(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!stopping)
|
while (!stopping)
|
||||||
|
@ -59,19 +63,31 @@ QList<DisassembledItem> Disassembler::disassemble(quint16 from, quint16 to,
|
||||||
if (item.isBranch())
|
if (item.isBranch())
|
||||||
{
|
{
|
||||||
qDebug() << "Is Branch";
|
qDebug() << "Is Branch";
|
||||||
if (!m_jumps.contains(item.targetAddress()))
|
m_stack.push(item.targetAddress());
|
||||||
{
|
// if (!m_jumps.contains(item.targetAddress()))
|
||||||
m_jumps.append(item.targetAddress());
|
// {
|
||||||
}
|
// m_jumps.append(item.targetAddress());
|
||||||
|
// qDebug() << "Appending branch" << uint16ToHex(item.targetAddress()) << "to jump table";
|
||||||
|
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.isJsr() && !item.canNotFollow())
|
if (item.isJsr() && !item.canNotFollow())
|
||||||
{
|
{
|
||||||
if (item.targetAddress() <= to) //TODO: Remove this to not limit disassembly to program range
|
if (item.targetAddress() <= to) //TODO: Remove this to not limit disassembly to program range
|
||||||
if (!m_jumps.contains(item.targetAddress()))
|
{
|
||||||
|
if (m_stack.push(item.targetAddress()))
|
||||||
|
//if (!m_jumps.contains(item.targetAddress()))
|
||||||
{
|
{
|
||||||
m_jumps.append(item.targetAddress());
|
qDebug() << "Appending" << uint16ToHex(item.targetAddress()) << "to jump table";
|
||||||
|
|
||||||
|
//m_jumps.append(item.targetAddress());
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug() << "Not adding" << uint16ToHex(item.targetAddress()) << "to jump table";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next <= to) //TODO: Remove this to not limit disassembly to program range
|
if (next <= to) //TODO: Remove this to not limit disassembly to program range
|
||||||
|
@ -99,19 +115,21 @@ QList<DisassembledItem> Disassembler::disassemble(quint16 from, quint16 to,
|
||||||
m_memusagemap.merge(memuse);
|
m_memusagemap.merge(memuse);
|
||||||
|
|
||||||
if (processRecursively)
|
if (processRecursively)
|
||||||
while (m_jumps.size())
|
//while (m_jumps.size())
|
||||||
{
|
while (!m_stack.isEmpty())
|
||||||
quint16 num = m_jumps.takeFirst();
|
|
||||||
if (!m_memusagemap[num].testFlag(Operation))
|
|
||||||
{
|
{
|
||||||
if (num >= from && num <= to) // TODO: remove this to not limit disassembly to program range
|
// quint16 num = m_jumps.takeFirst();
|
||||||
|
quint16 num = m_stack.pop();
|
||||||
|
if (!m_memusagemap[num].testFlag(Operation))
|
||||||
{
|
{
|
||||||
qDebug() << "Calling recursively to"<<uint16ToHex(num);
|
if (num >= from && num <= to) // TODO: remove this to not limit disassembly to program range
|
||||||
retval.append(disassemble(from,to,QList<quint16>() << num,false));
|
{
|
||||||
qDebug() << "Return from recursive call.";
|
qDebug() << "Calling recursively to"<<uint16ToHex(num);
|
||||||
|
retval.append(disassemble(from,to,QList<quint16>() << num,false));
|
||||||
|
qDebug() << "Return from recursive call.";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
qSort(retval);
|
qSort(retval);
|
||||||
|
@ -173,7 +191,11 @@ bool Disassembler::disassembleOp(quint16 address, DisassembledItem &retval, Memo
|
||||||
if (op.numArgs() == 1)
|
if (op.numArgs() == 1)
|
||||||
argval = (quint8) hexValues[1];
|
argval = (quint8) hexValues[1];
|
||||||
else if (op.numArgs() == 2)
|
else if (op.numArgs() == 2)
|
||||||
argval = (quint8) hexValues[1] + ((quint8) hexValues[2] * 256);
|
{
|
||||||
|
argval = makeWord(hexValues[1],hexValues[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (int idx = 0; idx < hexValues.length(); idx++) {
|
for (int idx = 0; idx < hexValues.length(); idx++) {
|
||||||
hexValueString.append(QString("%1 ").arg((quint8) hexValues[idx],2,16,QChar('0')));
|
hexValueString.append(QString("%1 ").arg((quint8) hexValues[idx],2,16,QChar('0')));
|
||||||
|
@ -184,109 +206,112 @@ bool Disassembler::disassembleOp(quint16 address, DisassembledItem &retval, Memo
|
||||||
|
|
||||||
// Disassemble instruction
|
// Disassemble instruction
|
||||||
switch (op.addressMode()) {
|
switch (op.addressMode()) {
|
||||||
case AM_InvalidOp: {
|
case AM_InvalidOp: {
|
||||||
disassemblyLine = op.mnemonic();
|
disassemblyLine = op.mnemonic();
|
||||||
retval.setIsInvalidOp(true);
|
retval.setIsInvalidOp(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AM_Absolute:{
|
case AM_Absolute:{
|
||||||
disassemblyLine = QString("%1 _ARG16_").arg(op.mnemonic());
|
disassemblyLine = QString("%1 _ARG16_").arg(op.mnemonic());
|
||||||
retval.setRawArgument(argval);
|
retval.setRawArgument(argval);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AM_AbsoluteIndexedIndirect:{
|
case AM_AbsoluteIndexedIndirect:{
|
||||||
disassemblyLine = QString("%1 (_ARG16_,x)").arg(op.mnemonic());
|
disassemblyLine = QString("%1 (_ARG16_,x)").arg(op.mnemonic());
|
||||||
retval.setRawArgument(argval);
|
retval.setRawArgument(argval);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AM_AbsoluteIndexedWithX:{
|
case AM_AbsoluteIndexedWithX:{
|
||||||
disassemblyLine = QString("%1 _ARG16_,x").arg(op.mnemonic());
|
disassemblyLine = QString("%1 _ARG16_,x").arg(op.mnemonic());
|
||||||
retval.setRawArgument(argval);
|
retval.setRawArgument(argval);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AM_AbsoluteIndexedWithY:{
|
case AM_AbsoluteIndexedWithY:{
|
||||||
disassemblyLine = QString("%1 _ARG16_,y").arg(op.mnemonic());
|
disassemblyLine = QString("%1 _ARG16_,y").arg(op.mnemonic());
|
||||||
retval.setRawArgument(argval);
|
retval.setRawArgument(argval);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AM_AbsoluteIndirect:{
|
case AM_AbsoluteIndirect:{
|
||||||
disassemblyLine = QString("%1 (_ARG16_)").arg(op.mnemonic());
|
disassemblyLine = QString("%1 (_ARG16_)").arg(op.mnemonic());
|
||||||
retval.setRawArgument(argval);
|
retval.setRawArgument(argval);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AM_Immediate:{
|
case AM_Immediate:{
|
||||||
disassemblyLine = QString("%1 #%2").arg(op.mnemonic()).arg((quint8) hexValues[1],2,16,QChar('0')).toUpper();
|
disassemblyLine = QString("%1 #%2").arg(op.mnemonic()).arg((quint8) hexValues[1],2,16,QChar('0')).toUpper();
|
||||||
retval.setRawArgument(argval);
|
retval.setRawArgument(argval);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AM_Implied:{
|
case AM_Implied:{
|
||||||
disassemblyLine = op.mnemonic();
|
disassemblyLine = op.mnemonic();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AM_Accumulator:{
|
case AM_Accumulator:{
|
||||||
disassemblyLine = op.mnemonic();
|
disassemblyLine = op.mnemonic();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AM_ProgramCounterRelative:{
|
case AM_ProgramCounterRelative:{
|
||||||
qint8 offset = (qint8) hexValues[1];
|
qint8 offset = (qint8) hexValues[1];
|
||||||
quint16 offsetAddress = address+2+offset;
|
quint16 offsetAddress = address+2+offset;
|
||||||
|
|
||||||
retval.setTargetAddress(offsetAddress);
|
retval.setTargetAddress(offsetAddress);
|
||||||
|
|
||||||
disassemblyLine = QString("%1 _ARG16_ {%2%3}").arg(op.mnemonic())
|
disassemblyLine = QString("%1 _ARG16_ {%2%3}").arg(op.mnemonic())
|
||||||
.arg((offset<0)?"-":"+")
|
.arg((offset<0)?"-":"+")
|
||||||
.arg(abs(offset));
|
.arg(abs(offset));
|
||||||
retval.setRawArgument(offsetAddress);
|
retval.setRawArgument(offsetAddress);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AM_ZeroPage:{
|
case AM_ZeroPage:{
|
||||||
disassemblyLine = QString("%1 _ARG8_").arg(op.mnemonic());
|
disassemblyLine = QString("%1 _ARG8_").arg(op.mnemonic());
|
||||||
retval.setRawArgument(argval);
|
retval.setRawArgument(argval);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AM_ZeroPageIndirectIndexedWithY:{
|
case AM_ZeroPageIndirectIndexedWithY:{
|
||||||
disassemblyLine = QString("%1 (_ARG8_),Y").arg(op.mnemonic());
|
disassemblyLine = QString("%1 (_ARG8_),Y").arg(op.mnemonic());
|
||||||
retval.setRawArgument(argval);
|
retval.setRawArgument(argval);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AM_ZeroPageIndexedIndirect:{
|
case AM_ZeroPageIndexedIndirect:{
|
||||||
disassemblyLine = QString("%1 (_ARG8_,x)").arg(op.mnemonic());
|
disassemblyLine = QString("%1 (_ARG8_,x)").arg(op.mnemonic());
|
||||||
retval.setRawArgument(argval);
|
retval.setRawArgument(argval);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AM_ZeroPageIndexedWithX:{
|
case AM_ZeroPageIndexedWithX:{
|
||||||
disassemblyLine = QString("%1 _ARG8_,x").arg(op.mnemonic());
|
disassemblyLine = QString("%1 _ARG8_,x").arg(op.mnemonic());
|
||||||
retval.setRawArgument(argval);
|
retval.setRawArgument(argval);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AM_ZeroPageIndexedWithY:{
|
case AM_ZeroPageIndexedWithY:{
|
||||||
disassemblyLine = QString("%1 _ARG8_,y").arg(op.mnemonic());
|
disassemblyLine = QString("%1 _ARG8_,y").arg(op.mnemonic());
|
||||||
retval.setRawArgument(argval);
|
retval.setRawArgument(argval);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AM_ZeroPageIndirect:{
|
case AM_ZeroPageIndirect:{
|
||||||
disassemblyLine = QString("%1 (_ARG8_)").arg(op.mnemonic());
|
disassemblyLine = QString("%1 (_ARG8_)").arg(op.mnemonic());
|
||||||
retval.setRawArgument(argval);
|
retval.setRawArgument(argval);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:{
|
default:{
|
||||||
disassemblyLine = op.mnemonic();
|
disassemblyLine = op.mnemonic();
|
||||||
retval.setIsInvalidOp(true);
|
retval.setIsInvalidOp(true);
|
||||||
qDebug() << "Unhandled Address Mode: " << op.addressMode();
|
qDebug() << "Unhandled Address Mode: " << op.addressMode();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opcode == 0x20 || opcode == 0x4c) {
|
if (opcode == 0x20 || opcode == 0x4c) {
|
||||||
retval.setTargetAddress(hexValues[2]*256 + hexValues[1]);
|
retval.setTargetAddress(makeWord(hexValues[1],hexValues[2]));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opcode == 0x4c)
|
if (opcode == 0x4c)
|
||||||
{
|
{
|
||||||
qDebug() << "JMP: Setting next flow address to"<<uint16ToHex(hexValues[2]*256 + hexValues[1]);
|
qDebug() << "JMP: Adding flow address "
|
||||||
retval.setNextFlowAddress(hexValues[2]*256 + hexValues[1]);
|
<< uint16ToHex(makeWord(hexValues[1],hexValues[2])) << "to jump table";
|
||||||
}
|
|
||||||
|
|
||||||
|
m_stack.push(argval);
|
||||||
|
retval.setCanNotFollow(true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
retval.setAddress(address);
|
retval.setAddress(address);
|
||||||
retval.setDisassembledString(disassemblyLine.toUpper());
|
retval.setDisassembledString(disassemblyLine.toUpper());
|
||||||
|
@ -865,30 +890,31 @@ AssyInstruction::AssyInstruction(quint8 opcode, QString mnemonic, AddressMode am
|
||||||
|
|
||||||
quint8 AssyInstruction::numArgs() {
|
quint8 AssyInstruction::numArgs() {
|
||||||
switch (m_addressMode) {
|
switch (m_addressMode) {
|
||||||
case AM_Absolute:
|
case AM_Absolute:
|
||||||
case AM_AbsoluteIndexedIndirect:
|
case AM_AbsoluteIndexedIndirect:
|
||||||
case AM_AbsoluteIndexedWithX:
|
case AM_AbsoluteIndexedWithX:
|
||||||
case AM_AbsoluteIndexedWithY:
|
case AM_AbsoluteIndexedWithY:
|
||||||
case AM_AbsoluteIndirect:
|
case AM_AbsoluteIndirect:
|
||||||
return 2;
|
return 2;
|
||||||
case AM_ProgramCounterRelative:
|
case AM_ProgramCounterRelative:
|
||||||
case AM_ZeroPage:
|
case AM_ZeroPage:
|
||||||
case AM_ZeroPageIndirectIndexedWithY:
|
case AM_ZeroPageIndirectIndexedWithY:
|
||||||
case AM_ZeroPageIndexedIndirect:
|
case AM_ZeroPageIndexedIndirect:
|
||||||
case AM_ZeroPageIndexedWithX:
|
case AM_ZeroPageIndexedWithX:
|
||||||
case AM_ZeroPageIndexedWithY:
|
case AM_ZeroPageIndexedWithY:
|
||||||
case AM_ZeroPageIndirect:
|
case AM_ZeroPageIndirect:
|
||||||
case AM_Immediate:
|
case AM_Immediate:
|
||||||
return 1;
|
return 1;
|
||||||
case AM_InvalidOp:
|
case AM_InvalidOp:
|
||||||
case AM_Implied:
|
case AM_Implied:
|
||||||
case AM_Accumulator:
|
case AM_Accumulator:
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DisassembledItem::DisassembledItem(AssyInstruction instr) {
|
DisassembledItem::DisassembledItem(AssyInstruction instr) {
|
||||||
|
m_canNotFollow = false;
|
||||||
setInstruction(instr);
|
setInstruction(instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QStack>
|
||||||
|
|
||||||
enum AddressMode {
|
enum AddressMode {
|
||||||
AM_InvalidOp,
|
AM_InvalidOp,
|
||||||
|
@ -29,6 +30,30 @@ enum AddressMode {
|
||||||
};
|
};
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class AddressStack
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AddressStack() { }
|
||||||
|
|
||||||
|
bool push(quint16 address, bool force = false) {
|
||||||
|
if (force || (!m_stack.contains(address)))
|
||||||
|
{
|
||||||
|
qDebug() << " PUSH: " << uint16ToHex(address);
|
||||||
|
m_stack.push(address);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEmpty() { return m_stack.isEmpty(); }
|
||||||
|
quint16 pop() { return m_stack.pop(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QStack<quint16> m_stack;
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct AssyInstruction {
|
struct AssyInstruction {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -93,7 +118,7 @@ public:
|
||||||
bool stopsProcessing() {
|
bool stopsProcessing() {
|
||||||
if (isReturn()) qDebug() << "Is Return";
|
if (isReturn()) qDebug() << "Is Return";
|
||||||
if (isInvalidOp()) qDebug() << "Is Invalid Op" << uint8ToHex(m_instruction.opcode());
|
if (isInvalidOp()) qDebug() << "Is Invalid Op" << uint8ToHex(m_instruction.opcode());
|
||||||
if (canNotFollow()) qDebug() << "Can not follow indirect jump";
|
if (canNotFollow()) qDebug() << "Not following jump";
|
||||||
if (isBreak()) qDebug() << "Is Break";
|
if (isBreak()) qDebug() << "Is Break";
|
||||||
return isBreak() || isInvalidOp() || isReturn() || canNotFollow(); }
|
return isBreak() || isInvalidOp() || isReturn() || canNotFollow(); }
|
||||||
|
|
||||||
|
@ -168,7 +193,7 @@ private:
|
||||||
QHash<quint8,AssyInstruction> m_opcodeinfo;
|
QHash<quint8,AssyInstruction> m_opcodeinfo;
|
||||||
QByteArray m_memimage;
|
QByteArray m_memimage;
|
||||||
|
|
||||||
QList<quint16> m_jumps;
|
AddressStack m_stack;
|
||||||
|
|
||||||
MemoryUsageMap m_memusagemap;
|
MemoryUsageMap m_memusagemap;
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ public slots:
|
||||||
protected:
|
protected:
|
||||||
QString makeTextStr(QByteArray data);
|
QString makeTextStr(QByteArray data);
|
||||||
QString makeHexStr(QByteArray data);
|
QString makeHexStr(QByteArray data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::TextHexDumpViewer *ui;
|
Ui::TextHexDumpViewer *ui;
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ void ViewerBase::setFile(GenericFile *file)
|
||||||
}
|
}
|
||||||
else if (dynamic_cast<TextFile*>(file))
|
else if (dynamic_cast<TextFile*>(file))
|
||||||
{
|
{
|
||||||
BinaryFile *bf = dynamic_cast<BinaryFile*>(file);
|
TextFile *bf = dynamic_cast<TextFile*>(file);
|
||||||
|
|
||||||
TextHexDumpViewer *thdv = new TextHexDumpViewer();
|
TextHexDumpViewer *thdv = new TextHexDumpViewer();
|
||||||
thdv->setFile(bf);
|
thdv->setFile(bf);
|
||||||
|
|
|
@ -69,7 +69,10 @@ inline QString uint32ToHex(quint32 val) {
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline quint16 makeWord(quint8 lo, quint8 hi)
|
||||||
|
{
|
||||||
|
return hi*256 + lo;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue