Mesen2/Core/WS/Debugger/WsDisUtils.cpp
Sour 2e6a2e5494 Debugger: WS - Fixed effective address calculation for LES/LDS
Show first word's address instead of the second's
2024-11-13 21:27:48 +09:00

734 lines
20 KiB
C++

#include "pch.h"
#include "WS/Debugger/WsDisUtils.h"
#include "WS/Debugger/DummyWsCpu.h"
#include "WS/WsTypes.h"
#include "WS/WsMemoryManager.h"
#include "WS/WsConsole.h"
#include "Debugger/DisassemblyInfo.h"
#include "Debugger/LabelManager.h"
#include "Debugger/MemoryDumper.h"
#include "Shared/MemoryType.h"
#include "Shared/EmuSettings.h"
#include "Utilities/FastString.h"
#include "Utilities/HexUtilities.h"
static constexpr const char* _modRegLut8[8] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
static constexpr const char* _modRegLut16[8] = { "AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI" };
static constexpr const char* _modSegRegLut[4] = { "ES", "CS", "SS", "DS" };
constexpr const char* _opTemplate[256] = {
//0-0F
"ADD m", "ADD m", "ADD m", "ADD m", "ADD AL, i", "ADD AX, j", "PUSH ES", "POP ES",
"OR m", "OR m", "OR m", "OR m", "OR AL, i", "OR AX, j", "PUSH CS", "UNDEFINED_0F",
//10-1F
"ADC m", "ADC m", "ADC m", "ADC m", "ADC AL, i", "ADC AX, j", "PUSH SS", "POP SS",
"SBB m", "SBB m", "SBB m", "SBB m", "SBB AL, i", "SBB AX, j", "PUSH DS", "POP DS",
//20-2F
"AND m", "AND m", "AND m", "AND m", "AND AL, i", "AND AX, j", "ES:", "DAA",
"SUB m", "SUB m", "SUB m", "SUB m", "SUB AL, i", "SUB AX, j", "CS:", "DAS",
//30-3F
"XOR m", "XOR m", "XOR m", "XOR m", "XOR AL, i", "XOR AX, j", "SS:", "AAA",
"CMP m", "CMP m", "CMP m", "CMP m", "CMP AL, i", "CMP AX, j", "DS:", "AAS",
//40-4F
"INC AX", "INC CX", "INC DX", "INC BX", "INC SP", "INC BP", "INC SI", "INC DI",
"DEC AX", "DEC CX", "DEC DX", "DEC BX", "DEC SP", "DEC BP", "DEC SI", "DEC DI",
//50-5F
"PUSH AX", "PUSH CX", "PUSH DX", "PUSH BX", "PUSH SP", "PUSH BP", "PUSH SI", "PUSH DI",
"POP AX", "POP CX", "POP DX", "POP BX", "POP SP", "POP BP", "POP SI", "POP DI",
//60-6F
"PUSHA", "POPA", "BOUND p", "UNDEFINED_63", "UNDEFINED_64", "UNDEFINED_65", "UNDEFINED_66", "UNDEFINED_67",
"PUSH j", "IMUL n, j", "PUSH i", "IMUL n, i", "INSB", "INSW", "OUTSB", "OUTSW",
//70-7F
"JO r", "JNO r", "JB r", "JNB r", "JZ r", "JNZ r", "JBE r", "JA r",
"JS r", "JNS r", "JPE r", "JPO r", "JL r", "JGE r", "JLE r", "JG r",
//80-8F
"v", "v", "v", "v", "TEST m", "TEST m", "XCHG m", "XCHG m",
"MOV m", "MOV m", "MOV m", "MOV m", "MOV q", "LEA o", "MOV q", "POP n",
//90-9F
"NOP", "XCHG CX, AX", "XCHG DX, AX", "XCHG BX, AX", "XCHG SP, AX", "XCHG BP, AX", "XCHG SI, AX", "XCHG DI, AX",
"CBW", "CWD", "CALL t", "WAIT", "PUSHF", "POPF", "SAHF", "LAHF",
//A0-AF
"MOV AL, a", "MOV AX, a", "MOV a, AL", "MOV a, AX", "MOVSB", "MOVSW", "CMPSB", "CMPSW",
"TEST AL, i", "TEST AX, j", "STOSB", "STOSW", "LODSB", "LODSW", "SCASB", "SCASW",
//B0-BF
"MOV AL, i", "MOV CL, i", "MOV DL, i", "MOV BL, i", "MOV AH, i", "MOV CH, i", "MOV DH, i", "MOV BH, i",
"MOV AX, j", "MOV CX, j", "MOV DX, j", "MOV BX, j", "MOV SP, j", "MOV BP, j", "MOV SI, j", "MOV DI, j",
//C0-CF
"w, i", "w, i", "RET j", "RET", "LES o", "LDS o", "MOV n, i", "MOV n, j",
"ENTER j, i", "LEAVE", "RETF j", "RETF", "INT 3", "INT i" , "INTO", "IRET",
//D0-DF
"w", "w", "w, CL", "w, CL", "AAM i", "AAD i", "SALC", "XLAT",
"UNDEFINED_D8", "UNDEFINED_D9", "UNDEFINED_DA", "UNDEFINED_DB", "UNDEFINED_DC", "UNDEFINED_DD", "UNDEFINED_DE", "UNDEFINED_DF",
//E0-EF
"LOOPNZ r", "LOOPZ r", "LOOP r", "JCXZ r", "IN AL, i", "IN AX, i", "OUT i, AL", "OUT i, AX",
"CALL s", "JMP s", "JMP t", "JMP r", "IN AL, DX", "IN AX, DX", "OUT DX, AL", "OUT DX, AX",
//F0-FF
"LOCK", "UNDEFINED_F1", "REPNZ", "REPZ", "HLT", "CMC", "x", "x",
"CLC", "STC", "CLI", "STI", "CLD", "STD", "y", "z"
};
void WsDisUtils::GetDisassembly(DisassemblyInfo& info, string& out, uint32_t memoryAddr, LabelManager* labelManager, EmuSettings* settings)
{
FastString str(settings->GetDebugConfig().UseLowerCaseDisassembly);
uint8_t* byteCode = info.GetByteCode();
uint8_t opCode = byteCode[0];
WsSegment segment = WsSegment::Default;
while(IsPrefix(opCode)) {
switch(opCode) {
case 0x26: segment = WsSegment::ES; break;
case 0x36: segment = WsSegment::SS; break;
case 0x2E: segment = WsSegment::CS; break;
case 0x3E: segment = WsSegment::DS; break;
case 0xF0:
case 0xF2:
case 0xF3:
//rep, lock
str.WriteAll(_opTemplate[opCode], ' ');
break;
}
byteCode++;
opCode = byteCode[0];
}
const char* op = _opTemplate[opCode];
int i = 0;
while(op[i]) {
switch(op[i]) {
//Address offset
case 'a':
GetSegment(str, segment, "DS");
str.WriteAll("[$", HexUtilities::ToHex((uint16_t)(byteCode[1] | (byteCode[2] << 8))), "]");
break;
//Immediate values
case 'i': str.WriteAll("$", HexUtilities::ToHex(byteCode[1])); byteCode++; break;
case 'j': str.WriteAll("$", HexUtilities::ToHex((uint16_t)(byteCode[1] | (byteCode[2] << 8)))); byteCode += 2; break;
//ModRM (2 operands)
case 'm': {
bool word = opCode & 0x01;
bool direction = opCode & 0x02;
if(direction) {
GetModRegParam(str, byteCode, word);
str.Write(", ");
GetModRmParam(str, byteCode, segment, word);
} else {
GetModRmParam(str, byteCode, segment, word);
str.Write(", ");
GetModRegParam(str, byteCode, word);
}
break;
}
//ModRM (+ immediate value)
case 'n': {
bool word = op[i] == 'l';
byteCode += GetModRmParam(str, byteCode, segment, word);
break;
}
//ModRM (2 operands, LEA/LDS/LES)
case 'o':
GetModRegParam(str, byteCode, true);
str.Write(", ");
GetModRmParam(str, byteCode, segment, true, true);
break;
//ModRM (2 operands, BOUND)
case 'p':
GetModRegParam(str, byteCode, true);
str.Write(", ");
GetModRmParam(str, byteCode, segment, true, false);
break;
//ModRM (mov segment)
case 'q': {
bool direction = opCode & 0x02;
if(direction) {
GetModSegRegParam(str, byteCode);
str.Write(", ");
GetModRmParam(str, byteCode, segment, true);
} else {
GetModRmParam(str, byteCode, segment, true);
str.Write(", ");
GetModSegRegParam(str, byteCode);
}
break;
}
//Relative jumps
case 'r': GetJmpDestination(str, byteCode, 1); break;
case 's': GetJmpDestination(str, byteCode, 2); break;
case 't': GetJmpDestination(str, byteCode, 4); break;
case 'v': //GRP1
switch((byteCode[1] >> 3) & 0x07) {
case 0: str.Write("ADD "); break;
case 1: str.Write("OR "); break;
case 2: str.Write("ADC "); break;
case 3: str.Write("SBB "); break;
case 4: str.Write("AND "); break;
case 5: str.Write("SUB "); break;
case 6: str.Write("XOR "); break;
case 7: str.Write("CMP "); break;
}
byteCode += GetModRmParam(str, byteCode, segment, opCode & 0x01);
str.Write(", ");
if((opCode & 0x03) == 0x01) {
str.WriteAll("$", HexUtilities::ToHex((uint16_t)(byteCode[1] | (byteCode[2] << 8))));
} else if((opCode & 0x03) == 0x03) {
str.WriteAll("$", HexUtilities::ToHex((uint16_t)(int16_t)(int8_t)byteCode[1]));
} else {
str.WriteAll("$", HexUtilities::ToHex(byteCode[1]));
}
break;
case 'w': { //GRP2
switch((byteCode[1] >> 3) & 0x07) {
case 0: str.Write("ROL "); break;
case 1: str.Write("ROR "); break;
case 2: str.Write("RCL "); break;
case 3: str.Write("RCR "); break;
case 4: str.Write("SHL "); break;
case 5: str.Write("SHR "); break;
case 6: str.Write("UNDEFINED_GRP2_6 "); break;
case 7: str.Write("SAR "); break;
}
//Followed by an immediate value for C0/C1
byteCode += GetModRmParam(str, byteCode, segment, opCode & 0x01);
break;
}
case 'x': { //GRP3
uint8_t mode = (byteCode[1] >> 3) & 0x07;
bool word = opCode & 0x01;
switch(mode) {
case 0: str.Write("TEST "); break;
case 1: str.Write("UNDEFINED_GRP3_1 "); break;
case 2: str.Write("NOT "); break;
case 3: str.Write("NEG "); break;
case 4: str.WriteAll("MUL ", word ? "AX, " : ""); break;
case 5: str.WriteAll("IMUL ", word ? "AX, " : ""); break;
case 6: str.WriteAll("DIV ", word ? "AX, " : ""); break;
case 7: str.WriteAll("IDIV ", word ? "AX, " : ""); break;
}
byteCode += GetModRmParam(str, byteCode, segment, word);
if(mode == 0) {
if(word) {
str.WriteAll(", $", HexUtilities::ToHex((uint16_t)(byteCode[1] | (byteCode[2] << 8))));
} else {
str.WriteAll(", $", HexUtilities::ToHex(byteCode[1]));
}
}
break;
}
case 'y': //grp 4
case 'z': //grp 5
switch((byteCode[1] >> 3) & 0x07) {
case 0: str.Write("INC "); break;
case 1: str.Write("DEC "); break;
case 2: str.Write("CALL "); break;
case 3: str.Write("CALL FAR "); break;
case 4: str.Write("JMP "); break;
case 5: str.Write("JMP FAR "); break;
case 6: str.Write("PUSH "); break;
case 7: str.Write("UNDEFINED_GRP5_7 "); break;
}
GetModRmParam(str, byteCode, segment, opCode & 0x01);
break;
default: str.Write(op[i]); break;
}
i++;
}
out += str.ToString();
}
void WsDisUtils::GetJmpDestination(FastString& str, uint8_t* byteCode, uint8_t size)
{
if(size == 4) {
str.WriteAll("$", HexUtilities::ToHex((uint16_t)(byteCode[3] | (byteCode[4] << 8))));
str.WriteAll(":$", HexUtilities::ToHex((uint16_t)(byteCode[1] | (byteCode[2] << 8))));
} else if(size == 2) {
uint16_t jmpOffset = (uint16_t)(byteCode[1] | (byteCode[2] << 8));
str.WriteAll("+$", HexUtilities::ToHex(jmpOffset));
} else if(size == 1) {
uint8_t jmpOffset = (uint8_t)byteCode[1];
str.WriteAll("+$", HexUtilities::ToHex(jmpOffset));
}
}
void WsDisUtils::GetSegment(FastString& str, WsSegment segment, const char* defaultSegment)
{
switch(segment) {
default: case WsSegment::Default: str.WriteAll(defaultSegment, ':'); break;
case WsSegment::ES: str.Write("ES:"); break;
case WsSegment::SS: str.Write("SS:"); break;
case WsSegment::CS: str.Write("CS:"); break;
case WsSegment::DS: str.Write("DS:"); break;
}
}
void WsDisUtils::GetModRegParam(FastString& str, uint8_t* byteCode, bool word)
{
uint8_t modRm = byteCode[1];
uint8_t reg = (modRm >> 3) & 0x07;
str.Write(word ? _modRegLut16[reg] : _modRegLut8[reg]);
}
void WsDisUtils::GetModSegRegParam(FastString& str, uint8_t* byteCode)
{
uint8_t modRm = byteCode[1];
uint8_t reg = (modRm >> 3) & 0x03;
str.Write(_modSegRegLut[reg]);
}
int WsDisUtils::GetModRmParam(FastString& str, uint8_t* byteCode, WsSegment segment, bool word, bool forLeaLdsLes)
{
uint8_t modRm = byteCode[1];
uint8_t mode = (modRm >> 6) & 0x03;
uint8_t rm = modRm & 0x07;
int len = 1;
string param;
string param2;
if(mode == 3) {
if(forLeaLdsLes) {
switch(rm) {
case 0x00: GetSegment(str, segment, "DS"); str.Write("[BX+AX]"); break;
case 0x01: GetSegment(str, segment, "DS"); str.Write("[BX+CX]"); break;
case 0x02: GetSegment(str, segment, "SS"); str.Write("[BP+DX]"); break;
case 0x03: GetSegment(str, segment, "SS"); str.Write("[BP+BX]"); break;
case 0x04: GetSegment(str, segment, "DS"); str.Write("[SP+SI]"); break;
case 0x05: GetSegment(str, segment, "DS"); str.Write("[BP+DI]"); break;
case 0x06: GetSegment(str, segment, "SS"); str.Write("[BP+SI]"); break;
case 0x07: GetSegment(str, segment, "DS"); str.Write("[BX+DI]"); break;
}
} else {
str.Write(word ? _modRegLut16[rm] : _modRegLut8[rm]);
}
} else if(mode == 0 && rm == 0x06) {
GetSegment(str, segment, "DS");
str.WriteAll("[$", HexUtilities::ToHex((uint16_t)(byteCode[2] | (byteCode[3] << 8))), ']');
len += 2;
} else {
switch(rm) {
case 0x00: GetSegment(str, segment, "DS"); str.Write("[BX+SI"); break;
case 0x01: GetSegment(str, segment, "DS"); str.Write("[BX+DI"); break;
case 0x02: GetSegment(str, segment, "SS"); str.Write("[BP+SI"); break;
case 0x03: GetSegment(str, segment, "SS"); str.Write("[BP+DI"); break;
case 0x04: GetSegment(str, segment, "DS"); str.Write("[SI"); break;
case 0x05: GetSegment(str, segment, "DS"); str.Write("[DI"); break;
case 0x06: GetSegment(str, segment, "SS"); str.Write("[BP"); break;
case 0x07: GetSegment(str, segment, "DS"); str.Write("[BX"); break;
}
if(mode == 1) {
str.WriteAll("+$", HexUtilities::ToHex((uint8_t)byteCode[2]), ']');
len++;
} else if(mode == 2) {
str.WriteAll("+$", HexUtilities::ToHex((uint16_t)(byteCode[2] | (byteCode[3] << 8))), ']');
len += 2;
} else {
str.Write(']');
}
}
return len;
}
EffectiveAddressInfo WsDisUtils::GetEffectiveAddress(DisassemblyInfo& info, WsConsole* console, WsCpuState& state)
{
DummyWsCpu dummyCpu(nullptr, console->GetMemoryManager());
dummyCpu.SetDummyState(state);
dummyCpu.Exec();
uint16_t opCode = WsDisUtils::GetFullOpCode(info);
if(WsDisUtils::IsReturnInstruction(opCode) || WsDisUtils::IsPushPopInstruction(opCode)) {
return {};
}
if((uint8_t)opCode == 0xC8 || (uint8_t)opCode == 0xC9) {
//Show nothing for Enter/Leave
return {};
}
if(WsDisUtils::IsConditionalJump(opCode) || WsDisUtils::IsUnconditionalJump(opCode)) {
EffectiveAddressInfo result;
result.ShowAddress = true;
result.Address = dummyCpu.GetProgramCounter();
result.Type = MemoryType::WsMemory;
return result;
}
//For everything else, return the last read/write address
uint32_t count = dummyCpu.GetOperationCount();
for(int i = count - 1; i > 0; i--) {
MemoryOperationInfo opInfo = dummyCpu.GetOperationInfo(i);
if(opInfo.Type != MemoryOperationType::ExecOperand) {
MemoryOperationInfo prevOpInfo = dummyCpu.GetOperationInfo(i - 1);
EffectiveAddressInfo result;
result.ShowAddress = true;
if(dummyCpu.IsWordAccess(i)) {
result.ValueSize = 2;
if(dummyCpu.IsWordAccess(i - 1) && prevOpInfo.Type == opInfo.Type && prevOpInfo.Address == opInfo.Address - 2) {
result.Address = prevOpInfo.Address;
result.Type = prevOpInfo.MemType;
} else {
result.Address = opInfo.Address;
result.Type = opInfo.MemType;
}
} else {
if(prevOpInfo.Type == opInfo.Type && prevOpInfo.Address == opInfo.Address - 1) {
//For 16-bit read/writes that were split into 2 8-bit accesses, return the first address
result.Address = prevOpInfo.Address;
result.Type = prevOpInfo.MemType;
result.ValueSize = 2;
} else {
result.Address = opInfo.Address;
result.Type = opInfo.MemType;
result.ValueSize = 1;
}
}
return result;
}
}
return {};
}
int WsDisUtils::GetModRmSize(uint8_t modRm)
{
uint8_t mode = (modRm >> 6) & 0x03;
uint8_t rm = modRm & 0x07;
if(mode == 2 || (mode == 0 && rm == 0x06)) {
return 3;
} else if(mode == 1) {
return 2;
}
return 1;
}
bool WsDisUtils::IsPrefix(uint8_t opCode)
{
return opCode == 0xF0 || opCode == 0xF2 || opCode == 0xF3 || opCode == 0x26 || opCode == 0x36 || opCode == 0x2E || opCode == 0x3F;
}
uint8_t WsDisUtils::GetOpSize(uint32_t cpuAddress, MemoryType memType, MemoryDumper* memoryDumper)
{
uint8_t size = 1;
uint8_t opCode = memoryDumper->GetMemoryValue(memType, cpuAddress);
while(IsPrefix(opCode)) {
cpuAddress++;
opCode = memoryDumper->GetMemoryValue(memType, cpuAddress);
size++;
}
const char* op = _opTemplate[opCode];
int i = 0;
while(op[i]) {
switch(op[i]) {
//Absolute address
case 'a': size+=2; break;
//Immediate values
case 'i': size++; break;
case 'j': size += 2; break;
//ModRM
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
size += GetModRmSize(memoryDumper->GetMemoryValue(memType, cpuAddress + 1));
break;
//Relative jumps
case 'r': size++; break;
case 's': size += 2; break;
case 't': size += 4; break;
case 'v': //grp1
size += GetModRmSize(memoryDumper->GetMemoryValue(memType, cpuAddress + 1));
size++;
if((opCode & 0x3) == 0x01) {
size++;
}
break;
case 'x': { //grp3
uint8_t modRm = memoryDumper->GetMemoryValue(memType, cpuAddress + 1);
size += GetModRmSize(modRm);
if(((modRm >> 3) & 0x07) == 0) {
size += (opCode & 0x01) ? 2 : 1;
}
break;
}
case 'w': //grp2
case 'y': //grp4
case 'z': //grp5
size += GetModRmSize(memoryDumper->GetMemoryValue(memType, cpuAddress + 1));
break;
default: break;
}
i++;
}
return size;
}
uint16_t WsDisUtils::GetFullOpCode(uint16_t cs, uint16_t ip, WsMemoryManager* memoryManager)
{
int i = 0;
while(IsPrefix(memoryManager->DebugRead((cs << 4) + ip)) && i < 6) {
ip++;
i++;
}
return (
memoryManager->DebugRead((cs << 4) + ip) |
(memoryManager->DebugRead((cs << 4) + (uint16_t)(ip + 1)) << 8)
);
}
uint16_t WsDisUtils::GetFullOpCode(DisassemblyInfo& disInfo)
{
uint8_t* byteCode = disInfo.GetByteCode();
int i = 0;
while(IsPrefix(byteCode[i]) && i < 6) {
i++;
}
return byteCode[i] | (byteCode[i+1] << 8);
}
bool WsDisUtils::IsJumpToSub(uint16_t opCode)
{
switch((uint8_t)opCode) {
case 0x9A:
case 0xE8:
return true;
case 0xFE:
case 0xFF: {
uint8_t mode = (opCode >> 11) & 0x07;
switch(mode) {
case 2: //CALL
case 3: //CALL FAR
return true;
default:
return false;
}
}
}
return false;
}
bool WsDisUtils::IsReturnInstruction(uint16_t opCode)
{
switch((uint8_t)opCode) {
case 0xC2: //RET
case 0xC3: //RET
case 0xCA: //RETF
case 0xCB: //RETF
case 0xCF: //IRET
return true;
}
return false;
}
bool WsDisUtils::IsUnconditionalJump(uint16_t opCode)
{
switch((uint8_t)opCode) {
case 0x9A: //CALL
case 0xC2: //RET
case 0xC3: //RET
case 0xCA: //RETF
case 0xCB: //RETF
case 0xCF: //IRET
case 0xE8: //CALL relative
case 0xE9: //JMP
case 0xEA: //JMP
case 0xEB: //JMP
return true;
case 0xFE:
case 0xFF: {
uint8_t mode = (opCode >> 11) & 0x07;
switch(mode) {
case 2: //CALL
case 3: //CALL FAR
case 4: //JMP
case 5: //JMP FAR
return true;
default:
return false;
}
}
}
return false;
}
bool WsDisUtils::IsConditionalJump(uint16_t opCode)
{
switch((uint8_t)opCode) {
case 0x70: //JO
case 0x71: //JNO
case 0x72: //JB
case 0x73: //JNB
case 0x74: //JZ
case 0x75: //JNZ
case 0x76: //JBE
case 0x77: //JA
case 0x78: //JS
case 0x79: //JNS
case 0x7A: //JPE
case 0x7B: //JPO
case 0x7C: //JL
case 0x7D: //JGE
case 0x7E: //JLE
case 0x7F: //JG
case 0xE0: //LOOPNZ
case 0xE1: //LOOPZ
case 0xE2: //LOOP
case 0xE3: //JCXZ
return true;
}
return false;
}
bool WsDisUtils::IsUndefinedOpCode(uint16_t opCode)
{
switch((uint8_t)opCode) {
case 0x0F:
case 0x63:
case 0x64:
case 0x65:
case 0x66:
case 0x67:
case 0xD8:
case 0xD9:
case 0xDA:
case 0xDB:
case 0xDC:
case 0xDD:
case 0xDE:
case 0xDF:
case 0xF1:
return true;
case 0xC0:
case 0xC1:
case 0xD0:
case 0xD1:
case 0xD2:
case 0xD3:
return ((opCode >> 11) & 0x07) == 0x06;
case 0xF6:
case 0xF7:
return ((opCode >> 11) & 0x07) == 0x01;
case 0xFE:
case 0xFF:
return ((opCode >> 11) & 0x07) == 0x07;
default:
return false;
}
}
bool WsDisUtils::IsPushPopInstruction(uint16_t opCode)
{
switch((uint8_t)opCode) {
//Push/pop segments
case 0x06: case 0x07: case 0x0E: case 0x16:
case 0x17: case 0x1E: case 0x1F:
//Push
case 0x50: case 0x51: case 0x52: case 0x53:
case 0x54: case 0x55: case 0x56: case 0x57:
//Pop
case 0x58: case 0x59: case 0x5A: case 0x5B:
case 0x5C: case 0x5D: case 0x5E: case 0x5F:
//Push/pop all
case 0x60: case 0x61:
//Push immediate
case 0x68: case 0x6A:
//Push/pop flags
case 0x9C: case 0x9D:
return true;
}
return false;
}
CdlFlags::CdlFlags WsDisUtils::GetOpFlags(uint16_t opCode, uint32_t pc, uint32_t prevPc, uint8_t opSize)
{
if(WsDisUtils::IsJumpToSub(opCode)) {
return CdlFlags::SubEntryPoint;
} else if(WsDisUtils::IsUnconditionalJump(opCode) && !WsDisUtils::IsReturnInstruction(opCode)) {
return CdlFlags::JumpTarget;
} else if(WsDisUtils::IsConditionalJump(opCode) && (pc != prevPc + opSize)) {
return CdlFlags::JumpTarget;
}
return CdlFlags::None;
}
void WsDisUtils::UpdateAddressCsIp(uint32_t addr, WsCpuState& state)
{
uint32_t baseAddr = (state.CS << 4);
if(addr >= baseAddr && addr <= baseAddr + 0xFFFF) {
//address fits within the current code segment, only change the instruction pointer
state.IP = addr - baseAddr;
} else {
//address is outside the range of the current CS, change both values
state.CS = (addr & 0xF0000) >> 4;
state.IP = (addr & 0xFFFF);
}
}