melonDS/src/ARMJIT.cpp

247 lines
6.2 KiB
C++
Raw Normal View History

#include "ARMJIT.h"
2019-06-25 15:09:27 +00:00
#include <string.h>
2019-07-14 02:33:36 +00:00
#include "Config.h"
#include "ARMJIT_x64/ARMJIT_Compiler.h"
namespace ARMJIT
{
Compiler* compiler;
BlockCache cache;
#define DUP2(x) x, x
static ptrdiff_t JIT_MEM[2][32] = {
//arm9
{
/* 0X*/ DUP2(offsetof(BlockCache, ARM9_ITCM)),
/* 1X*/ DUP2(offsetof(BlockCache, ARM9_ITCM)), // mirror
/* 2X*/ DUP2(offsetof(BlockCache, MainRAM)),
/* 3X*/ DUP2(offsetof(BlockCache, SWRAM)),
/* 4X*/ DUP2(-1),
/* 5X*/ DUP2(-1),
/* 6X*/ -1,
offsetof(BlockCache, ARM9_LCDC), // Plain ARM9-CPU Access (LCDC mode) (max 656KB)
/* 7X*/ DUP2(-1),
/* 8X*/ DUP2(-1),
/* 9X*/ DUP2(-1),
/* AX*/ DUP2(-1),
/* BX*/ DUP2(-1),
/* CX*/ DUP2(-1),
/* DX*/ DUP2(-1),
/* EX*/ DUP2(-1),
/* FX*/ DUP2(offsetof(BlockCache, ARM9_BIOS))
},
//arm7
{
/* 0X*/ DUP2(offsetof(BlockCache, ARM7_BIOS)),
/* 1X*/ DUP2(-1),
/* 2X*/ DUP2(offsetof(BlockCache, MainRAM)),
/* 3X*/ offsetof(BlockCache, SWRAM),
offsetof(BlockCache, ARM7_WRAM),
/* 4X*/ DUP2(-1),
/* 5X*/ DUP2(-1),
/* 6X*/ DUP2(offsetof(BlockCache, ARM7_WVRAM)), /* contrary to Gbatek, melonDS and itself,
DeSmuME doesn't mirror the 64 MB region at 0x6800000 */
/* 7X*/ DUP2(-1),
/* 8X*/ DUP2(-1),
/* 9X*/ DUP2(-1),
/* AX*/ DUP2(-1),
/* BX*/ DUP2(-1),
/* CX*/ DUP2(-1),
/* DX*/ DUP2(-1),
/* EX*/ DUP2(-1),
/* FX*/ DUP2(-1)
}
};
static u32 JIT_MASK[2][32] = {
//arm9
{
/* 0X*/ DUP2(0x00007FFF),
/* 1X*/ DUP2(0x00007FFF),
/* 2X*/ DUP2(0x003FFFFF),
/* 3X*/ DUP2(0x00007FFF),
/* 4X*/ DUP2(0x00000000),
/* 5X*/ DUP2(0x00000000),
/* 6X*/ 0x00000000,
0x000FFFFF,
/* 7X*/ DUP2(0x00000000),
/* 8X*/ DUP2(0x00000000),
/* 9X*/ DUP2(0x00000000),
/* AX*/ DUP2(0x00000000),
/* BX*/ DUP2(0x00000000),
/* CX*/ DUP2(0x00000000),
/* DX*/ DUP2(0x00000000),
/* EX*/ DUP2(0x00000000),
/* FX*/ DUP2(0x00007FFF)
},
//arm7
{
/* 0X*/ DUP2(0x00003FFF),
/* 1X*/ DUP2(0x00000000),
/* 2X*/ DUP2(0x003FFFFF),
/* 3X*/ 0x00007FFF,
0x0000FFFF,
/* 4X*/ 0x00000000,
0x0000FFFF,
/* 5X*/ DUP2(0x00000000),
/* 6X*/ DUP2(0x0003FFFF),
/* 7X*/ DUP2(0x00000000),
/* 8X*/ DUP2(0x00000000),
/* 9X*/ DUP2(0x00000000),
/* AX*/ DUP2(0x00000000),
/* BX*/ DUP2(0x00000000),
/* CX*/ DUP2(0x00000000),
/* DX*/ DUP2(0x00000000),
/* EX*/ DUP2(0x00000000),
/* FX*/ DUP2(0x00000000)
}
};
#undef DUP2
void Init()
{
memset(&cache, 0, sizeof(BlockCache));
for (int i = 0; i < 0x2000; i++)
cache.AddrMapping9[i] = JIT_MEM[0][i >> 8] == -1 ? NULL :
(CompiledBlock*)((u8*)&cache + JIT_MEM[0][i >> 8])
+ (((i << 15) & JIT_MASK[0][i >> 8]) >> 1);
for (int i = 0; i < 0x4000; i++)
cache.AddrMapping7[i] = JIT_MEM[1][i >> 9] == -1 ? NULL :
(CompiledBlock*)((u8*)&cache + JIT_MEM[1][i >> 9])
+ (((i << 14) & JIT_MASK[1][i >> 9]) >> 1);
compiler = new Compiler();
}
void DeInit()
{
delete compiler;
}
void floodFillSetFlags(FetchedInstr instrs[], int start, u8 flags)
{
for (int j = start; j >= 0; j--)
{
u8 match = instrs[j].Info.WriteFlags & flags;
u8 matchMaybe = (instrs[j].Info.WriteFlags >> 4) & flags;
if (matchMaybe) // writes flags maybe
instrs[j].SetFlags |= matchMaybe;
if (match)
{
instrs[j].SetFlags |= match;
flags &= ~match;
if (!flags)
return;
}
}
}
2019-07-11 14:22:47 +00:00
CompiledBlock CompileBlock(ARM* cpu)
{
bool thumb = cpu->CPSR & 0x20;
2019-07-14 02:33:36 +00:00
if (Config::JIT_MaxBlockSize < 1)
Config::JIT_MaxBlockSize = 1;
if (Config::JIT_MaxBlockSize > 32)
Config::JIT_MaxBlockSize = 32;
FetchedInstr instrs[Config::JIT_MaxBlockSize];
int i = 0;
2019-07-14 02:33:36 +00:00
u32 blockAddr = cpu->R[15] - (thumb ? 2 : 4);
u32 r15 = cpu->R[15];
cpu->FillPipeline();
u32 nextInstr[2] = {cpu->NextInstr[0], cpu->NextInstr[1]};
u32 nextInstrAddr[2] = {blockAddr, r15};
do
{
r15 += thumb ? 2 : 4;
2019-08-25 11:06:27 +00:00
instrs[i].SetFlags = 0;
instrs[i].Instr = nextInstr[0];
instrs[i].NextInstr[0] = nextInstr[0] = nextInstr[1];
instrs[i].Addr = nextInstrAddr[0];
nextInstrAddr[0] = nextInstrAddr[1];
nextInstrAddr[1] = r15;
if (cpu->Num == 0)
{
ARMv5* cpuv5 = (ARMv5*)cpu;
if (thumb && r15 & 0x2)
{
nextInstr[1] >>= 16;
instrs[i].CodeCycles = 0;
}
else
{
nextInstr[1] = cpuv5->CodeRead32(r15, false);
instrs[i].CodeCycles = cpu->CodeCycles;
}
}
else
{
ARMv4* cpuv4 = (ARMv4*)cpu;
if (thumb)
nextInstr[1] = cpuv4->CodeRead16(r15);
else
nextInstr[1] = cpuv4->CodeRead32(r15);
instrs[i].CodeCycles = cpu->CodeCycles;
}
instrs[i].NextInstr[1] = nextInstr[1];
instrs[i].Info = ARMInstrInfo::Decode(thumb, cpu->Num, instrs[i].Instr);
if (thumb && instrs[i].Info.Kind == ARMInstrInfo::tk_BL_LONG_2 && i > 0
&& instrs[i - 1].Info.Kind == ARMInstrInfo::tk_BL_LONG_1)
{
instrs[i - 1].Info.Kind = ARMInstrInfo::tk_BL_LONG;
instrs[i - 1].Instr = (instrs[i - 1].Instr & 0xFFFF) | (instrs[i].Instr << 16);
instrs[i - 1].Info.DstRegs = 0xC000;
instrs[i - 1].Info.SrcRegs = 0;
instrs[i - 1].Info.EndBlock = true;
i--;
}
i++;
bool canCompile = compiler->CanCompile(thumb, instrs[i - 1].Info.Kind);
if (instrs[i - 1].Info.ReadFlags != 0 || !canCompile)
floodFillSetFlags(instrs, i - 2, canCompile ? instrs[i - 1].Info.ReadFlags : 0xF);
} while(!instrs[i - 1].Info.EndBlock && i < Config::JIT_MaxBlockSize);
floodFillSetFlags(instrs, i - 1, 0xF);
CompiledBlock block = compiler->CompileBlock(cpu, instrs, i);
if (cpu->Num == 0)
InsertBlock<0>(blockAddr, block);
else
InsertBlock<1>(blockAddr, block);
2019-07-11 14:22:47 +00:00
return block;
}
2019-07-14 02:33:36 +00:00
void InvalidateBlockCache()
2019-06-25 15:09:27 +00:00
{
printf("Resetting JIT block cache...\n");
2019-06-25 15:09:27 +00:00
memset(cache.MainRAM, 0, sizeof(cache.MainRAM));
memset(cache.SWRAM, 0, sizeof(cache.SWRAM));
memset(cache.ARM9_BIOS, 0, sizeof(cache.ARM9_BIOS));
memset(cache.ARM9_ITCM, 0, sizeof(cache.ARM9_ITCM));
memset(cache.ARM9_LCDC, 0, sizeof(cache.ARM9_LCDC));
memset(cache.ARM7_BIOS, 0, sizeof(cache.ARM7_BIOS));
memset(cache.ARM7_WRAM, 0, sizeof(cache.ARM7_WRAM));
memset(cache.ARM7_WVRAM, 0, sizeof(cache.ARM7_WVRAM));
2019-07-14 02:33:36 +00:00
compiler->Reset();
2019-06-25 15:09:27 +00:00
}
}