DSPAnalyzer: Hide implementation details
Makes accessing flags a part of the function interface instead of exposing an internal variable.
This commit is contained in:
parent
cd29d565c4
commit
a8459fc189
|
@ -5,6 +5,7 @@
|
||||||
#include "Core/DSP/DSPAnalyzer.h"
|
#include "Core/DSP/DSPAnalyzer.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
|
|
||||||
|
@ -13,6 +14,10 @@
|
||||||
|
|
||||||
namespace DSPAnalyzer
|
namespace DSPAnalyzer
|
||||||
{
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr size_t ISPACE = 65536;
|
||||||
|
|
||||||
// Holds data about all instructions in RAM.
|
// Holds data about all instructions in RAM.
|
||||||
std::array<u8, ISPACE> code_flags;
|
std::array<u8, ISPACE> code_flags;
|
||||||
|
|
||||||
|
@ -21,11 +26,11 @@ std::array<u8, ISPACE> code_flags;
|
||||||
// as well give up its time slice immediately, after executing once.
|
// as well give up its time slice immediately, after executing once.
|
||||||
|
|
||||||
// Max signature length is 6. A 0 in a signature is ignored.
|
// Max signature length is 6. A 0 in a signature is ignored.
|
||||||
#define NUM_IDLE_SIGS 8
|
constexpr size_t NUM_IDLE_SIGS = 8;
|
||||||
#define MAX_IDLE_SIG_SIZE 6
|
constexpr size_t MAX_IDLE_SIG_SIZE = 6;
|
||||||
|
|
||||||
// 0xFFFF means ignore.
|
// 0xFFFF means ignore.
|
||||||
const u16 idle_skip_sigs[NUM_IDLE_SIGS][MAX_IDLE_SIG_SIZE + 1] = {
|
constexpr u16 idle_skip_sigs[NUM_IDLE_SIGS][MAX_IDLE_SIG_SIZE + 1] = {
|
||||||
// From AX:
|
// From AX:
|
||||||
{0x26fc, // LRS $30, @DMBH
|
{0x26fc, // LRS $30, @DMBH
|
||||||
0x02c0, 0x8000, // ANDCF $30, #0x8000
|
0x02c0, 0x8000, // ANDCF $30, #0x8000
|
||||||
|
@ -62,12 +67,12 @@ const u16 idle_skip_sigs[NUM_IDLE_SIGS][MAX_IDLE_SIG_SIZE + 1] = {
|
||||||
0x0295, 0xFFFF, // JZ 0x????
|
0x0295, 0xFFFF, // JZ 0x????
|
||||||
0, 0}};
|
0, 0}};
|
||||||
|
|
||||||
static void Reset()
|
void Reset()
|
||||||
{
|
{
|
||||||
code_flags.fill(0);
|
code_flags.fill(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void AnalyzeRange(u16 start_addr, u16 end_addr)
|
void AnalyzeRange(u16 start_addr, u16 end_addr)
|
||||||
{
|
{
|
||||||
// First we run an extremely simplified version of a disassembler to find
|
// First we run an extremely simplified version of a disassembler to find
|
||||||
// where all instructions start.
|
// where all instructions start.
|
||||||
|
@ -146,6 +151,7 @@ static void AnalyzeRange(u16 start_addr, u16 end_addr)
|
||||||
}
|
}
|
||||||
INFO_LOG(DSPLLE, "Finished analysis.");
|
INFO_LOG(DSPLLE, "Finished analysis.");
|
||||||
}
|
}
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
void Analyze()
|
void Analyze()
|
||||||
{
|
{
|
||||||
|
@ -154,4 +160,9 @@ void Analyze()
|
||||||
AnalyzeRange(0x8000, 0x9000); // IROM
|
AnalyzeRange(0x8000, 0x9000); // IROM
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
u8 GetCodeFlags(u16 address)
|
||||||
|
{
|
||||||
|
return code_flags[address];
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace DSPAnalyzer
|
||||||
|
|
|
@ -4,14 +4,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
// Basic code analysis.
|
// Basic code analysis.
|
||||||
namespace DSPAnalyzer
|
namespace DSPAnalyzer
|
||||||
{
|
{
|
||||||
#define ISPACE 65536
|
|
||||||
|
|
||||||
// Useful things to detect:
|
// Useful things to detect:
|
||||||
// * Loop endpoints - so that we can avoid checking for loops every cycle.
|
// * Loop endpoints - so that we can avoid checking for loops every cycle.
|
||||||
|
|
||||||
|
@ -25,11 +22,6 @@ enum
|
||||||
CODE_CHECK_INT = 32,
|
CODE_CHECK_INT = 32,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Easy to query array covering the whole of instruction memory.
|
|
||||||
// Just index by address.
|
|
||||||
// This one will be helpful for debuggers and jits.
|
|
||||||
extern std::array<u8, ISPACE> code_flags;
|
|
||||||
|
|
||||||
// This one should be called every time IRAM changes - which is basically
|
// This one should be called every time IRAM changes - which is basically
|
||||||
// every time that a new ucode gets uploaded, and never else. At that point,
|
// every time that a new ucode gets uploaded, and never else. At that point,
|
||||||
// we can do as much static analysis as we want - but we should always throw
|
// we can do as much static analysis as we want - but we should always throw
|
||||||
|
@ -38,4 +30,7 @@ extern std::array<u8, ISPACE> code_flags;
|
||||||
// some pretty expensive analysis if necessary.
|
// some pretty expensive analysis if necessary.
|
||||||
void Analyze();
|
void Analyze();
|
||||||
|
|
||||||
} // namespace
|
// Retrieves the flags set during analysis for code in memory.
|
||||||
|
u8 GetCodeFlags(u16 address);
|
||||||
|
|
||||||
|
} // namespace DSPAnalyzer
|
||||||
|
|
|
@ -100,7 +100,7 @@ void Step()
|
||||||
u16 opc = dsp_fetch_code();
|
u16 opc = dsp_fetch_code();
|
||||||
ExecuteInstruction(UDSPInstruction(opc));
|
ExecuteInstruction(UDSPInstruction(opc));
|
||||||
|
|
||||||
if (DSPAnalyzer::code_flags[static_cast<u16>(g_dsp.pc - 1u)] & DSPAnalyzer::CODE_LOOP_END)
|
if (DSPAnalyzer::GetCodeFlags(static_cast<u16>(g_dsp.pc - 1u)) & DSPAnalyzer::CODE_LOOP_END)
|
||||||
HandleLoop();
|
HandleLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +158,7 @@ int RunCyclesDebug(int cycles)
|
||||||
return cycles;
|
return cycles;
|
||||||
}
|
}
|
||||||
// Idle skipping.
|
// Idle skipping.
|
||||||
if (DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP)
|
if (DSPAnalyzer::GetCodeFlags(g_dsp.pc) & DSPAnalyzer::CODE_IDLE_SKIP)
|
||||||
return 0;
|
return 0;
|
||||||
Step();
|
Step();
|
||||||
cycles--;
|
cycles--;
|
||||||
|
@ -208,7 +208,7 @@ int RunCycles(int cycles)
|
||||||
if (g_dsp.cr & CR_HALT)
|
if (g_dsp.cr & CR_HALT)
|
||||||
return 0;
|
return 0;
|
||||||
// Idle skipping.
|
// Idle skipping.
|
||||||
if (DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP)
|
if (DSPAnalyzer::GetCodeFlags(g_dsp.pc) & DSPAnalyzer::CODE_IDLE_SKIP)
|
||||||
return 0;
|
return 0;
|
||||||
Step();
|
Step();
|
||||||
cycles--;
|
cycles--;
|
||||||
|
|
|
@ -92,11 +92,9 @@ void DSPEmitter::checkExceptions(u32 retval)
|
||||||
|
|
||||||
bool DSPEmitter::FlagsNeeded()
|
bool DSPEmitter::FlagsNeeded()
|
||||||
{
|
{
|
||||||
if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) ||
|
const u8 flags = DSPAnalyzer::GetCodeFlags(compilePC);
|
||||||
(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR))
|
|
||||||
return true;
|
return !(flags & DSPAnalyzer::CODE_START_OF_INST) || (flags & DSPAnalyzer::CODE_UPDATE_SR);
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPEmitter::FallBackToInterpreter(UDSPInstruction inst)
|
void DSPEmitter::FallBackToInterpreter(UDSPInstruction inst)
|
||||||
|
@ -217,7 +215,7 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||||
|
|
||||||
while (compilePC < start_addr + MAX_BLOCK_SIZE)
|
while (compilePC < start_addr + MAX_BLOCK_SIZE)
|
||||||
{
|
{
|
||||||
if (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_CHECK_INT)
|
if (DSPAnalyzer::GetCodeFlags(compilePC) & DSPAnalyzer::CODE_CHECK_INT)
|
||||||
checkExceptions(blockSize[start_addr]);
|
checkExceptions(blockSize[start_addr]);
|
||||||
|
|
||||||
UDSPInstruction inst = dsp_imem_read(compilePC);
|
UDSPInstruction inst = dsp_imem_read(compilePC);
|
||||||
|
@ -235,7 +233,7 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||||
|
|
||||||
// Handle loop condition, only if current instruction was flagged as a loop destination
|
// Handle loop condition, only if current instruction was flagged as a loop destination
|
||||||
// by the analyzer.
|
// by the analyzer.
|
||||||
if (DSPAnalyzer::code_flags[static_cast<u16>(compilePC - 1u)] & DSPAnalyzer::CODE_LOOP_END)
|
if (DSPAnalyzer::GetCodeFlags(static_cast<u16>(compilePC - 1u)) & DSPAnalyzer::CODE_LOOP_END)
|
||||||
{
|
{
|
||||||
MOVZX(32, 16, EAX, M(&(g_dsp.r.st[2])));
|
MOVZX(32, 16, EAX, M(&(g_dsp.r.st[2])));
|
||||||
TEST(32, R(EAX), R(EAX));
|
TEST(32, R(EAX), R(EAX));
|
||||||
|
@ -256,7 +254,8 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||||
DSPJitRegCache c(gpr);
|
DSPJitRegCache c(gpr);
|
||||||
HandleLoop();
|
HandleLoop();
|
||||||
gpr.SaveRegs();
|
gpr.SaveRegs();
|
||||||
if (!DSPHost::OnThread() && DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
|
if (!DSPHost::OnThread() &&
|
||||||
|
DSPAnalyzer::GetCodeFlags(start_addr) & DSPAnalyzer::CODE_IDLE_SKIP)
|
||||||
{
|
{
|
||||||
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
|
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
|
||||||
}
|
}
|
||||||
|
@ -291,7 +290,7 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||||
// don't update g_dsp.pc -- the branch insn already did
|
// don't update g_dsp.pc -- the branch insn already did
|
||||||
gpr.SaveRegs();
|
gpr.SaveRegs();
|
||||||
if (!DSPHost::OnThread() &&
|
if (!DSPHost::OnThread() &&
|
||||||
DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
|
DSPAnalyzer::GetCodeFlags(start_addr) & DSPAnalyzer::CODE_IDLE_SKIP)
|
||||||
{
|
{
|
||||||
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
|
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
|
||||||
}
|
}
|
||||||
|
@ -308,7 +307,7 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// End the block if we're before an idle skip address
|
// End the block if we're before an idle skip address
|
||||||
if (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_IDLE_SKIP)
|
if (DSPAnalyzer::GetCodeFlags(compilePC) & DSPAnalyzer::CODE_IDLE_SKIP)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -354,7 +353,7 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
gpr.SaveRegs();
|
gpr.SaveRegs();
|
||||||
if (!DSPHost::OnThread() && DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
|
if (!DSPHost::OnThread() && DSPAnalyzer::GetCodeFlags(start_addr) & DSPAnalyzer::CODE_IDLE_SKIP)
|
||||||
{
|
{
|
||||||
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
|
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ static void WriteBranchExit(DSPEmitter& emitter)
|
||||||
{
|
{
|
||||||
DSPJitRegCache c(emitter.gpr);
|
DSPJitRegCache c(emitter.gpr);
|
||||||
emitter.gpr.SaveRegs();
|
emitter.gpr.SaveRegs();
|
||||||
if (DSPAnalyzer::code_flags[emitter.startAddr] & DSPAnalyzer::CODE_IDLE_SKIP)
|
if (DSPAnalyzer::GetCodeFlags(emitter.startAddr) & DSPAnalyzer::CODE_IDLE_SKIP)
|
||||||
{
|
{
|
||||||
emitter.MOV(16, R(EAX), Imm16(0x1000));
|
emitter.MOV(16, R(EAX), Imm16(0x1000));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue