📄 deasm.cpp
字号:
/*-----------------------------------------------------------------------------
6502 Macroassembler and Simulator
Copyright (C) 1995-2003 Michal Kowalski
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-----------------------------------------------------------------------------*/
#include "StdAfx.h"
#include "Deasm.h"
extern C6502App theApp; // dost阷 do GetProcType() z CGlobal
CString CDeasm::DeasmInstr(const CmdInfo& ci, DeasmFmt flags)
{
CString str(_T(' '), 128), fmt(_T(' '), 128);
str.Empty();
UINT16 addr= ci.pc;
UINT8 cmd= ci.cmd;
UINT16 uLen= cmd == 0 ? 1 : mode_to_len[CodeToMode()[cmd]];
if (flags & DF_ADDRESS)
{
fmt.Format("%04X ",(int)addr);
str += fmt;
}
if (flags & DF_CODE_BYTES)
{
switch (uLen)
{
case 1:
fmt.Format("%02X ", int(cmd));
break;
case 2:
fmt.Format("%02X %02X ", int(cmd), int(ci.arg1));
break;
case 3:
fmt.Format("%02X %02X %02X ", int(cmd), int(ci.arg1), int(ci.arg2));
break;
default:
fmt.Empty();
ASSERT(FALSE);
}
str += fmt;
}
bool b6502= theApp.m_global.m_bProc6502 && !(flags & DF_65C02);
str += Mnemonic(cmd, b6502, !!(flags & DF_USE_BRK));
str += Argument(cmd, (CodeAdr)CodeToMode(b6502)[cmd], addr, ci.arg1, ci.arg2, flags & DF_LABELS, flags & DF_HELP);
return str;
}
CString CDeasm::DeasmInstr(const CContext& ctx, DeasmFmt flags, int& ptr)
{
ASSERT(ptr == -1 || ptr >= 0 && ptr <= 0xFFFF);
CString str(_T(' '), 128), fmt(_T(' '), 128);
str.Empty();
UINT16 addr= ptr >= 0 ? ptr : ctx.pc;
UINT8 cmd= ctx.mem[addr];
UINT16 uLen= cmd == 0 ? 1 : mode_to_len[CodeToMode()[cmd]];
if (flags & DF_ADDRESS)
{
fmt.Format("%04X ",(int)addr);
str += fmt;
}
if (flags & DF_CODE_BYTES)
{
switch (uLen)
{
case 1:
fmt.Format("%02X ", int(ctx.mem[addr]));
break;
case 2:
fmt.Format("%02X %02X ", int(ctx.mem[addr]), int(ctx.mem[addr + 1]));
break;
case 3:
fmt.Format("%02X %02X %02X ", int(ctx.mem[addr]), int(ctx.mem[addr + 1]), int(ctx.mem[addr + 2]));
break;
default:
fmt.Empty();
ASSERT(FALSE);
}
str += fmt;
}
bool b6502= theApp.m_global.m_bProc6502 && !(flags & DF_65C02);
str += Mnemonic(cmd, b6502);
str += Argument(cmd, (CodeAdr)CodeToMode(b6502)[cmd], addr, ctx.mem[addr+1], ctx.mem[addr+2], flags & DF_LABELS);
if (flags & DF_BRANCH_INFO)
{
bool sign= FALSE;
switch (CodeToCommand()[cmd])
{
case C_BRA:
sign = TRUE;
break;
case C_BPL:
if (!ctx.negative)
sign = TRUE;
break;
case C_BMI:
if (ctx.negative)
sign = TRUE;
break;
case C_BVC:
if (!ctx.overflow)
sign = TRUE;
break;
case C_BVS:
if (ctx.overflow)
sign = TRUE;
break;
case C_BCC:
if (!ctx.carry)
sign = TRUE;
break;
case C_BCS:
if (ctx.carry)
sign = TRUE;
break;
case C_BNE:
if (!ctx.zero)
sign = TRUE;
break;
case C_BEQ:
if (ctx.zero)
sign = TRUE;
break;
case C_BBS:
{
UINT8 zpg= ctx.mem[addr + 1];
int bit_no= (cmd >> 4) & 0x07;
if (ctx.mem[zpg] & UINT8(1 << bit_no))
sign = TRUE;
break;
}
case C_BBR:
{
UINT8 zpg= ctx.mem[addr + 1];
int bit_no= (cmd >> 4) & 0x07;
if (!(ctx.mem[zpg] & UINT8(1 << bit_no)))
sign = TRUE;
break;
}
}
if (sign)
str += " ->"; // oznaczenie aktywnego skoku
}
ptr = (addr + uLen) & 0xFFFF; // adr nast. instr.
return str;
}
CString CDeasm::Mnemonic(UINT8 code, bool bUse6502, bool bUseBrk/*= false*/)
{
ASSERT(CodeToCommand(bUse6502)[code] <= C_ILL && CodeToCommand(bUse6502)[code] >= 0);
TCHAR buf[16];
UINT8 cmd= CodeToCommand(bUse6502)[code];
if (cmd == C_ILL || (cmd == C_BRK && !bUseBrk)) // kod nielegalnego rozkazu lub BRK
wsprintf(buf, ".DB $%02X", int(code));
else
{
memcpy(buf, mnemonics + 3 * cmd, 3);
buf[3] = _T('\0');
}
return CString(buf);
}
const TCHAR CDeasm::mnemonics[]=
"LDALDXLDYSTASTXSTYSTZTAXTXATAYTYATXSTSXADCSBCCMPCPXCPYINCDECINADEAINXDEXINYDEY"
"ASLLSRROLRORANDORAEORBITTSBTRBJMPJSRBRKBRABPLBMIBVCBVSBCCBCSBNEBEQRTSRTIPHAPLA"
"PHXPLXPHYPLYPHPPLPCLCSECCLVCLDSEDCLISEINOP"
"BBRBBSRMBSMB"
"???";
CString CDeasm::Argument(UINT8 cmd, CodeAdr mode, UINT16 addr, UINT8 arg1, UINT8 arg2, bool bLabel, bool bHelp)
{
CString str;
addr++;
UINT8 lo= arg1;
UINT16 word= arg1 + (arg2 << 8);
switch (mode)
{
case A_IMP: // implied
case A_IMP2: // implied dla BRK
if (bHelp)
str = _T(" |Implied");
break;
case A_ACC: // accumulator
if (bHelp)
str = _T(" |Accumulator");
break;
case A_ILL: // warto滄 do oznaczania nielegalnych rozkaz體 w symulatorze (ILLEGAL)
break;
case A_IMM: // immediate
str.Format(" #$%02X",(int)lo);
if (bHelp)
str += _T(" |Immediate");
break;
case A_ZPG: // zero page
str.Format(bLabel ? " z%02X" : " $%02X",(int)lo);
if (bHelp)
str += _T(" |Zero Page");
break;
case A_ABS: // absolute
str.Format(bLabel ? " a%04X" : " $%04X",(int)word);
if (bHelp)
str += _T(" |Absolute");
break;
case A_ABS_X: // absolute indexed X
str.Format(bLabel ? " a%04X,X" : " $%04X,X",(int)word);
if (bHelp)
str += _T(" |Absolute Indexed, X");
break;
case A_ABS_Y: // absolute indexed Y
str.Format(bLabel ? " a%04X,Y" : " $%04X,Y",(int)word);
if (bHelp)
str += _T(" |Absolute Indexed, Y");
break;
case A_ZPG_X: // zero page indexed X
str.Format(bLabel ? " z%02X,X" : " $%02X,X",(int)lo);
if (bHelp)
str += _T(" |Zero Page Indexed, X");
break;
case A_ZPG_Y: // zero page indexed Y
str.Format(bLabel ? " z%02X,Y" : " $%02X,Y",(int)lo);
if (bHelp)
str += _T(" |Zero Page Indexed, Y");
break;
case A_REL: // relative
if (bHelp)
str = _T(" label |Relative");
else
str.Format(bLabel ? " e%04X" : " $%04X", int( lo & 0x80 ? addr+1 - (0x100 - lo) : addr+1 + lo ));
break;
case A_ZPGI: // zero page indirect
str.Format(bLabel ? " (z%02X)" : " ($%02X)",(int)lo);
if (bHelp)
str += _T(" |Zero Page Indirect");
break;
case A_ZPGI_X: // zero page indirect, indexed X
str.Format(bLabel ? " (z%02X,X)" : " ($%02X,X)",(int)lo);
if (bHelp)
str += _T(" |Zero Page Indexed X, Indirect");
break;
case A_ZPGI_Y: // zero page indirect, indexed Y
str.Format(bLabel ? " (z%02X),Y" : " ($%02X),Y",(int)lo);
if (bHelp)
str += _T(" |Zero Page Indirect, Indexed Y");
break;
case A_ABSI: // absolute indirect
str.Format(bLabel ? " (a%04X)" : " ($%04X)",(int)word);
if (bHelp)
str += _T(" |Absolute Indirect");
break;
case A_ABSI_X: // absolute indirect, indexed X
str.Format(bLabel ? " (a%04X,X)" : " ($%04X,X)",(int)word);
if (bHelp)
str += _T(" |Absolute Indexed X, Indirect");
break;
case A_ZPG2: // zero page dla RMB i SMB
{
unsigned int bit_no= (cmd>>4) & 0x07;
str.Format(bLabel ? " #%u,z%02X" : " #%u,$%02X",(unsigned int)bit_no,(int)lo);
if (bHelp)
str += _T(" |Memory Bit Manipulation");
break;
}
case A_ZREL: // zero page / relative dla BBS i BBR
{
UINT8 hi= arg2; //ctx.mem[addr + 1];
unsigned int bit_no= (cmd >> 4) & 0x07;
str.Format(bLabel ? " #%u,z%02X,e%04X" : " #%u,$%02X,$%04X", bit_no, int(lo), int( hi & 0x80 ? addr+2 - (0x100 - hi) : addr+2 + hi ));
if (bHelp)
str += _T(" |Relative Bit Branch");
break;
}
default:
ASSERT(FALSE);
}
return str;
}
CString CDeasm::ArgumentValue(const CContext &ctx, int cmd_addr /*= -1*/)
{
CString str(_T("-"));
UINT8 arg;
UINT16 addr,tmp;
ASSERT(cmd_addr==-1 || cmd_addr>=0 && cmd_addr<=0xFFFF); // b酬dny adres
if (cmd_addr == -1)
cmd_addr = ctx.pc;
// UINT8 cmd= ctx.mem[cmd_addr];
UINT8 mode= CodeToMode()[ctx.mem[cmd_addr]];
cmd_addr = (cmd_addr + 1) & 0xFFFF;
switch (mode)
{
case A_IMP:
case A_IMP2:
case A_ACC:
break;
case A_IMM:
return SetValInfo(ctx.mem[cmd_addr]);
case A_REL:
arg = ctx.mem[cmd_addr];
if (arg & 0x80) // skok do ty硊
str.Format(_T("PC-$%02X"),int(0x100 - arg));
else // skok do przodu
str.Format(_T("PC+$%02X"),int(arg));
return str;
case A_ZPGI:
arg = ctx.mem[cmd_addr]; // adres kom髍ki na str. 0
addr = ctx.mem[arg]; // adres wsk. przez kom髍ki
addr += UINT16( ctx.mem[(arg+1)&0xFF] ) << 8;
// addr &= ctx.mem_mask;
return SetMemInfo(addr, ctx.mem[addr]);
case A_ZPG:
case A_ZPG2:
addr = ctx.mem[cmd_addr];
return SetMemZPGInfo((UINT8)addr, ctx.mem[addr]);
case A_ZPG_X:
addr = (ctx.mem[cmd_addr]+ctx.x) & 0xFF;
return SetMemZPGInfo((UINT8)addr, ctx.mem[addr]);
case A_ZPG_Y:
addr = (ctx.mem[cmd_addr]+ctx.y) & 0xFF;
return SetMemZPGInfo((UINT8)addr, ctx.mem[addr]);
case A_ABS:
addr = ctx.mem[cmd_addr]; // m硂dszy bajt adresu
addr += UINT16( ctx.mem[cmd_addr + 1] ) << 8;
// addr &= ctx.mem_mask;
return SetMemInfo(addr, ctx.mem[addr]);
case A_ABSI:
addr = ctx.mem[cmd_addr]; // m硂dszy bajt adresu
addr += UINT16( ctx.mem[cmd_addr + 1] ) << 8;
// addr &= ctx.mem_mask;
tmp = ctx.mem[addr]; // liczba pod adresem
tmp += UINT16( ctx.mem[addr + 1] ) << 8;
// tmp &= ctx.mem_mask;
return SetMemInfo(tmp, ctx.mem[tmp]);
case A_ABSI_X:
addr = ctx.mem[cmd_addr] + ctx.x; // m硂dszy bajt adresu + przesuni阠ie X
if (theApp.m_global.GetProcType() && (cmd_addr & 0xFF)==0xFF) // m硂dszy bajt == 0xFF?
addr += UINT16( ctx.mem[cmd_addr - 0xFF] ) << 8; // zgodnie z b酬dem w 6502
else
addr += UINT16( ctx.mem[cmd_addr + 1] ) << 8;
// addr &= ctx.mem_mask;
tmp = ctx.mem[addr]; // liczba pod adresem
tmp += UINT16( ctx.mem[addr + 1] ) << 8;
// tmp &= ctx.mem_mask;
return SetMemInfo(tmp, ctx.mem[tmp]);
case A_ABS_X:
addr = ctx.mem[cmd_addr] + ctx.x; // m硂dszy bajt adresu i przesuni阠ie X
addr += UINT16( ctx.mem[cmd_addr + 1] ) << 8;
// addr &= ctx.mem_mask;
return SetMemInfo(addr, ctx.mem[addr]);
case A_ABS_Y:
addr = ctx.mem[cmd_addr] + ctx.y; // m硂dszy bajt adresu i przesuni阠ie Y
addr += UINT16( ctx.mem[cmd_addr + 1] ) << 8;
// addr &= ctx.mem_mask;
return SetMemInfo(addr, ctx.mem[addr]);
case A_ZPGI_X:
arg = ctx.mem[cmd_addr]; // adres kom髍ki na str. 0
arg = (arg + ctx.x) & 0xFF;
addr = ctx.mem[arg]; // adres wsk. przez kom髍ki
addr += UINT16( ctx.mem[(arg+1)&0xFF] ) << 8;
// addr &= ctx.mem_mask;
return SetMemInfo(addr, ctx.mem[addr]);
case A_ZPGI_Y:
arg = ctx.mem[cmd_addr]; // adres kom髍ki na str. 0
addr = ctx.mem[arg] + ctx.y; // adres wsk. przez kom髍ki i przesuni阠ie Y
addr += UINT16( ctx.mem[(arg+1)&0xFF] ) << 8;
// addr &= ctx.mem_mask;
return SetMemInfo(addr, ctx.mem[addr]);
case A_ZREL:
{
CString tmp= SetMemZPGInfo((UINT8)cmd_addr, ctx.mem[cmd_addr]);
arg = ctx.mem[cmd_addr + 1];
if (arg & 0x80) // skok do ty硊
str.Format(_T("; PC-$%02X"),int(0x100 - arg));
else // skok do przodu
str.Format(_T("; PC+$%02X"),int(arg));
return tmp+str;
}
case A_ILL:
str.Empty();
break;
default:
ASSERT(FALSE);
str.Empty();
}
return str;
}
CString CDeasm::SetMemInfo(UINT16 addr, UINT8 val) // opis kom髍ki pami阠i
{
CString str;
str.Format("[%04X]: $%02X, %d, '%c', %s", int(addr), int(val), val&0xFF, val ? (char)val : (char)' ', (const TCHAR *)Binary(val));
return str;
}
CString CDeasm::SetMemZPGInfo(UINT8 addr, UINT8 val) // opis kom髍ki strony zerowej pami阠i
{
CString str;
str.Format("[%02X]: $%02X, %d, '%c', %s", int(addr), int(val), val&0xFF, val ? (char)val : (char)' ', (const TCHAR *)Binary(val));
return str;
}
CString CDeasm::SetValInfo(UINT8 val) // opis warto渃i 'val'
{
CString str;
str.Format("%d, '%c', %s", val&0xFF, val ? (char)val : (char)' ', (const TCHAR *)Binary(val));
return str;
}
CString CDeasm::Binary(UINT8 val)
{
CString bin(_T(' '),8);
bin.SetAt(0, val & 0x80 ? _T('1') : _T('0') );
bin.SetAt(1, val & 0x40 ? _T('1') : _T('0') );
bin.SetAt(2, val & 0x20 ? _T('1') : _T('0') );
bin.SetAt(3, val & 0x10 ? _T('1') : _T('0') );
bin.SetAt(4, val & 0x08 ? _T('1') : _T('0') );
bin.SetAt(5, val & 0x04 ? _T('1') : _T('0') );
bin.SetAt(6, val & 0x02 ? _T('1') : _T('0') );
bin.SetAt(7, val & 0x01 ? _T('1') : _T('0') );
return bin;
}
// odszukanie adresu rozkazu poprzedzaj筩ego dany rozkazint CDeasm::FindPrevAddr(UINT16 &addr, const CContext &ctx, int cnt/*= 1*/){
ASSERT(cnt >= 0);
if (cnt <= 0)
return 0;
if (cnt > 1)
{
int len= max(10, cnt * 3) + 2; UINT16 start= int(addr) - len > 0 ? addr - len : 0;
start &= ~1; // parzysty adres
CWordArray addresses;
addresses.SetSize(len + 4);
UINT8 cmd;
int ret= 0;
int i;
for (i = 0; start < addr; i++)
{
addresses[i] = start;
cmd = ctx.mem[start];
// start += mode_to_len[CodeToMode()[cmd]];
start += cmd == 0 ? 1 : mode_to_len[CodeToMode()[cmd]];
// start &= ctx.mem_mask;
}
if (start == addr)
ret = 1;
else
ret = -1;
addr = addresses[i - cnt];
return ret;
}
else
{
UINT16 start= int(addr)-10 > 0 ? addr-10 : 0;
UINT16 prev= start;
int ret= 0;
// ASSERT(addr <= ctx.mem_mask); // niepoprawny adres; za du縴
UINT8 cmd;
while (start < addr)
{
prev = start;
cmd = ctx.mem[start];
if (cmd == 0) // rozkaz BRK?
start++; // zwi阫szamy tylko o 1, chocia
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -