mirror of
https://github.com/emu-russia/pureikyubu.git
synced 2025-04-02 10:42:15 -04:00
427 lines
12 KiB
C++
427 lines
12 KiB
C++
// The analyzer is a key component of the processor module.
|
|
// It is used by all other interested components (disassembler, interpreter, etc.)
|
|
|
|
#include "pch.h"
|
|
|
|
namespace DVD
|
|
{
|
|
bool MnAnalyze::Main(uint8_t* instrPtr, size_t instrMaxSize, MnInstrInfo* info)
|
|
{
|
|
*instrPtr++ = *instrPtr++;
|
|
info->instrSize++;
|
|
instrMaxSize--;
|
|
|
|
int nn = (info->instrBytes[0] >> 2) & 3;
|
|
int mm = info->instrBytes[0] & 3;
|
|
|
|
if (info->instrBytes[0] >= 0xF0)
|
|
{
|
|
switch (info->instrBytes[0])
|
|
{
|
|
case 0xF6: // NOP
|
|
info->instr = MnInstruction::NOP;
|
|
break;
|
|
case 0xF8: // MOV imm16, Dm
|
|
case 0xF9:
|
|
case 0xFA:
|
|
case 0xFB:
|
|
info->instr = MnInstruction::MOV;
|
|
if (!AddOp(info, MnOperand::Imm16, 0))
|
|
return false;
|
|
if (!FetchImm16(instrPtr, instrMaxSize, info))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + mm), mm))
|
|
return false;
|
|
break;
|
|
case 0xFC: // JMP label16
|
|
info->instr = MnInstruction::JMP;
|
|
info->flow = true;
|
|
if (!AddOp(info, MnOperand::Imm16, 0))
|
|
return false;
|
|
if (!FetchImm16(instrPtr, instrMaxSize, info))
|
|
return false;
|
|
break;
|
|
case 0xFD: // JSR label16
|
|
info->instr = MnInstruction::JSR;
|
|
info->flow = true;
|
|
if (!AddOp(info, MnOperand::Imm16, 0))
|
|
return false;
|
|
if (!FetchImm16(instrPtr, instrMaxSize, info))
|
|
return false;
|
|
break;
|
|
case 0xFE: // RTS
|
|
info->instr = MnInstruction::RTS;
|
|
info->flow = true;
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
else if (info->instrBytes[0] >= 0xE0)
|
|
{
|
|
switch (info->instrBytes[0])
|
|
{
|
|
case 0xE0: // Bxx
|
|
case 0xE1:
|
|
case 0xE2:
|
|
case 0xE3:
|
|
case 0xE4:
|
|
case 0xE5:
|
|
case 0xE6:
|
|
case 0xE7:
|
|
case 0xE8:
|
|
case 0xE9:
|
|
case 0xEA:
|
|
info->instr = MnInstruction::Bcc;
|
|
info->cc = (MnCond)(info->instrBytes[0] & 0xf);
|
|
info->flow = true;
|
|
if (!AddOp(info, MnOperand::Imm8, 0))
|
|
return false;
|
|
if (!FetchImm8(instrPtr, instrMaxSize, info))
|
|
return false;
|
|
break;
|
|
case 0xEB: // RTI
|
|
info->instr = MnInstruction::RTI;
|
|
info->flow = true;
|
|
break;
|
|
case 0xEC: // CMP imm16, Am
|
|
case 0xED:
|
|
case 0xEE:
|
|
case 0xEF:
|
|
info->instr = MnInstruction::CMP;
|
|
if (!AddOp(info, MnOperand::Imm16, 0))
|
|
return false;
|
|
if (!FetchImm16(instrPtr, instrMaxSize, info))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::A0 + mm), mm))
|
|
return false;
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
switch (info->instrBytes[0] >> 4)
|
|
{
|
|
case 0: // MOV Dm, (An)
|
|
info->instr = MnInstruction::MOV;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + mm), mm))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::Ind_A0 + nn), nn))
|
|
return false;
|
|
break;
|
|
case 1: // MOVB Dm, (An)
|
|
info->instr = MnInstruction::MOVB;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + mm), mm))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::Ind_A0 + nn), nn))
|
|
return false;
|
|
break;
|
|
case 2: // MOV (An), Dm
|
|
info->instr = MnInstruction::MOV;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::Ind_A0 + nn), nn))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + mm), mm))
|
|
return false;
|
|
break;
|
|
case 3: // MOVBU (An), Dm
|
|
info->instr = MnInstruction::MOVBU;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::Ind_A0 + nn), nn))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + mm), mm))
|
|
return false;
|
|
break;
|
|
case 4: // MOV Dm, (d8, An)
|
|
info->instr = MnInstruction::MOV;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + mm), mm))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D8_A0 + nn), nn))
|
|
return false;
|
|
if (!FetchImm8(instrPtr, instrMaxSize, info))
|
|
return false;
|
|
break;
|
|
case 5: // MOV Am, (d8, An)
|
|
info->instr = MnInstruction::MOV;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::A0 + mm), mm))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D8_A0 + nn), nn))
|
|
return false;
|
|
if (!FetchImm8(instrPtr, instrMaxSize, info))
|
|
return false;
|
|
break;
|
|
case 6: // MOV (d8, An), Dm
|
|
info->instr = MnInstruction::MOV;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D8_A0 + nn), nn))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + mm), mm))
|
|
return false;
|
|
if (!FetchImm8(instrPtr, instrMaxSize, info))
|
|
return false;
|
|
break;
|
|
case 7: // MOV (d8, An), Am
|
|
info->instr = MnInstruction::MOV;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D8_A0 + nn), nn))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::A0 + mm), mm))
|
|
return false;
|
|
if (!FetchImm8(instrPtr, instrMaxSize, info))
|
|
return false;
|
|
break;
|
|
case 8: // MOV Dn, Dm (n==m: MOV imm8, Dn)
|
|
info->instr = MnInstruction::MOV;
|
|
if (nn == mm)
|
|
{
|
|
if (!AddOp(info, MnOperand::Imm8, 0))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + nn), nn))
|
|
return false;
|
|
if (!FetchImm8(instrPtr, instrMaxSize, info))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + nn), nn))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + mm), mm))
|
|
return false;
|
|
}
|
|
break;
|
|
case 9: // ADD Dn, Dm
|
|
info->instr = MnInstruction::ADD;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + nn), nn))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + mm), mm))
|
|
return false;
|
|
break;
|
|
case 0xA: // SUB Dn, Dm
|
|
info->instr = MnInstruction::SUB;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + nn), nn))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + mm), mm))
|
|
return false;
|
|
break;
|
|
case 0xB: // EXTXxx Dm
|
|
switch (nn)
|
|
{
|
|
case 0: info->instr = MnInstruction::EXTX; break;
|
|
case 1: info->instr = MnInstruction::EXTXU; break;
|
|
case 2: info->instr = MnInstruction::EXTXB; break;
|
|
case 3: info->instr = MnInstruction::EXTXBU; break;
|
|
}
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + mm), mm))
|
|
return false;
|
|
break;
|
|
case 0xC:
|
|
switch (nn)
|
|
{
|
|
case 0: // MOV Dm, (abs16)
|
|
info->instr = MnInstruction::MOV;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + mm), mm))
|
|
return false;
|
|
if (!AddOp(info, MnOperand::Abs16, 0))
|
|
return false;
|
|
if (!FetchImm16(instrPtr, instrMaxSize, info))
|
|
return false;
|
|
break;
|
|
case 1: // MOVB Dm, (abs16)
|
|
info->instr = MnInstruction::MOVB;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + mm), mm))
|
|
return false;
|
|
if (!AddOp(info, MnOperand::Abs16, 0))
|
|
return false;
|
|
if (!FetchImm16(instrPtr, instrMaxSize, info))
|
|
return false;
|
|
break;
|
|
case 2: // MOV (abs16), Dm
|
|
info->instr = MnInstruction::MOV;
|
|
if (!AddOp(info, MnOperand::Abs16, 0))
|
|
return false;
|
|
if (!FetchImm16(instrPtr, instrMaxSize, info))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + mm), mm))
|
|
return false;
|
|
break;
|
|
case 3: // MOVBU (abs16), Dm
|
|
info->instr = MnInstruction::MOVBU;
|
|
if (!AddOp(info, MnOperand::Abs16, 0))
|
|
return false;
|
|
if (!FetchImm16(instrPtr, instrMaxSize, info))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + mm), mm))
|
|
return false;
|
|
break;
|
|
}
|
|
break;
|
|
case 0xD:
|
|
switch (nn)
|
|
{
|
|
case 0: // ADD imm8, Am
|
|
info->instr = MnInstruction::ADD;
|
|
if (!AddOp(info, MnOperand::Imm8, 0))
|
|
return false;
|
|
if (!FetchImm8(instrPtr, instrMaxSize, info))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::A0 + mm), mm))
|
|
return false;
|
|
break;
|
|
case 1: // ADD imm8, Dm
|
|
info->instr = MnInstruction::ADD;
|
|
if (!AddOp(info, MnOperand::Imm8, 0))
|
|
return false;
|
|
if (!FetchImm8(instrPtr, instrMaxSize, info))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + mm), mm))
|
|
return false;
|
|
break;
|
|
case 2: // CMP imm8, Dm
|
|
info->instr = MnInstruction::CMP;
|
|
if (!AddOp(info, MnOperand::Imm8, 0))
|
|
return false;
|
|
if (!FetchImm8(instrPtr, instrMaxSize, info))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::D0 + mm), mm))
|
|
return false;
|
|
break;
|
|
case 3: // MOV imm16, Am
|
|
info->instr = MnInstruction::MOV;
|
|
if (!AddOp(info, MnOperand::Imm16, 0))
|
|
return false;
|
|
if (!FetchImm16(instrPtr, instrMaxSize, info))
|
|
return false;
|
|
if (!AddOp(info, (MnOperand)((int)MnOperand::A0 + mm), mm))
|
|
return false;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool MnAnalyze::F0(uint8_t* instrPtr, size_t instrMaxSize, MnInstrInfo* info)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool MnAnalyze::F1(uint8_t* instrPtr, size_t instrMaxSize, MnInstrInfo* info)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool MnAnalyze::F2(uint8_t* instrPtr, size_t instrMaxSize, MnInstrInfo* info)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool MnAnalyze::F3(uint8_t* instrPtr, size_t instrMaxSize, MnInstrInfo* info)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool MnAnalyze::F4(uint8_t* instrPtr, size_t instrMaxSize, MnInstrInfo* info)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool MnAnalyze::F5(uint8_t* instrPtr, size_t instrMaxSize, MnInstrInfo* info)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool MnAnalyze::F7(uint8_t* instrPtr, size_t instrMaxSize, MnInstrInfo* info)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool MnAnalyze::FetchImm8(uint8_t* instrPtr, size_t instrMaxSize, MnInstrInfo* info)
|
|
{
|
|
if (instrMaxSize < sizeof(uint8_t))
|
|
return false;
|
|
*instrPtr++ = instrPtr[0];
|
|
info->instrSize++;
|
|
info->imm.Uint8 = instrPtr[0];
|
|
return true;
|
|
}
|
|
|
|
bool MnAnalyze::FetchImm16(uint8_t* instrPtr, size_t instrMaxSize, MnInstrInfo* info)
|
|
{
|
|
if (instrMaxSize < 2 * sizeof(uint8_t))
|
|
return false;
|
|
*instrPtr++ = instrPtr[0];
|
|
info->instrSize++;
|
|
*instrPtr++ = instrPtr[1];
|
|
info->instrSize++;
|
|
info->imm.Uint16 = ((uint16_t)instrPtr[1] << 8) | instrPtr[0];
|
|
return true;
|
|
}
|
|
|
|
bool MnAnalyze::FetchImm24(uint8_t* instrPtr, size_t instrMaxSize, MnInstrInfo* info)
|
|
{
|
|
if (instrMaxSize < 3 * sizeof(uint8_t))
|
|
return false;
|
|
*instrPtr++ = instrPtr[0];
|
|
info->instrSize++;
|
|
*instrPtr++ = instrPtr[1];
|
|
info->instrSize++;
|
|
*instrPtr++ = instrPtr[2];
|
|
info->instrSize++;
|
|
info->imm.Uint24 = ((uint32_t)instrPtr[2] << 16) | ((uint32_t)instrPtr[1] << 8) | instrPtr[0];
|
|
return true;
|
|
}
|
|
|
|
bool MnAnalyze::AddOp(MnInstrInfo* info, MnOperand op, int bits)
|
|
{
|
|
if (info->numOp >= MnInstrInfoOperands)
|
|
return false;
|
|
|
|
info->op[info->numOp] = op;
|
|
info->opBits[info->numOp] = bits;
|
|
|
|
info->numOp++;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool MnAnalyze::Analyze(uint8_t* instrPtr, size_t instrMaxSize, MnInstrInfo* info)
|
|
{
|
|
assert(instrPtr);
|
|
assert(info);
|
|
|
|
if (instrMaxSize == 0)
|
|
return false;
|
|
|
|
info->instr = MnInstruction::Unknown;
|
|
instrPtr = info->instrBytes;
|
|
info->instrSize = 0;
|
|
info->numOp = 0;
|
|
info->flow = false;
|
|
|
|
if (instrPtr[0] >= 0xF0)
|
|
{
|
|
switch (instrPtr[0])
|
|
{
|
|
case 0xF0: return F0(instrPtr, instrMaxSize, info);
|
|
case 0xF1: return F1(instrPtr, instrMaxSize, info);
|
|
case 0xF2: return F2(instrPtr, instrMaxSize, info);
|
|
case 0xF3: return F3(instrPtr, instrMaxSize, info);
|
|
case 0xF4: return F4(instrPtr, instrMaxSize, info);
|
|
case 0xF5: return F5(instrPtr, instrMaxSize, info);
|
|
case 0xF6: return Main(instrPtr, instrMaxSize, info);
|
|
case 0xF7: return F7(instrPtr, instrMaxSize, info);
|
|
case 0xF8: return Main(instrPtr, instrMaxSize, info);
|
|
case 0xF9: return Main(instrPtr, instrMaxSize, info);
|
|
case 0xFA: return Main(instrPtr, instrMaxSize, info);
|
|
case 0xFB: return Main(instrPtr, instrMaxSize, info);
|
|
case 0xFC: return Main(instrPtr, instrMaxSize, info);
|
|
case 0xFD: return Main(instrPtr, instrMaxSize, info);
|
|
case 0xFE: return Main(instrPtr, instrMaxSize, info);
|
|
case 0xFF: break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return Main(instrPtr, instrMaxSize, info);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
}
|