reconcile DSi and JIT, fastmem for x64 and Windows
This commit is contained in:
parent
ea6d03581b
commit
c5381d2911
23
src/ARM.cpp
23
src/ARM.cpp
|
@ -21,12 +21,15 @@
|
|||
#include "DSi.h"
|
||||
#include "ARM.h"
|
||||
#include "ARMInterpreter.h"
|
||||
#include "ARMJIT.h"
|
||||
#include "Config.h"
|
||||
#include "AREngine.h"
|
||||
#include "ARMJIT.h"
|
||||
#include "Config.h"
|
||||
|
||||
#ifdef JIT_ENABLED
|
||||
#include "ARMJIT.h"
|
||||
#include "ARMJIT_Memory.h"
|
||||
#endif
|
||||
|
||||
// instruction timing notes
|
||||
//
|
||||
|
@ -109,6 +112,12 @@ void ARM::Reset()
|
|||
|
||||
CodeMem.Mem = NULL;
|
||||
|
||||
#ifdef JIT_ENABLED
|
||||
FastBlockLookup = NULL;
|
||||
FastBlockLookupStart = 0;
|
||||
FastBlockLookupSize = 0;
|
||||
#endif
|
||||
|
||||
// zorp
|
||||
JumpTo(ExceptionBase);
|
||||
}
|
||||
|
@ -752,6 +761,12 @@ void ARMv4::Execute()
|
|||
|
||||
if (Halted == 2)
|
||||
Halted = 0;
|
||||
|
||||
if (Halted == 4)
|
||||
{
|
||||
DSi::SoftReset();
|
||||
Halted = 2;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef JIT_ENABLED
|
||||
|
@ -820,6 +835,12 @@ void ARMv4::ExecuteJIT()
|
|||
|
||||
if (Halted == 2)
|
||||
Halted = 0;
|
||||
|
||||
if (Halted == 4)
|
||||
{
|
||||
DSi::SoftReset();
|
||||
Halted = 2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ public:
|
|||
NDS::MemRegion CodeMem;
|
||||
|
||||
#ifdef JIT_ENABLED
|
||||
u32 FastBlockLookupStart = 0, FastBlockLookupSize = 0;
|
||||
u32 FastBlockLookupStart, FastBlockLookupSize;
|
||||
u64* FastBlockLookup;
|
||||
#endif
|
||||
|
||||
|
|
271
src/ARMJIT.cpp
271
src/ARMJIT.cpp
|
@ -18,6 +18,7 @@
|
|||
#include "ARMInterpreter_Branch.h"
|
||||
#include "ARMInterpreter.h"
|
||||
|
||||
#include "DSi.h"
|
||||
#include "GPU.h"
|
||||
#include "GPU3D.h"
|
||||
#include "SPU.h"
|
||||
|
@ -38,25 +39,35 @@ namespace ARMJIT
|
|||
Compiler* JITCompiler;
|
||||
|
||||
AddressRange CodeIndexITCM[ITCMPhysicalSize / 512];
|
||||
AddressRange CodeIndexMainRAM[NDS::MainRAMSize / 512];
|
||||
AddressRange CodeIndexMainRAM[NDS::MainRAMMaxSize / 512];
|
||||
AddressRange CodeIndexSWRAM[NDS::SharedWRAMSize / 512];
|
||||
AddressRange CodeIndexVRAM[0x100000 / 512];
|
||||
AddressRange CodeIndexARM9BIOS[sizeof(NDS::ARM9BIOS) / 512];
|
||||
AddressRange CodeIndexARM7BIOS[sizeof(NDS::ARM7BIOS) / 512];
|
||||
AddressRange CodeIndexARM7WRAM[NDS::ARM7WRAMSize / 512];
|
||||
AddressRange CodeIndexARM7WVRAM[0x40000 / 512];
|
||||
AddressRange CodeIndexBIOS9DSi[0x10000 / 512];
|
||||
AddressRange CodeIndexBIOS7DSi[0x10000 / 512];
|
||||
AddressRange CodeIndexNWRAM_A[DSi::NWRAMSize / 512];
|
||||
AddressRange CodeIndexNWRAM_B[DSi::NWRAMSize / 512];
|
||||
AddressRange CodeIndexNWRAM_C[DSi::NWRAMSize / 512];
|
||||
|
||||
std::unordered_map<u32, JitBlock*> JitBlocks9;
|
||||
std::unordered_map<u32, JitBlock*> JitBlocks7;
|
||||
|
||||
u64 FastBlockLookupITCM[ITCMPhysicalSize / 2];
|
||||
u64 FastBlockLookupMainRAM[NDS::MainRAMSize / 2];
|
||||
u64 FastBlockLookupMainRAM[NDS::MainRAMMaxSize / 2];
|
||||
u64 FastBlockLookupSWRAM[NDS::SharedWRAMSize / 2];
|
||||
u64 FastBlockLookupVRAM[0x100000 / 2];
|
||||
u64 FastBlockLookupARM9BIOS[sizeof(NDS::ARM9BIOS) / 2];
|
||||
u64 FastBlockLookupARM7BIOS[sizeof(NDS::ARM7BIOS) / 2];
|
||||
u64 FastBlockLookupARM7WRAM[NDS::ARM7WRAMSize / 2];
|
||||
u64 FastBlockLookupARM7WVRAM[0x40000 / 2];
|
||||
u64 FastBlockLookupBIOS9DSi[0x10000 / 2];
|
||||
u64 FastBlockLookupBIOS7DSi[0x10000 / 2];
|
||||
u64 FastBlockLookupNWRAM_A[DSi::NWRAMSize / 2];
|
||||
u64 FastBlockLookupNWRAM_B[DSi::NWRAMSize / 2];
|
||||
u64 FastBlockLookupNWRAM_C[DSi::NWRAMSize / 2];
|
||||
|
||||
const u32 CodeRegionSizes[ARMJIT_Memory::memregions_Count] =
|
||||
{
|
||||
|
@ -64,7 +75,7 @@ const u32 CodeRegionSizes[ARMJIT_Memory::memregions_Count] =
|
|||
ITCMPhysicalSize,
|
||||
0,
|
||||
sizeof(NDS::ARM9BIOS),
|
||||
NDS::MainRAMSize,
|
||||
NDS::MainRAMMaxSize,
|
||||
NDS::SharedWRAMSize,
|
||||
0,
|
||||
0x100000,
|
||||
|
@ -73,6 +84,11 @@ const u32 CodeRegionSizes[ARMJIT_Memory::memregions_Count] =
|
|||
0,
|
||||
0,
|
||||
0x40000,
|
||||
0x10000,
|
||||
0x10000,
|
||||
sizeof(DSi::NWRAM_A),
|
||||
sizeof(DSi::NWRAM_B),
|
||||
sizeof(DSi::NWRAM_C),
|
||||
};
|
||||
|
||||
AddressRange* const CodeMemRegions[ARMJIT_Memory::memregions_Count] =
|
||||
|
@ -90,6 +106,11 @@ AddressRange* const CodeMemRegions[ARMJIT_Memory::memregions_Count] =
|
|||
NULL,
|
||||
NULL,
|
||||
CodeIndexARM7WVRAM,
|
||||
CodeIndexBIOS9DSi,
|
||||
CodeIndexBIOS7DSi,
|
||||
CodeIndexNWRAM_A,
|
||||
CodeIndexNWRAM_B,
|
||||
CodeIndexNWRAM_C
|
||||
};
|
||||
|
||||
u64* const FastBlockLookupRegions[ARMJIT_Memory::memregions_Count] =
|
||||
|
@ -106,7 +127,12 @@ u64* const FastBlockLookupRegions[ARMJIT_Memory::memregions_Count] =
|
|||
FastBlockLookupARM7WRAM,
|
||||
NULL,
|
||||
NULL,
|
||||
FastBlockLookupARM7WVRAM
|
||||
FastBlockLookupARM7WVRAM,
|
||||
FastBlockLookupBIOS9DSi,
|
||||
FastBlockLookupBIOS7DSi,
|
||||
FastBlockLookupNWRAM_A,
|
||||
FastBlockLookupNWRAM_B,
|
||||
FastBlockLookupNWRAM_C
|
||||
};
|
||||
|
||||
u32 LocaliseCodeAddress(u32 num, u32 addr)
|
||||
|
@ -115,21 +141,14 @@ u32 LocaliseCodeAddress(u32 num, u32 addr)
|
|||
? ARMJIT_Memory::ClassifyAddress9(addr)
|
||||
: ARMJIT_Memory::ClassifyAddress7(addr);
|
||||
|
||||
u32 mappingStart, mappingSize, memoryOffset, memorySize;
|
||||
if (ARMJIT_Memory::GetRegionMapping(region, num, mappingStart,
|
||||
mappingSize, memoryOffset, memorySize)
|
||||
&& CodeMemRegions[region])
|
||||
{
|
||||
addr = ((addr - mappingStart) & (memorySize - 1)) + memoryOffset;
|
||||
addr |= (u32)region << 28;
|
||||
return addr;
|
||||
}
|
||||
if (CodeMemRegions[region])
|
||||
return ARMJIT_Memory::LocaliseAddress(region, num, addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
TinyVector<u32> InvalidLiterals;
|
||||
|
||||
template <typename T>
|
||||
template <typename T, int ConsoleType>
|
||||
T SlowRead9(u32 addr, ARMv5* cpu)
|
||||
{
|
||||
u32 offset = addr & 0x3;
|
||||
|
@ -141,11 +160,11 @@ T SlowRead9(u32 addr, ARMv5* cpu)
|
|||
else if (addr >= cpu->DTCMBase && addr < (cpu->DTCMBase + cpu->DTCMSize))
|
||||
val = *(T*)&cpu->DTCM[(addr - cpu->DTCMBase) & 0x3FFF];
|
||||
else if (std::is_same<T, u32>::value)
|
||||
val = NDS::ARM9Read32(addr);
|
||||
val = (ConsoleType == 0 ? NDS::ARM9Read32 : DSi::ARM9Read32)(addr);
|
||||
else if (std::is_same<T, u16>::value)
|
||||
val = NDS::ARM9Read16(addr);
|
||||
val = (ConsoleType == 0 ? NDS::ARM9Read16 : DSi::ARM9Read16)(addr);
|
||||
else
|
||||
val = NDS::ARM9Read8(addr);
|
||||
val = (ConsoleType == 0 ? NDS::ARM9Read8 : DSi::ARM9Read8)(addr);
|
||||
|
||||
if (std::is_same<T, u32>::value)
|
||||
return ROR(val, offset << 3);
|
||||
|
@ -153,7 +172,7 @@ T SlowRead9(u32 addr, ARMv5* cpu)
|
|||
return val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename T, int ConsoleType>
|
||||
void SlowWrite9(u32 addr, ARMv5* cpu, T val)
|
||||
{
|
||||
addr &= ~(sizeof(T) - 1);
|
||||
|
@ -169,27 +188,19 @@ void SlowWrite9(u32 addr, ARMv5* cpu, T val)
|
|||
}
|
||||
else if (std::is_same<T, u32>::value)
|
||||
{
|
||||
NDS::ARM9Write32(addr, val);
|
||||
(ConsoleType == 0 ? NDS::ARM9Write32 : DSi::ARM9Write32)(addr, val);
|
||||
}
|
||||
else if (std::is_same<T, u16>::value)
|
||||
{
|
||||
NDS::ARM9Write16(addr, val);
|
||||
(ConsoleType == 0 ? NDS::ARM9Write16 : DSi::ARM9Write16)(addr, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
NDS::ARM9Write8(addr, val);
|
||||
(ConsoleType == 0 ? NDS::ARM9Write8 : DSi::ARM9Write8)(addr, val);
|
||||
}
|
||||
}
|
||||
|
||||
template void SlowWrite9<u32>(u32, ARMv5*, u32);
|
||||
template void SlowWrite9<u16>(u32, ARMv5*, u16);
|
||||
template void SlowWrite9<u8>(u32, ARMv5*, u8);
|
||||
|
||||
template u32 SlowRead9<u32>(u32, ARMv5*);
|
||||
template u16 SlowRead9<u16>(u32, ARMv5*);
|
||||
template u8 SlowRead9<u8>(u32, ARMv5*);
|
||||
|
||||
template <typename T>
|
||||
template <typename T, int ConsoleType>
|
||||
T SlowRead7(u32 addr)
|
||||
{
|
||||
u32 offset = addr & 0x3;
|
||||
|
@ -197,11 +208,11 @@ T SlowRead7(u32 addr)
|
|||
|
||||
T val;
|
||||
if (std::is_same<T, u32>::value)
|
||||
val = NDS::ARM7Read32(addr);
|
||||
val = (ConsoleType == 0 ? NDS::ARM7Read32 : DSi::ARM7Read32)(addr);
|
||||
else if (std::is_same<T, u16>::value)
|
||||
val = NDS::ARM7Read16(addr);
|
||||
val = (ConsoleType == 0 ? NDS::ARM7Read16 : DSi::ARM7Read16)(addr);
|
||||
else
|
||||
val = NDS::ARM7Read8(addr);
|
||||
val = (ConsoleType == 0 ? NDS::ARM7Read8 : DSi::ARM7Read8)(addr);
|
||||
|
||||
if (std::is_same<T, u32>::value)
|
||||
return ROR(val, offset << 3);
|
||||
|
@ -209,67 +220,71 @@ T SlowRead7(u32 addr)
|
|||
return val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename T, int ConsoleType>
|
||||
void SlowWrite7(u32 addr, T val)
|
||||
{
|
||||
addr &= ~(sizeof(T) - 1);
|
||||
|
||||
if (std::is_same<T, u32>::value)
|
||||
NDS::ARM7Write32(addr, val);
|
||||
(ConsoleType == 0 ? NDS::ARM7Write32 : DSi::ARM7Write32)(addr, val);
|
||||
else if (std::is_same<T, u16>::value)
|
||||
NDS::ARM7Write16(addr, val);
|
||||
(ConsoleType == 0 ? NDS::ARM7Write16 : DSi::ARM7Write16)(addr, val);
|
||||
else
|
||||
NDS::ARM7Write8(addr, val);
|
||||
(ConsoleType == 0 ? NDS::ARM7Write8 : DSi::ARM7Write8)(addr, val);
|
||||
}
|
||||
|
||||
template <bool PreInc, bool Write>
|
||||
template <bool Write, int ConsoleType>
|
||||
void SlowBlockTransfer9(u32 addr, u64* data, u32 num, ARMv5* cpu)
|
||||
{
|
||||
addr &= ~0x3;
|
||||
if (PreInc)
|
||||
addr += 4;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
if (Write)
|
||||
SlowWrite9<u32>(addr, cpu, data[i]);
|
||||
SlowWrite9<u32, ConsoleType>(addr, cpu, data[i]);
|
||||
else
|
||||
data[i] = SlowRead9<u32>(addr, cpu);
|
||||
data[i] = SlowRead9<u32, ConsoleType>(addr, cpu);
|
||||
addr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
template <bool PreInc, bool Write>
|
||||
template <bool Write, int ConsoleType>
|
||||
void SlowBlockTransfer7(u32 addr, u64* data, u32 num)
|
||||
{
|
||||
addr &= ~0x3;
|
||||
if (PreInc)
|
||||
addr += 4;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
if (Write)
|
||||
SlowWrite7<u32>(addr, data[i]);
|
||||
SlowWrite7<u32, ConsoleType>(addr, data[i]);
|
||||
else
|
||||
data[i] = SlowRead7<u32>(addr);
|
||||
data[i] = SlowRead7<u32, ConsoleType>(addr);
|
||||
addr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
template void SlowWrite7<u32>(u32, u32);
|
||||
template void SlowWrite7<u16>(u32, u16);
|
||||
template void SlowWrite7<u8>(u32, u8);
|
||||
#define INSTANTIATE_SLOWMEM(consoleType) \
|
||||
template void SlowWrite9<u32, consoleType>(u32, ARMv5*, u32); \
|
||||
template void SlowWrite9<u16, consoleType>(u32, ARMv5*, u16); \
|
||||
template void SlowWrite9<u8, consoleType>(u32, ARMv5*, u8); \
|
||||
\
|
||||
template u32 SlowRead9<u32, consoleType>(u32, ARMv5*); \
|
||||
template u16 SlowRead9<u16, consoleType>(u32, ARMv5*); \
|
||||
template u8 SlowRead9<u8, consoleType>(u32, ARMv5*); \
|
||||
\
|
||||
template void SlowWrite7<u32, consoleType>(u32, u32); \
|
||||
template void SlowWrite7<u16, consoleType>(u32, u16); \
|
||||
template void SlowWrite7<u8, consoleType>(u32, u8); \
|
||||
\
|
||||
template u32 SlowRead7<u32, consoleType>(u32); \
|
||||
template u16 SlowRead7<u16, consoleType>(u32); \
|
||||
template u8 SlowRead7<u8, consoleType>(u32); \
|
||||
\
|
||||
template void SlowBlockTransfer9<false, consoleType>(u32, u64*, u32, ARMv5*); \
|
||||
template void SlowBlockTransfer9<true, consoleType>(u32, u64*, u32, ARMv5*); \
|
||||
template void SlowBlockTransfer7<false, consoleType>(u32 addr, u64* data, u32 num); \
|
||||
template void SlowBlockTransfer7<true, consoleType>(u32 addr, u64* data, u32 num); \
|
||||
|
||||
template u32 SlowRead7<u32>(u32);
|
||||
template u16 SlowRead7<u16>(u32);
|
||||
template u8 SlowRead7<u8>(u32);
|
||||
|
||||
template void SlowBlockTransfer9<false, false>(u32, u64*, u32, ARMv5*);
|
||||
template void SlowBlockTransfer9<false, true>(u32, u64*, u32, ARMv5*);
|
||||
template void SlowBlockTransfer9<true, false>(u32, u64*, u32, ARMv5*);
|
||||
template void SlowBlockTransfer9<true, true>(u32, u64*, u32, ARMv5*);
|
||||
template void SlowBlockTransfer7<false, false>(u32 addr, u64* data, u32 num);
|
||||
template void SlowBlockTransfer7<false, true>(u32 addr, u64* data, u32 num);
|
||||
template void SlowBlockTransfer7<true, false>(u32 addr, u64* data, u32 num);
|
||||
template void SlowBlockTransfer7<true, true>(u32 addr, u64* data, u32 num);
|
||||
INSTANTIATE_SLOWMEM(0)
|
||||
INSTANTIATE_SLOWMEM(1)
|
||||
|
||||
template <typename K, typename V, int Size, V InvalidValue>
|
||||
struct UnreliableHashTable
|
||||
|
@ -616,6 +631,12 @@ void CompileBlock(ARM* cpu)
|
|||
|
||||
u32 blockAddr = cpu->R[15] - (thumb ? 2 : 4);
|
||||
|
||||
u32 localAddr = LocaliseCodeAddress(cpu->Num, blockAddr);
|
||||
if (!localAddr)
|
||||
{
|
||||
printf("trying to compile non executable code? %x\n", blockAddr);
|
||||
}
|
||||
|
||||
auto& map = cpu->Num == 0 ? JitBlocks9 : JitBlocks7;
|
||||
auto existingBlockIt = map.find(blockAddr);
|
||||
if (existingBlockIt != map.end())
|
||||
|
@ -623,18 +644,24 @@ void CompileBlock(ARM* cpu)
|
|||
// there's already a block, though it's not inside the fast map
|
||||
// could be that there are two blocks at the same physical addr
|
||||
// but different mirrors
|
||||
u32 localAddr = existingBlockIt->second->StartAddrLocal;
|
||||
u32 otherLocalAddr = existingBlockIt->second->StartAddrLocal;
|
||||
|
||||
u64* entry = &FastBlockLookupRegions[localAddr >> 28][localAddr & 0xFFFFFFF];
|
||||
*entry = ((u64)blockAddr | cpu->Num) << 32;
|
||||
*entry |= JITCompiler->SubEntryOffset(existingBlockIt->second->EntryPoint);
|
||||
return;
|
||||
}
|
||||
if (localAddr == otherLocalAddr)
|
||||
{
|
||||
JIT_DEBUGPRINT("switching out block %x %x %x\n", localAddr, blockAddr, existingBlockIt->second->StartAddr);
|
||||
|
||||
u32 localAddr = LocaliseCodeAddress(cpu->Num, blockAddr);
|
||||
if (!localAddr)
|
||||
{
|
||||
printf("trying to compile non executable code? %x\n", blockAddr);
|
||||
u64* entry = &FastBlockLookupRegions[localAddr >> 27][(localAddr & 0x7FFFFFF) / 2];
|
||||
*entry = ((u64)blockAddr | cpu->Num) << 32;
|
||||
*entry |= JITCompiler->SubEntryOffset(existingBlockIt->second->EntryPoint);
|
||||
return;
|
||||
}
|
||||
|
||||
// some memory has been remapped
|
||||
JitBlock* prevBlock = RestoreCandidates.Insert(existingBlockIt->second->InstrHash, existingBlockIt->second);
|
||||
if (prevBlock)
|
||||
delete prevBlock;
|
||||
|
||||
map.erase(existingBlockIt);
|
||||
}
|
||||
|
||||
FetchedInstr instrs[Config::JIT_MaxBlockSize];
|
||||
|
@ -655,7 +682,7 @@ void CompileBlock(ARM* cpu)
|
|||
u32 nextInstr[2] = {cpu->NextInstr[0], cpu->NextInstr[1]};
|
||||
u32 nextInstrAddr[2] = {blockAddr, r15};
|
||||
|
||||
JIT_DEBUGPRINT("start block %x %08x (%x)\n", blockAddr, cpu->CPSR, pseudoPhysicalAddr);
|
||||
JIT_DEBUGPRINT("start block %x %08x (%x)\n", blockAddr, cpu->CPSR, localAddr);
|
||||
|
||||
u32 lastSegmentStart = blockAddr;
|
||||
u32 lr;
|
||||
|
@ -678,7 +705,7 @@ void CompileBlock(ARM* cpu)
|
|||
instrValues[i] = instrs[i].Instr;
|
||||
|
||||
u32 translatedAddr = LocaliseCodeAddress(cpu->Num, instrs[i].Addr);
|
||||
assert(translatedAddr);
|
||||
assert(translatedAddr >> 27);
|
||||
u32 translatedAddrRounded = translatedAddr & ~0x1FF;
|
||||
if (i == 0 || translatedAddrRounded != addressRanges[numAddressRanges - 1])
|
||||
{
|
||||
|
@ -727,7 +754,10 @@ void CompileBlock(ARM* cpu)
|
|||
cpu->CurInstr = instrs[i].Instr;
|
||||
cpu->CodeCycles = instrs[i].CodeCycles;
|
||||
|
||||
if (instrs[i].Info.DstRegs & (1 << 14))
|
||||
if (instrs[i].Info.DstRegs & (1 << 14)
|
||||
|| (!thumb
|
||||
&& (instrs[i].Info.Kind == ARMInstrInfo::ak_MSR_IMM || instrs[i].Info.Kind == ARMInstrInfo::ak_MSR_REG)
|
||||
&& instrs[i].Instr & (1 << 16)))
|
||||
hasLink = false;
|
||||
|
||||
if (thumb)
|
||||
|
@ -792,7 +822,7 @@ void CompileBlock(ARM* cpu)
|
|||
i--;
|
||||
}
|
||||
|
||||
if (instrs[i].Info.Branches() && Config::JIT_BrancheOptimisations)
|
||||
if (instrs[i].Info.Branches() && Config::JIT_BranchOptimisations)
|
||||
{
|
||||
bool hasBranched = cpu->R[15] != r15;
|
||||
|
||||
|
@ -830,8 +860,6 @@ void CompileBlock(ARM* cpu)
|
|||
}
|
||||
else if (hasBranched && !isBackJump && i + 1 < Config::JIT_MaxBlockSize)
|
||||
{
|
||||
u32 targetLocalised = LocaliseCodeAddress(cpu->Num, target);
|
||||
|
||||
if (link)
|
||||
{
|
||||
lr = linkAddr;
|
||||
|
@ -927,6 +955,8 @@ void CompileBlock(ARM* cpu)
|
|||
FloodFillSetFlags(instrs, i - 1, 0xF);
|
||||
|
||||
block->EntryPoint = JITCompiler->CompileBlock(cpu, thumb, instrs, i);
|
||||
|
||||
JIT_DEBUGPRINT("block start %p\n", block->EntryPoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -940,12 +970,12 @@ void CompileBlock(ARM* cpu)
|
|||
assert(addressMasks[j] == block->AddressMasks()[j]);
|
||||
assert(addressMasks[j] != 0);
|
||||
|
||||
AddressRange* region = CodeMemRegions[addressRanges[j] >> 28];
|
||||
AddressRange* region = CodeMemRegions[addressRanges[j] >> 27];
|
||||
|
||||
if (!PageContainsCode(®ion[(addressRanges[j] & 0xFFFF000) / 512]))
|
||||
ARMJIT_Memory::SetCodeProtection(addressRanges[j] >> 28, addressRanges[j] & 0xFFFFFFF, true);
|
||||
if (!PageContainsCode(®ion[(addressRanges[j] & 0x7FFF000) / 512]))
|
||||
ARMJIT_Memory::SetCodeProtection(addressRanges[j] >> 27, addressRanges[j] & 0x7FFFFFF, true);
|
||||
|
||||
AddressRange* range = ®ion[(addressRanges[j] & 0xFFFFFFF) / 512];
|
||||
AddressRange* range = ®ion[(addressRanges[j] & 0x7FFFFFF) / 512];
|
||||
range->Code |= addressMasks[j];
|
||||
range->Blocks.Add(block);
|
||||
}
|
||||
|
@ -955,7 +985,7 @@ void CompileBlock(ARM* cpu)
|
|||
else
|
||||
JitBlocks7[blockAddr] = block;
|
||||
|
||||
u64* entry = &FastBlockLookupRegions[(localAddr >> 28)][(localAddr & 0xFFFFFFF) / 2];
|
||||
u64* entry = &FastBlockLookupRegions[(localAddr >> 27)][(localAddr & 0x7FFFFFF) / 2];
|
||||
*entry = ((u64)blockAddr | cpu->Num) << 32;
|
||||
*entry |= JITCompiler->SubEntryOffset(block->EntryPoint);
|
||||
}
|
||||
|
@ -964,8 +994,8 @@ void InvalidateByAddr(u32 localAddr)
|
|||
{
|
||||
JIT_DEBUGPRINT("invalidating by addr %x\n", localAddr);
|
||||
|
||||
AddressRange* region = CodeMemRegions[localAddr >> 28];
|
||||
AddressRange* range = ®ion[(localAddr & 0xFFFFFFF) / 512];
|
||||
AddressRange* region = CodeMemRegions[localAddr >> 27];
|
||||
AddressRange* range = ®ion[(localAddr & 0x7FFFFFF) / 512];
|
||||
u32 mask = 1 << ((localAddr & 0x1FF) / 16);
|
||||
|
||||
range->Code = 0;
|
||||
|
@ -994,9 +1024,9 @@ void InvalidateByAddr(u32 localAddr)
|
|||
range->Blocks.Remove(i);
|
||||
|
||||
if (range->Blocks.Length == 0
|
||||
&& !PageContainsCode(®ion[(localAddr & 0xFFFF000) / 512]))
|
||||
&& !PageContainsCode(®ion[(localAddr & 0x7FFF000) / 512]))
|
||||
{
|
||||
ARMJIT_Memory::SetCodeProtection(localAddr >> 28, localAddr & 0xFFFFFFF, false);
|
||||
ARMJIT_Memory::SetCodeProtection(localAddr >> 27, localAddr & 0x7FFFFFF, false);
|
||||
}
|
||||
|
||||
bool literalInvalidation = false;
|
||||
|
@ -1019,8 +1049,8 @@ void InvalidateByAddr(u32 localAddr)
|
|||
u32 addr = block->AddressRanges()[j];
|
||||
if ((addr / 512) != (localAddr / 512))
|
||||
{
|
||||
AddressRange* otherRegion = CodeMemRegions[addr >> 28];
|
||||
AddressRange* otherRange = &otherRegion[(addr & 0xFFFFFFF) / 512];
|
||||
AddressRange* otherRegion = CodeMemRegions[addr >> 27];
|
||||
AddressRange* otherRange = &otherRegion[(addr & 0x7FFFFFF) / 512];
|
||||
assert(otherRange != range);
|
||||
|
||||
bool removed = otherRange->Blocks.RemoveByValue(block);
|
||||
|
@ -1028,15 +1058,15 @@ void InvalidateByAddr(u32 localAddr)
|
|||
|
||||
if (otherRange->Blocks.Length == 0)
|
||||
{
|
||||
if (!PageContainsCode(&otherRegion[(addr & 0xFFFF000) / 512]))
|
||||
ARMJIT_Memory::SetCodeProtection(addr >> 28, addr & 0xFFFFFFF, false);
|
||||
if (!PageContainsCode(&otherRegion[(addr & 0x7FFF000) / 512]))
|
||||
ARMJIT_Memory::SetCodeProtection(addr >> 27, addr & 0x7FFFFFF, false);
|
||||
|
||||
otherRange->Code = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FastBlockLookupRegions[block->StartAddrLocal >> 28][(block->StartAddrLocal & 0xFFFFFFF) / 2] = (u64)UINT32_MAX << 32;
|
||||
FastBlockLookupRegions[block->StartAddrLocal >> 27][(block->StartAddrLocal & 0x7FFFFFF) / 2] = (u64)UINT32_MAX << 32;
|
||||
if (block->Num == 0)
|
||||
JitBlocks9.erase(block->StartAddr);
|
||||
else
|
||||
|
@ -1055,17 +1085,23 @@ void InvalidateByAddr(u32 localAddr)
|
|||
}
|
||||
}
|
||||
|
||||
void CheckAndInvalidateITCM()
|
||||
{
|
||||
for (u32 i = 0; i < ITCMPhysicalSize; i+=16)
|
||||
{
|
||||
if (CodeIndexITCM[i / 512].Code & (1 << ((i & 0x1FF) / 16)))
|
||||
{
|
||||
InvalidateByAddr(i | (ARMJIT_Memory::memregion_ITCM << 27));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <u32 num, int region>
|
||||
void CheckAndInvalidate(u32 addr)
|
||||
{
|
||||
// let's hope this gets all properly inlined
|
||||
u32 mappingStart, mappingSize, memoryOffset, memorySize;
|
||||
if (ARMJIT_Memory::GetRegionMapping(region, num, mappingStart, mappingSize, memoryOffset, memorySize))
|
||||
{
|
||||
u32 localAddr = ((addr - mappingStart) & (memorySize - 1)) + memoryOffset;
|
||||
if (CodeMemRegions[region][localAddr / 512].Code & (1 << ((localAddr & 0x1FF) / 16)))
|
||||
InvalidateByAddr(localAddr | (region << 28));
|
||||
}
|
||||
u32 localAddr = ARMJIT_Memory::LocaliseAddress(region, num, addr);
|
||||
if (CodeMemRegions[region][(localAddr & 0x7FFFFFF) / 512].Code & (1 << ((localAddr & 0x1FF) / 16)))
|
||||
InvalidateByAddr(localAddr);
|
||||
}
|
||||
|
||||
JitBlockEntry LookUpBlock(u32 num, u64* entries, u32 offset, u32 addr)
|
||||
|
@ -1076,35 +1112,44 @@ JitBlockEntry LookUpBlock(u32 num, u64* entries, u32 offset, u32 addr)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void blockSanityCheck(u32 num, u32 blockAddr, JitBlockEntry entry)
|
||||
{
|
||||
u32 localAddr = LocaliseCodeAddress(num, blockAddr);
|
||||
assert(JITCompiler->AddEntryOffset((u32)FastBlockLookupRegions[localAddr >> 27][(localAddr & 0x7FFFFFF) / 2]) == entry);
|
||||
}
|
||||
|
||||
bool SetupExecutableRegion(u32 num, u32 blockAddr, u64*& entry, u32& start, u32& size)
|
||||
{
|
||||
// amazingly ignoring the DTCM is the proper behaviour for code fetches
|
||||
int region = num == 0
|
||||
? ARMJIT_Memory::ClassifyAddress9(blockAddr)
|
||||
: ARMJIT_Memory::ClassifyAddress7(blockAddr);
|
||||
|
||||
u32 mappingStart, mappingSize, memoryOffset, memorySize;
|
||||
if (CodeMemRegions[region]
|
||||
&& ARMJIT_Memory::GetRegionMapping(region, num, mappingStart,
|
||||
mappingSize, memoryOffset, memorySize))
|
||||
u32 memoryOffset;
|
||||
if (FastBlockLookupRegions[region]
|
||||
&& ARMJIT_Memory::GetMirrorLocation(region, num, blockAddr, memoryOffset, start, size))
|
||||
{
|
||||
//printf("setup exec region %d %d %08x %08x %x %x\n", num, region, blockAddr, start, size, memoryOffset);
|
||||
entry = FastBlockLookupRegions[region] + memoryOffset / 2;
|
||||
// evil, though it should work for everything except DTCM which is not relevant here
|
||||
start = blockAddr & ~(memorySize - 1);
|
||||
size = memorySize;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
template void CheckAndInvalidate<0, ARMJIT_Memory::memregion_MainRAM>(u32);
|
||||
template void CheckAndInvalidate<1, ARMJIT_Memory::memregion_MainRAM>(u32);
|
||||
template void CheckAndInvalidate<0, ARMJIT_Memory::memregion_SWRAM>(u32);
|
||||
template void CheckAndInvalidate<1, ARMJIT_Memory::memregion_SWRAM>(u32);
|
||||
template void CheckAndInvalidate<0, ARMJIT_Memory::memregion_SharedWRAM>(u32);
|
||||
template void CheckAndInvalidate<1, ARMJIT_Memory::memregion_SharedWRAM>(u32);
|
||||
template void CheckAndInvalidate<1, ARMJIT_Memory::memregion_WRAM7>(u32);
|
||||
template void CheckAndInvalidate<1, ARMJIT_Memory::memregion_VWRAM>(u32);
|
||||
template void CheckAndInvalidate<0, ARMJIT_Memory::memregion_VRAM>(u32);
|
||||
template void CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(u32);
|
||||
template void CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_A>(u32);
|
||||
template void CheckAndInvalidate<1, ARMJIT_Memory::memregion_NewSharedWRAM_A>(u32);
|
||||
template void CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_B>(u32);
|
||||
template void CheckAndInvalidate<1, ARMJIT_Memory::memregion_NewSharedWRAM_B>(u32);
|
||||
template void CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_C>(u32);
|
||||
template void CheckAndInvalidate<1, ARMJIT_Memory::memregion_NewSharedWRAM_C>(u32);
|
||||
|
||||
void ResetBlockCache()
|
||||
{
|
||||
|
@ -1133,7 +1178,7 @@ void ResetBlockCache()
|
|||
for (int j = 0; j < block->NumAddresses; j++)
|
||||
{
|
||||
u32 addr = block->AddressRanges()[j];
|
||||
AddressRange* range = &CodeMemRegions[addr >> 28][(addr & 0xFFFFFFF) / 512];
|
||||
AddressRange* range = &CodeMemRegions[addr >> 27][(addr & 0x7FFFFFF) / 512];
|
||||
range->Blocks.Clear();
|
||||
range->Code = 0;
|
||||
}
|
||||
|
@ -1145,7 +1190,7 @@ void ResetBlockCache()
|
|||
for (int j = 0; j < block->NumAddresses; j++)
|
||||
{
|
||||
u32 addr = block->AddressRanges()[j];
|
||||
AddressRange* range = &CodeMemRegions[addr >> 28][(addr & 0xFFFFFFF) / 512];
|
||||
AddressRange* range = &CodeMemRegions[addr >> 27][(addr & 0x7FFFFFF) / 512];
|
||||
range->Blocks.Clear();
|
||||
range->Code = 0;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ void DeInit();
|
|||
|
||||
void Reset();
|
||||
|
||||
void CheckAndInvalidateITCM();
|
||||
|
||||
void InvalidateByAddr(u32 pseudoPhysical);
|
||||
|
||||
template <u32 num, int region>
|
||||
|
|
|
@ -168,7 +168,7 @@ void Compiler::Comp_MemAccess(int rd, int rn, Op2 offset, int size, int flags)
|
|||
? ARMJIT_Memory::ClassifyAddress9(addrIsStatic ? staticAddress : CurInstr.DataRegion)
|
||||
: ARMJIT_Memory::ClassifyAddress7(addrIsStatic ? staticAddress : CurInstr.DataRegion);
|
||||
|
||||
if (Config::JIT_FastMemory && ((!Thumb && CurInstr.Cond() != 0xE) || ARMJIT_Memory::IsMappable(expectedTarget)))
|
||||
if (Config::JIT_FastMemory && ((!Thumb && CurInstr.Cond() != 0xE) || ARMJIT_Memory::IsFastmemCompatible(expectedTarget)))
|
||||
{
|
||||
ptrdiff_t memopStart = GetCodeOffset();
|
||||
LoadStorePatch patch;
|
||||
|
@ -461,7 +461,7 @@ s32 Compiler::Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc
|
|||
: ARMJIT_Memory::ClassifyAddress7(CurInstr.DataRegion);
|
||||
|
||||
bool compileFastPath = Config::JIT_FastMemory
|
||||
&& store && !usermode && (CurInstr.Cond() < 0xE || ARMJIT_Memory::IsMappable(expectedTarget));
|
||||
&& store && !usermode && (CurInstr.Cond() < 0xE || ARMJIT_Memory::IsFastmemCompatible(expectedTarget));
|
||||
|
||||
if (decrement)
|
||||
{
|
||||
|
|
|
@ -214,13 +214,13 @@ u32 LocaliseCodeAddress(u32 num, u32 addr);
|
|||
template <u32 Num>
|
||||
void LinkBlock(ARM* cpu, u32 codeOffset);
|
||||
|
||||
template <typename T> T SlowRead9(u32 addr, ARMv5* cpu);
|
||||
template <typename T> void SlowWrite9(u32 addr, ARMv5* cpu, T val);
|
||||
template <typename T> T SlowRead7(u32 addr);
|
||||
template <typename T> void SlowWrite7(u32 addr, T val);
|
||||
template <typename T, int ConsoleType> T SlowRead9(u32 addr, ARMv5* cpu);
|
||||
template <typename T, int ConsoleType> void SlowWrite9(u32 addr, ARMv5* cpu, T val);
|
||||
template <typename T, int ConsoleType> T SlowRead7(u32 addr);
|
||||
template <typename T, int ConsoleType> void SlowWrite7(u32 addr, T val);
|
||||
|
||||
template <bool PreInc, bool Write> void SlowBlockTransfer9(u32 addr, u64* data, u32 num, ARMv5* cpu);
|
||||
template <bool PreInc, bool Write> void SlowBlockTransfer7(u32 addr, u64* data, u32 num);
|
||||
template <bool Write, int ConsoleType> void SlowBlockTransfer9(u32 addr, u64* data, u32 num, ARMv5* cpu);
|
||||
template <bool Write, int ConsoleType> void SlowBlockTransfer7(u32 addr, u64* data, u32 num);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#ifdef __SWITCH__
|
||||
#if defined(__SWITCH__)
|
||||
#include "switch/compat_switch.h"
|
||||
#elif defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "ARMJIT_Memory.h"
|
||||
|
@ -7,6 +9,7 @@
|
|||
#include "ARMJIT_Internal.h"
|
||||
#include "ARMJIT_Compiler.h"
|
||||
|
||||
#include "DSi.h"
|
||||
#include "GPU.h"
|
||||
#include "GPU3D.h"
|
||||
#include "Wifi.h"
|
||||
|
@ -37,66 +40,24 @@
|
|||
|
||||
namespace ARMJIT_Memory
|
||||
{
|
||||
#ifdef __aarch64__
|
||||
struct FaultDescription
|
||||
{
|
||||
u64 IntegerRegisters[33];
|
||||
u64 FaultAddr;
|
||||
|
||||
u32 GetEmulatedAddr()
|
||||
{
|
||||
// now this is podracing
|
||||
return (u32)IntegerRegisters[0];
|
||||
}
|
||||
u64 RealAddr()
|
||||
{
|
||||
return FaultAddr;
|
||||
}
|
||||
|
||||
u64 GetPC()
|
||||
{
|
||||
return IntegerRegisters[32];
|
||||
}
|
||||
|
||||
void RestoreAndRepeat(s64 offset);
|
||||
u32 EmulatedFaultAddr;
|
||||
u64 FaultPC;
|
||||
};
|
||||
#else
|
||||
struct FaultDescription
|
||||
{
|
||||
u64 GetPC()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 GetEmulatedAddr()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
u64 RealAddr()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RestoreAndRepeat(s64 offset);
|
||||
};
|
||||
#endif
|
||||
|
||||
void FaultHandler(FaultDescription* faultDesc);
|
||||
bool FaultHandler(FaultDescription* faultDesc, s32& offset);
|
||||
}
|
||||
|
||||
|
||||
#ifdef __aarch64__
|
||||
|
||||
extern "C" void ARM_RestoreContext(u64* registers) __attribute__((noreturn));
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __SWITCH__
|
||||
#if defined(__SWITCH__)
|
||||
// with LTO the symbols seem to be not properly overriden
|
||||
// if they're somewhere else
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
void ARM_RestoreContext(u64* registers) __attribute__((noreturn));
|
||||
|
||||
extern char __start__;
|
||||
extern char __rodata_start;
|
||||
|
||||
|
@ -106,57 +67,85 @@ u64 __nx_exception_stack_size = 0x8000;
|
|||
void __libnx_exception_handler(ThreadExceptionDump* ctx)
|
||||
{
|
||||
ARMJIT_Memory::FaultDescription desc;
|
||||
memcpy(desc.IntegerRegisters, &ctx->cpu_gprs[0].x, 8*29);
|
||||
desc.IntegerRegisters[29] = ctx->fp.x;
|
||||
desc.IntegerRegisters[30] = ctx->lr.x;
|
||||
desc.IntegerRegisters[31] = ctx->sp.x;
|
||||
desc.IntegerRegisters[32] = ctx->pc.x;
|
||||
desc.EmulatedFaultAddr = ctx->cpu_gprs[0].w;
|
||||
desc.FaultPC = ctx->pc.x;
|
||||
|
||||
ARMJIT_Memory::FaultHandler(&desc);
|
||||
u64 integerRegisters[33];
|
||||
memcpy(integerRegisters, &ctx->cpu_gprs[0].x, 8*29);
|
||||
integerRegisters[29] = ctx->fp.x;
|
||||
integerRegisters[30] = ctx->lr.x;
|
||||
integerRegisters[31] = ctx->sp.x;
|
||||
integerRegisters[32] = ctx->pc.x;
|
||||
|
||||
s32 offset;
|
||||
if (ARMJIT_Memory::FaultHandler(&desc, offset))
|
||||
{
|
||||
integerRegisters[32] += offset;
|
||||
|
||||
ARM_RestoreContext(integerRegisters);
|
||||
}
|
||||
|
||||
if (ctx->pc.x >= (u64)&__start__ && ctx->pc.x < (u64)&__rodata_start)
|
||||
{
|
||||
printf("non JIT fault in .text at 0x%x (type %d) (trying to access 0x%x?)\n",
|
||||
printf("unintentional fault in .text at 0x%x (type %d) (trying to access 0x%x?)\n",
|
||||
ctx->pc.x - (u64)&__start__, ctx->error_desc, ctx->far.x);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("non JIT fault somewhere in deep (address) space at %x (type %d)\n", ctx->pc.x, ctx->error_desc);
|
||||
printf("unintentional fault somewhere in deep (address) space at %x (type %d)\n", ctx->pc.x, ctx->error_desc);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
static LONG ExceptionHandler(EXCEPTION_POINTERS* exceptionInfo)
|
||||
{
|
||||
if (exceptionInfo->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
ARMJIT_Memory::FaultDescription desc;
|
||||
desc.EmulatedFaultAddr = exceptionInfo->ContextRecord->Rcx;
|
||||
desc.FaultPC = exceptionInfo->ContextRecord->Rip;
|
||||
|
||||
s32 offset = 0;
|
||||
if (ARMJIT_Memory::FaultHandler(&desc, offset))
|
||||
{
|
||||
exceptionInfo->ContextRecord->Rip += offset;
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace ARMJIT_Memory
|
||||
{
|
||||
|
||||
#ifdef __aarch64__
|
||||
void FaultDescription::RestoreAndRepeat(s64 offset)
|
||||
{
|
||||
IntegerRegisters[32] += offset;
|
||||
void* FastMem9Start, *FastMem7Start;
|
||||
|
||||
ARM_RestoreContext(IntegerRegisters);
|
||||
#ifdef _WIN32
|
||||
inline u32 RoundUp(u32 size)
|
||||
{
|
||||
return (size + 0xFFFF) & ~0xFFFF;
|
||||
}
|
||||
#else
|
||||
void FaultDescription::RestoreAndRepeat(s64 offset)
|
||||
inline u32 RoundUp(u32 size)
|
||||
{
|
||||
|
||||
return size;
|
||||
}
|
||||
#endif
|
||||
|
||||
void* FastMem9Start, *FastMem7Start;
|
||||
|
||||
const u32 MemoryTotalSize =
|
||||
NDS::MainRAMSize
|
||||
+ NDS::SharedWRAMSize
|
||||
+ NDS::ARM7WRAMSize
|
||||
+ DTCMPhysicalSize;
|
||||
|
||||
const u32 MemBlockMainRAMOffset = 0;
|
||||
const u32 MemBlockSWRAMOffset = NDS::MainRAMSize;
|
||||
const u32 MemBlockARM7WRAMOffset = NDS::MainRAMSize + NDS::SharedWRAMSize;
|
||||
const u32 MemBlockDTCMOffset = NDS::MainRAMSize + NDS::SharedWRAMSize + NDS::ARM7WRAMSize;
|
||||
const u32 MemBlockSWRAMOffset = RoundUp(NDS::MainRAMMaxSize);
|
||||
const u32 MemBlockARM7WRAMOffset = MemBlockSWRAMOffset + RoundUp(NDS::SharedWRAMSize);
|
||||
const u32 MemBlockDTCMOffset = MemBlockARM7WRAMOffset + RoundUp(NDS::ARM7WRAMSize);
|
||||
const u32 MemBlockNWRAM_AOffset = MemBlockDTCMOffset + RoundUp(DTCMPhysicalSize);
|
||||
const u32 MemBlockNWRAM_BOffset = MemBlockNWRAM_AOffset + RoundUp(DSi::NWRAMSize);
|
||||
const u32 MemBlockNWRAM_COffset = MemBlockNWRAM_BOffset + RoundUp(DSi::NWRAMSize);
|
||||
const u32 MemoryTotalSize = MemBlockNWRAM_COffset + RoundUp(DSi::NWRAMSize);
|
||||
|
||||
const u32 OffsetsPerRegion[memregions_Count] =
|
||||
{
|
||||
|
@ -173,6 +162,11 @@ const u32 OffsetsPerRegion[memregions_Count] =
|
|||
UINT32_MAX,
|
||||
UINT32_MAX,
|
||||
UINT32_MAX,
|
||||
UINT32_MAX,
|
||||
UINT32_MAX,
|
||||
MemBlockNWRAM_AOffset,
|
||||
MemBlockNWRAM_BOffset,
|
||||
MemBlockNWRAM_COffset
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -186,11 +180,13 @@ enum
|
|||
u8 MappingStatus9[1 << (32-12)];
|
||||
u8 MappingStatus7[1 << (32-12)];
|
||||
|
||||
#ifdef __SWITCH__
|
||||
#if defined(__SWITCH__)
|
||||
u8* MemoryBase;
|
||||
u8* MemoryBaseCodeMem;
|
||||
#else
|
||||
#elif defined(_WIN32)
|
||||
u8* MemoryBase;
|
||||
HANDLE MemoryFile;
|
||||
LPVOID ExceptionHandlerHandle;
|
||||
#endif
|
||||
|
||||
bool MapIntoRange(u32 addr, u32 num, u32 offset, u32 size)
|
||||
|
@ -200,6 +196,9 @@ bool MapIntoRange(u32 addr, u32 num, u32 offset, u32 size)
|
|||
Result r = (svcMapProcessMemory(dst, envGetOwnProcessHandle(),
|
||||
(u64)(MemoryBaseCodeMem + offset), size));
|
||||
return R_SUCCEEDED(r);
|
||||
#elif defined(_WIN32)
|
||||
bool r = MapViewOfFileEx(MemoryFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, offset, size, dst) == dst;
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -209,8 +208,24 @@ bool UnmapFromRange(u32 addr, u32 num, u32 offset, u32 size)
|
|||
#ifdef __SWITCH__
|
||||
Result r = svcUnmapProcessMemory(dst, envGetOwnProcessHandle(),
|
||||
(u64)(MemoryBaseCodeMem + offset), size);
|
||||
printf("%x\n", r);
|
||||
return R_SUCCEEDED(r);
|
||||
#else
|
||||
return UnmapViewOfFile(dst);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SetCodeProtectionRange(u32 addr, u32 size, u32 num, int protection)
|
||||
{
|
||||
u8* dst = (u8*)(num == 0 ? FastMem9Start : FastMem7Start) + addr;
|
||||
#if defined(_WIN32)
|
||||
DWORD winProtection, oldProtection;
|
||||
if (protection == 0)
|
||||
winProtection = PAGE_NOACCESS;
|
||||
else if (protection == 1)
|
||||
winProtection = PAGE_READONLY;
|
||||
else
|
||||
winProtection = PAGE_READWRITE;
|
||||
VirtualProtect(dst, size, winProtection, &oldProtection);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -230,7 +245,6 @@ struct Mapping
|
|||
if (skipDTCM && Addr + offset == NDS::ARM9->DTCMBase)
|
||||
{
|
||||
offset += NDS::ARM9->DTCMSize;
|
||||
printf("%x skip\n", NDS::ARM9->DTCMSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -245,6 +259,7 @@ struct Mapping
|
|||
offset += 0x1000;
|
||||
}
|
||||
|
||||
#ifdef __SWITCH__
|
||||
if (status == memstate_MappedRW)
|
||||
{
|
||||
u32 segmentSize = offset - segmentOffset;
|
||||
|
@ -252,8 +267,12 @@ struct Mapping
|
|||
bool success = UnmapFromRange(Addr + segmentOffset, Num, segmentOffset + LocalOffset + OffsetsPerRegion[region], segmentSize);
|
||||
assert(success);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if defined(_WIN32)
|
||||
UnmapFromRange(Addr, Num, OffsetsPerRegion[region] + LocalOffset, Size);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
ARMJIT::TinyVector<Mapping> Mappings[memregions_Count];
|
||||
|
@ -268,6 +287,8 @@ void SetCodeProtection(int region, u32 offset, bool protect)
|
|||
Mapping& mapping = Mappings[region][i];
|
||||
|
||||
u32 effectiveAddr = mapping.Addr + (offset - mapping.LocalOffset);
|
||||
if (offset < mapping.LocalOffset || offset >= mapping.LocalOffset + mapping.Size)
|
||||
continue;
|
||||
if (mapping.Num == 0
|
||||
&& region != memregion_DTCM
|
||||
&& effectiveAddr >= NDS::ARM9->DTCMBase
|
||||
|
@ -276,16 +297,20 @@ void SetCodeProtection(int region, u32 offset, bool protect)
|
|||
|
||||
u8* states = (u8*)(mapping.Num == 0 ? MappingStatus9 : MappingStatus7);
|
||||
|
||||
printf("%d %x %d\n", states[effectiveAddr >> 12], effectiveAddr, mapping.Num);
|
||||
printf("%x %d %x %x %x %d\n", effectiveAddr, mapping.Num, mapping.Addr, mapping.LocalOffset, mapping.Size, states[effectiveAddr >> 12]);
|
||||
assert(states[effectiveAddr >> 12] == (protect ? memstate_MappedRW : memstate_MappedProtected));
|
||||
states[effectiveAddr >> 12] = protect ? memstate_MappedProtected : memstate_MappedRW;
|
||||
|
||||
#if defined(__SWITCH__)
|
||||
bool success;
|
||||
if (protect)
|
||||
success = UnmapFromRange(effectiveAddr, mapping.Num, OffsetsPerRegion[region] + offset, 0x1000);
|
||||
else
|
||||
success = MapIntoRange(effectiveAddr, mapping.Num, OffsetsPerRegion[region] + offset, 0x1000);
|
||||
assert(success);
|
||||
#elif defined(_WIN32)
|
||||
SetCodeProtectionRange(effectiveAddr, 0x1000, mapping.Num, protect ? 1 : 2);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,8 +339,8 @@ void RemapDTCM(u32 newBase, u32 newSize)
|
|||
|
||||
printf("mapping %d %x %x %x %x\n", region, mapping.Addr, mapping.Size, mapping.Num, mapping.LocalOffset);
|
||||
|
||||
bool oldOverlap = NDS::ARM9->DTCMSize > 0 && ((oldDTCMBase >= start && oldDTCMBase < end) || (oldDTCBEnd >= start && oldDTCBEnd < end));
|
||||
bool newOverlap = newSize > 0 && ((newBase >= start && newBase < end) || (newEnd >= start && newEnd < end));
|
||||
bool oldOverlap = NDS::ARM9->DTCMSize > 0 && !(oldDTCMBase >= end || oldDTCBEnd < start);
|
||||
bool newOverlap = newSize > 0 && !(newBase >= end || newEnd < start);
|
||||
|
||||
if (mapping.Num == 0 && (oldOverlap || newOverlap))
|
||||
{
|
||||
|
@ -336,19 +361,50 @@ void RemapDTCM(u32 newBase, u32 newSize)
|
|||
Mappings[memregion_DTCM].Clear();
|
||||
}
|
||||
|
||||
void RemapNWRAM(int num)
|
||||
{
|
||||
for (int i = 0; i < Mappings[memregion_SharedWRAM].Length;)
|
||||
{
|
||||
Mapping& mapping = Mappings[memregion_SharedWRAM][i];
|
||||
if (!(DSi::NWRAMStart[mapping.Num][num] >= mapping.Addr + mapping.Size
|
||||
|| DSi::NWRAMEnd[mapping.Num][num] < mapping.Addr))
|
||||
{
|
||||
mapping.Unmap(memregion_SharedWRAM);
|
||||
Mappings[memregion_SharedWRAM].Remove(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < Mappings[memregion_NewSharedWRAM_A + num].Length; i++)
|
||||
{
|
||||
Mappings[memregion_NewSharedWRAM_A + num][i].Unmap(memregion_NewSharedWRAM_A + num);
|
||||
}
|
||||
Mappings[memregion_NewSharedWRAM_A + num].Clear();
|
||||
}
|
||||
|
||||
void RemapSWRAM()
|
||||
{
|
||||
printf("remapping SWRAM\n");
|
||||
for (int i = 0; i < Mappings[memregion_SWRAM].Length; i++)
|
||||
for (int i = 0; i < Mappings[memregion_SharedWRAM].Length; i++)
|
||||
{
|
||||
Mappings[memregion_SWRAM][i].Unmap(memregion_SWRAM);
|
||||
Mappings[memregion_SharedWRAM][i].Unmap(memregion_SharedWRAM);
|
||||
}
|
||||
Mappings[memregion_SWRAM].Clear();
|
||||
Mappings[memregion_SharedWRAM].Clear();
|
||||
for (int i = 0; i < Mappings[memregion_WRAM7].Length; i++)
|
||||
{
|
||||
Mappings[memregion_WRAM7][i].Unmap(memregion_WRAM7);
|
||||
}
|
||||
Mappings[memregion_WRAM7].Clear();
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
for (int i = 0; i < Mappings[memregion_NewSharedWRAM_A + j].Length; i++)
|
||||
{
|
||||
Mappings[memregion_NewSharedWRAM_A + j][i].Unmap(memregion_NewSharedWRAM_A + j);
|
||||
}
|
||||
Mappings[memregion_NewSharedWRAM_A + j].Clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool MapAtAddress(u32 addr)
|
||||
|
@ -359,33 +415,36 @@ bool MapAtAddress(u32 addr)
|
|||
? ClassifyAddress9(addr)
|
||||
: ClassifyAddress7(addr);
|
||||
|
||||
if (!IsMappable(region))
|
||||
if (!IsFastmemCompatible(region))
|
||||
return false;
|
||||
|
||||
u32 mappingStart, mappingSize, memoryOffset, memorySize;
|
||||
bool isMapped = GetRegionMapping(region, num, mappingStart, mappingSize, memoryOffset, memorySize);
|
||||
return false;
|
||||
|
||||
u32 mirrorStart, mirrorSize, memoryOffset;
|
||||
bool isMapped = GetMirrorLocation(region, num, addr, memoryOffset, mirrorStart, mirrorSize);
|
||||
if (!isMapped)
|
||||
return false;
|
||||
|
||||
// this calculation even works with DTCM
|
||||
// which doesn't have to be aligned to it's own size
|
||||
u32 mirrorStart = (addr - mappingStart) / memorySize * memorySize + mappingStart;
|
||||
|
||||
u8* states = num == 0 ? MappingStatus9 : MappingStatus7;
|
||||
printf("trying to create mapping %08x %d %x %d %x\n", addr, num, memorySize, region, memoryOffset);
|
||||
printf("trying to create mapping %x, %x %d %d\n", mirrorStart, mirrorSize, region, num);
|
||||
bool isExecutable = ARMJIT::CodeMemRegions[region];
|
||||
|
||||
ARMJIT::AddressRange* range = ARMJIT::CodeMemRegions[region] + memoryOffset;
|
||||
#if defined(_WIN32)
|
||||
bool succeded = MapIntoRange(mirrorStart, num, OffsetsPerRegion[region] + memoryOffset, mirrorSize);
|
||||
assert(succeded);
|
||||
#endif
|
||||
|
||||
ARMJIT::AddressRange* range = ARMJIT::CodeMemRegions[region] + memoryOffset / 512;
|
||||
|
||||
// this overcomplicated piece of code basically just finds whole pieces of code memory
|
||||
// which can be mapped
|
||||
u32 offset = 0;
|
||||
bool skipDTCM = num == 0 && region != memregion_DTCM;
|
||||
while (offset < memorySize)
|
||||
while (offset < mirrorSize)
|
||||
{
|
||||
if (skipDTCM && mirrorStart + offset == NDS::ARM9->DTCMBase)
|
||||
{
|
||||
SetCodeProtectionRange(NDS::ARM9->DTCMBase, NDS::ARM9->DTCMSize, 0, 0);
|
||||
offset += NDS::ARM9->DTCMSize;
|
||||
}
|
||||
else
|
||||
|
@ -393,7 +452,7 @@ bool MapAtAddress(u32 addr)
|
|||
u32 sectionOffset = offset;
|
||||
bool hasCode = isExecutable && ARMJIT::PageContainsCode(&range[offset / 512]);
|
||||
while ((!isExecutable || ARMJIT::PageContainsCode(&range[offset / 512]) == hasCode)
|
||||
&& offset < memorySize
|
||||
&& offset < mirrorSize
|
||||
&& (!skipDTCM || mirrorStart + offset != NDS::ARM9->DTCMBase))
|
||||
{
|
||||
assert(states[(mirrorStart + offset) >> 12] == memstate_Unmapped);
|
||||
|
@ -403,41 +462,49 @@ bool MapAtAddress(u32 addr)
|
|||
|
||||
u32 sectionSize = offset - sectionOffset;
|
||||
|
||||
#if defined(__SWITCH__)
|
||||
if (!hasCode)
|
||||
{
|
||||
printf("trying to map %x (size: %x) from %x\n", mirrorStart + sectionOffset, sectionSize, sectionOffset + memoryOffset + OffsetsPerRegion[region]);
|
||||
bool succeded = MapIntoRange(mirrorStart + sectionOffset, num, sectionOffset + memoryOffset + OffsetsPerRegion[region], sectionSize);
|
||||
assert(succeded);
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
if (hasCode)
|
||||
{
|
||||
SetCodeProtectionRange(mirrorStart + offset, sectionSize, num, 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
Mapping mapping{mirrorStart, memorySize, memoryOffset, num};
|
||||
assert(num == 0 || num == 1);
|
||||
Mapping mapping{mirrorStart, mirrorSize, memoryOffset, num};
|
||||
Mappings[region].Add(mapping);
|
||||
|
||||
printf("mapped mirror at %08x-%08x\n", mirrorStart, mirrorStart + memorySize - 1);
|
||||
printf("mapped mirror at %08x-%08x\n", mirrorStart, mirrorStart + mirrorSize - 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FaultHandler(FaultDescription* faultDesc)
|
||||
bool FaultHandler(FaultDescription* faultDesc, s32& offset)
|
||||
{
|
||||
if (ARMJIT::JITCompiler->IsJITFault(faultDesc->GetPC()))
|
||||
if (ARMJIT::JITCompiler->IsJITFault(faultDesc->FaultPC))
|
||||
{
|
||||
bool rewriteToSlowPath = true;
|
||||
|
||||
u32 addr = faultDesc->GetEmulatedAddr();
|
||||
u32 addr = faultDesc->EmulatedFaultAddr;
|
||||
|
||||
if ((NDS::CurCPU == 0 ? MappingStatus9 : MappingStatus7)[addr >> 12] == memstate_Unmapped)
|
||||
rewriteToSlowPath = !MapAtAddress(faultDesc->GetEmulatedAddr());
|
||||
rewriteToSlowPath = !MapAtAddress(faultDesc->EmulatedFaultAddr);
|
||||
|
||||
s64 offset = 0;
|
||||
if (rewriteToSlowPath)
|
||||
{
|
||||
offset = ARMJIT::JITCompiler->RewriteMemAccess(faultDesc->GetPC());
|
||||
offset = ARMJIT::JITCompiler->RewriteMemAccess(faultDesc->FaultPC);
|
||||
}
|
||||
faultDesc->RestoreAndRepeat(offset);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Init()
|
||||
|
@ -459,18 +526,34 @@ void Init()
|
|||
FastMem7Start = virtmemReserve(0x100000000);
|
||||
assert(FastMem7Start);
|
||||
|
||||
NDS::MainRAM = MemoryBaseCodeMem + MemBlockMainRAMOffset;
|
||||
NDS::SharedWRAM = MemoryBaseCodeMem + MemBlockSWRAMOffset;
|
||||
NDS::ARM7WRAM = MemoryBaseCodeMem + MemBlockARM7WRAMOffset;
|
||||
NDS::ARM9->DTCM = MemoryBaseCodeMem + MemBlockDTCMOffset;
|
||||
#else
|
||||
MemoryBase = new u8[MemoryTotalSize];
|
||||
u8* basePtr = MemoryBaseCodeMem;
|
||||
#elif defined(_WIN32)
|
||||
ExceptionHandlerHandle = AddVectoredExceptionHandler(1, ExceptionHandler);
|
||||
|
||||
NDS::MainRAM = MemoryBase + MemBlockMainRAMOffset;
|
||||
NDS::SharedWRAM = MemoryBase + MemBlockSWRAMOffset;
|
||||
NDS::ARM7WRAM = MemoryBase + MemBlockARM7WRAMOffset;
|
||||
NDS::ARM9->DTCM = MemoryBase + MemBlockDTCMOffset;
|
||||
MemoryFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MemoryTotalSize, NULL);
|
||||
|
||||
MemoryBase = (u8*)VirtualAlloc(NULL, MemoryTotalSize, MEM_RESERVE, PAGE_READWRITE);
|
||||
|
||||
FastMem9Start = VirtualAlloc(NULL, 0x100000000, MEM_RESERVE, PAGE_READWRITE);
|
||||
FastMem7Start = VirtualAlloc(NULL, 0x100000000, MEM_RESERVE, PAGE_READWRITE);
|
||||
|
||||
// only free them after they have all been reserved
|
||||
// so they can't overlap
|
||||
VirtualFree(MemoryBase, 0, MEM_RELEASE);
|
||||
VirtualFree(FastMem9Start, 0, MEM_RELEASE);
|
||||
VirtualFree(FastMem7Start, 0, MEM_RELEASE);
|
||||
|
||||
MapViewOfFileEx(MemoryFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, MemoryTotalSize, MemoryBase);
|
||||
|
||||
u8* basePtr = MemoryBase;
|
||||
#endif
|
||||
NDS::MainRAM = basePtr + MemBlockMainRAMOffset;
|
||||
NDS::SharedWRAM = basePtr + MemBlockSWRAMOffset;
|
||||
NDS::ARM7WRAM = basePtr + MemBlockARM7WRAMOffset;
|
||||
NDS::ARM9->DTCM = basePtr + MemBlockDTCMOffset;
|
||||
DSi::NWRAM_A = basePtr + MemBlockNWRAM_AOffset;
|
||||
DSi::NWRAM_B = basePtr + MemBlockNWRAM_BOffset;
|
||||
DSi::NWRAM_C = basePtr + MemBlockNWRAM_COffset;
|
||||
}
|
||||
|
||||
void DeInit()
|
||||
|
@ -482,8 +565,11 @@ void DeInit()
|
|||
svcUnmapProcessCodeMemory(envGetOwnProcessHandle(), (u64)MemoryBaseCodeMem, (u64)MemoryBase, MemoryTotalSize);
|
||||
virtmemFree(MemoryBaseCodeMem, MemoryTotalSize);
|
||||
free(MemoryBase);
|
||||
#else
|
||||
delete[] MemoryBase;
|
||||
#elif defined(_WIN32)
|
||||
assert(UnmapViewOfFile(MemoryBase));
|
||||
CloseHandle(MemoryFile);
|
||||
|
||||
RemoveVectoredExceptionHandler(ExceptionHandlerHandle);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -505,12 +591,23 @@ void Reset()
|
|||
printf("done resetting jit mem\n");
|
||||
}
|
||||
|
||||
bool IsMappable(int region)
|
||||
bool IsFastmemCompatible(int region)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
/*
|
||||
TODO: with some hacks, the smaller shared WRAM regions
|
||||
could be mapped in some occaisons as well
|
||||
*/
|
||||
if (region == memregion_DTCM
|
||||
|| region == memregion_SharedWRAM
|
||||
|| region == memregion_NewSharedWRAM_B
|
||||
|| region == memregion_NewSharedWRAM_C)
|
||||
return false;
|
||||
#endif
|
||||
return OffsetsPerRegion[region] != UINT32_MAX;
|
||||
}
|
||||
|
||||
bool GetRegionMapping(int region, u32 num, u32& mappingStart, u32& mappingSize, u32& memoryOffset, u32& memorySize)
|
||||
bool GetMirrorLocation(int region, u32 num, u32 addr, u32& memoryOffset, u32& mirrorStart, u32& mirrorSize)
|
||||
{
|
||||
memoryOffset = 0;
|
||||
switch (region)
|
||||
|
@ -518,137 +615,251 @@ bool GetRegionMapping(int region, u32 num, u32& mappingStart, u32& mappingSize,
|
|||
case memregion_ITCM:
|
||||
if (num == 0)
|
||||
{
|
||||
mappingStart = 0;
|
||||
mappingSize = NDS::ARM9->ITCMSize;
|
||||
memorySize = ITCMPhysicalSize;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case memregion_DTCM:
|
||||
if (num == 0)
|
||||
{
|
||||
mappingStart = NDS::ARM9->DTCMBase;
|
||||
mappingSize = NDS::ARM9->DTCMSize;
|
||||
memorySize = DTCMPhysicalSize;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case memregion_BIOS9:
|
||||
if (num == 0)
|
||||
{
|
||||
mappingStart = 0xFFFF0000;
|
||||
mappingSize = 0x10000;
|
||||
memorySize = 0x1000;
|
||||
mirrorStart = addr & ~(ITCMPhysicalSize - 1);
|
||||
mirrorSize = ITCMPhysicalSize;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case memregion_MainRAM:
|
||||
mappingStart = 0x2000000;
|
||||
mappingSize = 0x1000000;
|
||||
memorySize = NDS::MainRAMSize;
|
||||
mirrorStart = addr & ~NDS::MainRAMMask;
|
||||
mirrorSize = NDS::MainRAMMask + 1;
|
||||
return true;
|
||||
case memregion_SWRAM:
|
||||
mappingStart = 0x3000000;
|
||||
if (num == 0 && NDS::SWRAM_ARM9.Mem)
|
||||
{
|
||||
mappingSize = 0x1000000;
|
||||
memoryOffset = NDS::SWRAM_ARM9.Mem - NDS::SharedWRAM;
|
||||
memorySize = NDS::SWRAM_ARM9.Mask + 1;
|
||||
return true;
|
||||
}
|
||||
else if (num == 1 && NDS::SWRAM_ARM7.Mem)
|
||||
{
|
||||
mappingSize = 0x800000;
|
||||
memoryOffset = NDS::SWRAM_ARM7.Mem - NDS::SharedWRAM;
|
||||
memorySize = NDS::SWRAM_ARM7.Mask + 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case memregion_VRAM:
|
||||
case memregion_BIOS9:
|
||||
if (num == 0)
|
||||
{
|
||||
// this is a gross simplification
|
||||
// mostly to make code on vram working
|
||||
// it doesn't take any of the actual VRAM mappings into account
|
||||
mappingStart = 0x6000000;
|
||||
mappingSize = 0x1000000;
|
||||
memorySize = 0x100000;
|
||||
mirrorStart = addr & ~0xFFF;
|
||||
mirrorSize = 0x1000;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case memregion_BIOS7:
|
||||
if (num == 1)
|
||||
{
|
||||
mappingStart = 0;
|
||||
mappingSize = 0x4000;
|
||||
memorySize = 0x4000;
|
||||
mirrorStart = 0;
|
||||
mirrorSize = 0x4000;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case memregion_SharedWRAM:
|
||||
if (num == 0 && NDS::SWRAM_ARM9.Mem)
|
||||
{
|
||||
mirrorStart = addr & ~NDS::SWRAM_ARM9.Mask;
|
||||
mirrorSize = NDS::SWRAM_ARM9.Mask + 1;
|
||||
memoryOffset = NDS::SWRAM_ARM9.Mem - NDS::SharedWRAM;
|
||||
return true;
|
||||
}
|
||||
else if (num == 1 && NDS::SWRAM_ARM7.Mem)
|
||||
{
|
||||
mirrorStart = addr & ~NDS::SWRAM_ARM7.Mask;
|
||||
mirrorSize = NDS::SWRAM_ARM7.Mask + 1;
|
||||
memoryOffset = NDS::SWRAM_ARM7.Mem - NDS::SharedWRAM;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case memregion_WRAM7:
|
||||
if (num == 1)
|
||||
{
|
||||
if (NDS::SWRAM_ARM7.Mem)
|
||||
{
|
||||
mappingStart = 0x3800000;
|
||||
mappingSize = 0x800000;
|
||||
}
|
||||
else
|
||||
{
|
||||
mappingStart = 0x3000000;
|
||||
mappingSize = 0x1000000;
|
||||
}
|
||||
memorySize = NDS::ARM7WRAMSize;
|
||||
mirrorStart = addr & ~(NDS::ARM7WRAMSize - 1);
|
||||
mirrorSize = NDS::ARM7WRAMSize;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case memregion_VRAM:
|
||||
if (num == 0)
|
||||
{
|
||||
mirrorStart = addr & ~0xFFFFF;
|
||||
mirrorSize = 0x100000;
|
||||
}
|
||||
return false;
|
||||
case memregion_VWRAM:
|
||||
if (num == 1)
|
||||
{
|
||||
mappingStart = 0x6000000;
|
||||
mappingSize = 0x1000000;
|
||||
memorySize = 0x20000;
|
||||
mirrorStart = addr & ~0x3FFFF;
|
||||
mirrorSize = 0x40000;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case memregion_NewSharedWRAM_A:
|
||||
{
|
||||
u8* ptr = DSi::NWRAMMap_A[num][(addr >> 16) & DSi::NWRAMMask[num][0]];
|
||||
if (ptr)
|
||||
{
|
||||
memoryOffset = ptr - DSi::NWRAM_A;
|
||||
mirrorStart = addr & ~0xFFFF;
|
||||
mirrorSize = 0x10000;
|
||||
return true;
|
||||
}
|
||||
return false; // zero filled memory
|
||||
}
|
||||
case memregion_NewSharedWRAM_B:
|
||||
{
|
||||
u8* ptr = DSi::NWRAMMap_B[num][(addr >> 15) & DSi::NWRAMMask[num][1]];
|
||||
if (ptr)
|
||||
{
|
||||
memoryOffset = ptr - DSi::NWRAM_B;
|
||||
mirrorStart = addr & ~0x7FFF;
|
||||
mirrorSize = 0x8000;
|
||||
return true;
|
||||
}
|
||||
return false; // zero filled memory
|
||||
}
|
||||
case memregion_NewSharedWRAM_C:
|
||||
{
|
||||
u8* ptr = DSi::NWRAMMap_C[num][(addr >> 15) & DSi::NWRAMMask[num][2]];
|
||||
if (ptr)
|
||||
{
|
||||
memoryOffset = ptr - DSi::NWRAM_C;
|
||||
mirrorStart = addr & ~0x7FFF;
|
||||
mirrorSize = 0x8000;
|
||||
return true;
|
||||
}
|
||||
return false; // zero filled memory
|
||||
}
|
||||
case memregion_BIOS9DSi:
|
||||
if (num == 0)
|
||||
{
|
||||
mirrorStart = addr & ~0xFFFF;
|
||||
mirrorSize = DSi::SCFG_BIOS & (1<<0) ? 0x8000 : 0x10000;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case memregion_BIOS7DSi:
|
||||
if (num == 1)
|
||||
{
|
||||
mirrorStart = addr & ~0xFFFF;
|
||||
mirrorSize = DSi::SCFG_BIOS & (1<<8) ? 0x8000 : 0x10000;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
// for the JIT we don't are about the rest
|
||||
assert(false && "For the time being this should only be used for code");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
u32 LocaliseAddress(int region, u32 num, u32 addr)
|
||||
{
|
||||
switch (region)
|
||||
{
|
||||
case memregion_ITCM:
|
||||
return (addr & (ITCMPhysicalSize - 1)) | (memregion_ITCM << 27);
|
||||
case memregion_MainRAM:
|
||||
return (addr & NDS::MainRAMMask) | (memregion_MainRAM << 27);
|
||||
case memregion_BIOS9:
|
||||
return (addr & 0xFFF) | (memregion_BIOS9 << 27);
|
||||
case memregion_BIOS7:
|
||||
return (addr & 0x3FFF) | (memregion_BIOS7 << 27);
|
||||
case memregion_SharedWRAM:
|
||||
if (num == 0)
|
||||
return ((addr & NDS::SWRAM_ARM9.Mask) + (NDS::SWRAM_ARM9.Mem - NDS::SharedWRAM)) | (memregion_SharedWRAM << 27);
|
||||
else
|
||||
return ((addr & NDS::SWRAM_ARM7.Mask) + (NDS::SWRAM_ARM7.Mem - NDS::SharedWRAM)) | (memregion_SharedWRAM << 27);
|
||||
case memregion_WRAM7:
|
||||
return (addr & (NDS::ARM7WRAMSize - 1)) | (memregion_WRAM7 << 27);
|
||||
case memregion_VRAM:
|
||||
// TODO: take mapping properly into account
|
||||
return (addr & 0xFFFFF) | (memregion_VRAM << 27);
|
||||
case memregion_VWRAM:
|
||||
// same here
|
||||
return (addr & 0x3FFFF) | (memregion_VWRAM << 27);
|
||||
case memregion_NewSharedWRAM_A:
|
||||
{
|
||||
u8* ptr = DSi::NWRAMMap_A[num][(addr >> 16) & DSi::NWRAMMask[num][0]];
|
||||
if (ptr)
|
||||
return (ptr - DSi::NWRAM_A + (addr & 0xFFFF)) | (memregion_NewSharedWRAM_A << 27);
|
||||
else
|
||||
return memregion_Other << 27; // zero filled memory
|
||||
}
|
||||
case memregion_NewSharedWRAM_B:
|
||||
{
|
||||
u8* ptr = DSi::NWRAMMap_B[num][(addr >> 15) & DSi::NWRAMMask[num][1]];
|
||||
if (ptr)
|
||||
return (ptr - DSi::NWRAM_B + (addr & 0x7FFF)) | (memregion_NewSharedWRAM_B << 27);
|
||||
else
|
||||
return memregion_Other << 27;
|
||||
}
|
||||
case memregion_NewSharedWRAM_C:
|
||||
{
|
||||
u8* ptr = DSi::NWRAMMap_C[num][(addr >> 15) & DSi::NWRAMMask[num][2]];
|
||||
if (ptr)
|
||||
return (ptr - DSi::NWRAM_C + (addr & 0x7FFF)) | (memregion_NewSharedWRAM_C << 27);
|
||||
else
|
||||
return memregion_Other << 27;
|
||||
}
|
||||
case memregion_BIOS9DSi:
|
||||
case memregion_BIOS7DSi:
|
||||
return (addr & 0xFFFF) | (region << 27);
|
||||
default:
|
||||
assert(false && "This should only be needed for regions which can contain code");
|
||||
return memregion_Other << 27;
|
||||
}
|
||||
}
|
||||
|
||||
int ClassifyAddress9(u32 addr)
|
||||
{
|
||||
if (addr < NDS::ARM9->ITCMSize)
|
||||
return memregion_ITCM;
|
||||
else if (addr >= NDS::ARM9->DTCMBase && addr < (NDS::ARM9->DTCMBase + NDS::ARM9->DTCMSize))
|
||||
return memregion_DTCM;
|
||||
else if ((addr & 0xFFFFF000) == 0xFFFF0000)
|
||||
return memregion_BIOS9;
|
||||
else
|
||||
{
|
||||
return memregion_ITCM;
|
||||
}
|
||||
else if (addr >= NDS::ARM9->DTCMBase && addr < (NDS::ARM9->DTCMBase + NDS::ARM9->DTCMSize))
|
||||
{
|
||||
return memregion_DTCM;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NDS::ConsoleType == 1 && addr >= 0xFFFF0000 && !(DSi::SCFG_BIOS & (1<<1)))
|
||||
{
|
||||
if ((addr >= 0xFFFF8000) && (DSi::SCFG_BIOS & (1<<0)))
|
||||
return memregion_Other;
|
||||
|
||||
return memregion_BIOS9DSi;
|
||||
}
|
||||
else if ((addr & 0xFFFFF000) == 0xFFFF0000)
|
||||
{
|
||||
return memregion_BIOS9;
|
||||
}
|
||||
|
||||
switch (addr & 0xFF000000)
|
||||
{
|
||||
case 0x02000000:
|
||||
return memregion_MainRAM;
|
||||
case 0x03000000:
|
||||
if (NDS::ConsoleType == 1)
|
||||
{
|
||||
if (addr >= DSi::NWRAMStart[0][0] && addr < DSi::NWRAMEnd[0][0])
|
||||
return memregion_NewSharedWRAM_A;
|
||||
if (addr >= DSi::NWRAMStart[0][1] && addr < DSi::NWRAMEnd[0][1])
|
||||
return memregion_NewSharedWRAM_B;
|
||||
if (addr >= DSi::NWRAMStart[0][2] && addr < DSi::NWRAMEnd[0][2])
|
||||
return memregion_NewSharedWRAM_C;
|
||||
}
|
||||
|
||||
if (NDS::SWRAM_ARM9.Mem)
|
||||
return memregion_SWRAM;
|
||||
else
|
||||
return memregion_Other;
|
||||
return memregion_SharedWRAM;
|
||||
return memregion_Other;
|
||||
case 0x04000000:
|
||||
return memregion_IO9;
|
||||
case 0x06000000:
|
||||
return memregion_VRAM;
|
||||
default:
|
||||
return memregion_Other;
|
||||
}
|
||||
}
|
||||
return memregion_Other;
|
||||
}
|
||||
|
||||
int ClassifyAddress7(u32 addr)
|
||||
{
|
||||
if (addr < 0x00004000)
|
||||
if (NDS::ConsoleType == 1 && addr < 0x00010000 && !(DSi::SCFG_BIOS & (1<<9)))
|
||||
{
|
||||
if (addr >= 0x00008000 && DSi::SCFG_BIOS & (1<<8))
|
||||
return memregion_Other;
|
||||
|
||||
return memregion_BIOS7DSi;
|
||||
}
|
||||
else if (addr < 0x00004000)
|
||||
{
|
||||
return memregion_BIOS7;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (addr & 0xFF800000)
|
||||
|
@ -657,10 +868,19 @@ int ClassifyAddress7(u32 addr)
|
|||
case 0x02800000:
|
||||
return memregion_MainRAM;
|
||||
case 0x03000000:
|
||||
if (NDS::ConsoleType == 1)
|
||||
{
|
||||
if (addr >= DSi::NWRAMStart[1][0] && addr < DSi::NWRAMEnd[1][0])
|
||||
return memregion_NewSharedWRAM_A;
|
||||
if (addr >= DSi::NWRAMStart[1][1] && addr < DSi::NWRAMEnd[1][1])
|
||||
return memregion_NewSharedWRAM_B;
|
||||
if (addr >= DSi::NWRAMStart[1][2] && addr < DSi::NWRAMEnd[1][2])
|
||||
return memregion_NewSharedWRAM_C;
|
||||
}
|
||||
|
||||
if (NDS::SWRAM_ARM7.Mem)
|
||||
return memregion_SWRAM;
|
||||
else
|
||||
return memregion_WRAM7;
|
||||
return memregion_SharedWRAM;
|
||||
return memregion_WRAM7;
|
||||
case 0x03800000:
|
||||
return memregion_WRAM7;
|
||||
case 0x04000000:
|
||||
|
@ -740,14 +960,29 @@ void* GetFuncForAddr(ARM* cpu, u32 addr, bool store, int size)
|
|||
}
|
||||
}
|
||||
|
||||
switch (size | store)
|
||||
if (NDS::ConsoleType == 0)
|
||||
{
|
||||
case 8: return (void*)NDS::ARM9IORead8;
|
||||
case 9: return (void*)NDS::ARM9IOWrite8;
|
||||
case 16: return (void*)NDS::ARM9IORead16;
|
||||
case 17: return (void*)NDS::ARM9IOWrite16;
|
||||
case 32: return (void*)NDS::ARM9IORead32;
|
||||
case 33: return (void*)NDS::ARM9IOWrite32;
|
||||
switch (size | store)
|
||||
{
|
||||
case 8: return (void*)NDS::ARM9IORead8;
|
||||
case 9: return (void*)NDS::ARM9IOWrite8;
|
||||
case 16: return (void*)NDS::ARM9IORead16;
|
||||
case 17: return (void*)NDS::ARM9IOWrite16;
|
||||
case 32: return (void*)NDS::ARM9IORead32;
|
||||
case 33: return (void*)NDS::ARM9IOWrite32;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (size | store)
|
||||
{
|
||||
case 8: return (void*)DSi::ARM9IORead8;
|
||||
case 9: return (void*)DSi::ARM9IOWrite8;
|
||||
case 16: return (void*)DSi::ARM9IORead16;
|
||||
case 17: return (void*)DSi::ARM9IOWrite16;
|
||||
case 32: return (void*)DSi::ARM9IORead32;
|
||||
case 33: return (void*)DSi::ARM9IOWrite32;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x06000000:
|
||||
|
@ -781,14 +1016,29 @@ void* GetFuncForAddr(ARM* cpu, u32 addr, bool store, int size)
|
|||
}
|
||||
}
|
||||
|
||||
switch (size | store)
|
||||
if (NDS::ConsoleType == 0)
|
||||
{
|
||||
case 8: return (void*)NDS::ARM7IORead8;
|
||||
case 9: return (void*)NDS::ARM7IOWrite8;
|
||||
case 16: return (void*)NDS::ARM7IORead16;
|
||||
case 17: return (void*)NDS::ARM7IOWrite16;
|
||||
case 32: return (void*)NDS::ARM7IORead32;
|
||||
case 33: return (void*)NDS::ARM7IOWrite32;
|
||||
switch (size | store)
|
||||
{
|
||||
case 8: return (void*)NDS::ARM7IORead8;
|
||||
case 9: return (void*)NDS::ARM7IOWrite8;
|
||||
case 16: return (void*)NDS::ARM7IORead16;
|
||||
case 17: return (void*)NDS::ARM7IOWrite16;
|
||||
case 32: return (void*)NDS::ARM7IORead32;
|
||||
case 33: return (void*)NDS::ARM7IOWrite32;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (size | store)
|
||||
{
|
||||
case 8: return (void*)DSi::ARM7IORead8;
|
||||
case 9: return (void*)DSi::ARM7IOWrite8;
|
||||
case 16: return (void*)DSi::ARM7IORead16;
|
||||
case 17: return (void*)DSi::ARM7IOWrite16;
|
||||
case 32: return (void*)DSi::ARM7IORead32;
|
||||
case 33: return (void*)DSi::ARM7IOWrite32;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x04800000:
|
||||
|
|
|
@ -23,7 +23,7 @@ enum
|
|||
memregion_DTCM,
|
||||
memregion_BIOS9,
|
||||
memregion_MainRAM,
|
||||
memregion_SWRAM,
|
||||
memregion_SharedWRAM,
|
||||
memregion_IO9,
|
||||
memregion_VRAM,
|
||||
memregion_BIOS7,
|
||||
|
@ -31,18 +31,28 @@ enum
|
|||
memregion_IO7,
|
||||
memregion_Wifi,
|
||||
memregion_VWRAM,
|
||||
|
||||
// DSi
|
||||
memregion_BIOS9DSi,
|
||||
memregion_BIOS7DSi,
|
||||
memregion_NewSharedWRAM_A,
|
||||
memregion_NewSharedWRAM_B,
|
||||
memregion_NewSharedWRAM_C,
|
||||
|
||||
memregions_Count
|
||||
};
|
||||
|
||||
int ClassifyAddress9(u32 addr);
|
||||
int ClassifyAddress7(u32 addr);
|
||||
|
||||
bool GetRegionMapping(int region, u32 num, u32& mappingStart, u32& mappingSize, u32& memoryOffset, u32& memorySize);
|
||||
bool GetMirrorLocation(int region, u32 num, u32 addr, u32& memoryOffset, u32& mirrorStart, u32& mirrorSize);
|
||||
u32 LocaliseAddress(int region, u32 num, u32 addr);
|
||||
|
||||
bool IsMappable(int region);
|
||||
bool IsFastmemCompatible(int region);
|
||||
|
||||
void RemapDTCM(u32 newBase, u32 newSize);
|
||||
void RemapSWRAM();
|
||||
void RemapNWRAM(int num);
|
||||
|
||||
void SetCodeProtection(int region, u32 offset, bool protect);
|
||||
|
||||
|
|
|
@ -40,6 +40,12 @@ const int RegisterCache<Compiler, X64Reg>::NativeRegsAvailable =
|
|||
#endif
|
||||
;
|
||||
|
||||
#ifdef _WIN32
|
||||
const BitSet32 CallerSavedPushRegs({R10, R11});
|
||||
#else
|
||||
const BitSet32 CallerSavedPushRegs({R9, R10, R11});
|
||||
#endif
|
||||
|
||||
void Compiler::PushRegs(bool saveHiRegs)
|
||||
{
|
||||
BitSet32 loadedRegs(RegCache.LoadedRegs);
|
||||
|
@ -301,6 +307,107 @@ Compiler::Compiler()
|
|||
RET();
|
||||
}
|
||||
|
||||
for (int consoleType = 0; consoleType < 2; consoleType++)
|
||||
{
|
||||
for (int num = 0; num < 2; num++)
|
||||
{
|
||||
for (int size = 0; size < 3; size++)
|
||||
{
|
||||
for (int reg = 0; reg < 16; reg++)
|
||||
{
|
||||
if (reg == RSCRATCH || reg == ABI_PARAM1 || reg == ABI_PARAM2 || reg == ABI_PARAM3)
|
||||
{
|
||||
PatchedStoreFuncs[consoleType][num][size][reg] = NULL;
|
||||
PatchedLoadFuncs[consoleType][num][size][0][reg] = NULL;
|
||||
PatchedLoadFuncs[consoleType][num][size][1][reg] = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
X64Reg rdMapped = (X64Reg)reg;
|
||||
PatchedStoreFuncs[consoleType][num][size][reg] = GetWritableCodePtr();
|
||||
if (RSCRATCH3 != ABI_PARAM1)
|
||||
MOV(32, R(ABI_PARAM1), R(RSCRATCH3));
|
||||
if (num == 0)
|
||||
{
|
||||
MOV(64, R(ABI_PARAM2), R(RCPU));
|
||||
MOV(32, R(ABI_PARAM3), R(rdMapped));
|
||||
}
|
||||
else
|
||||
{
|
||||
MOV(32, R(ABI_PARAM2), R(rdMapped));
|
||||
}
|
||||
ABI_PushRegistersAndAdjustStack(CallerSavedPushRegs, 8);
|
||||
if (consoleType == 0)
|
||||
{
|
||||
switch ((8 << size) | num)
|
||||
{
|
||||
case 32: ABI_CallFunction(SlowWrite9<u32, 0>); break;
|
||||
case 33: ABI_CallFunction(SlowWrite7<u32, 0>); break;
|
||||
case 16: ABI_CallFunction(SlowWrite9<u16, 0>); break;
|
||||
case 17: ABI_CallFunction(SlowWrite7<u16, 0>); break;
|
||||
case 8: ABI_CallFunction(SlowWrite9<u8, 0>); break;
|
||||
case 9: ABI_CallFunction(SlowWrite7<u8, 0>); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ((8 << size) | num)
|
||||
{
|
||||
case 32: ABI_CallFunction(SlowWrite9<u32, 1>); break;
|
||||
case 33: ABI_CallFunction(SlowWrite7<u32, 1>); break;
|
||||
case 16: ABI_CallFunction(SlowWrite9<u16, 1>); break;
|
||||
case 17: ABI_CallFunction(SlowWrite7<u16, 1>); break;
|
||||
case 8: ABI_CallFunction(SlowWrite9<u8, 1>); break;
|
||||
case 9: ABI_CallFunction(SlowWrite7<u8, 1>); break;
|
||||
}
|
||||
}
|
||||
ABI_PopRegistersAndAdjustStack(CallerSavedPushRegs, 8);
|
||||
RET();
|
||||
|
||||
for (int signextend = 0; signextend < 2; signextend++)
|
||||
{
|
||||
PatchedLoadFuncs[consoleType][num][size][signextend][reg] = GetWritableCodePtr();
|
||||
if (RSCRATCH3 != ABI_PARAM1)
|
||||
MOV(32, R(ABI_PARAM1), R(RSCRATCH3));
|
||||
if (num == 0)
|
||||
MOV(64, R(ABI_PARAM2), R(RCPU));
|
||||
ABI_PushRegistersAndAdjustStack(CallerSavedPushRegs, 8);
|
||||
if (consoleType == 0)
|
||||
{
|
||||
switch ((8 << size) | num)
|
||||
{
|
||||
case 32: ABI_CallFunction(SlowRead9<u32, 0>); break;
|
||||
case 33: ABI_CallFunction(SlowRead7<u32, 0>); break;
|
||||
case 16: ABI_CallFunction(SlowRead9<u16, 0>); break;
|
||||
case 17: ABI_CallFunction(SlowRead7<u16, 0>); break;
|
||||
case 8: ABI_CallFunction(SlowRead9<u8, 0>); break;
|
||||
case 9: ABI_CallFunction(SlowRead7<u8, 0>); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ((8 << size) | num)
|
||||
{
|
||||
case 32: ABI_CallFunction(SlowRead9<u32, 1>); break;
|
||||
case 33: ABI_CallFunction(SlowRead7<u32, 1>); break;
|
||||
case 16: ABI_CallFunction(SlowRead9<u16, 1>); break;
|
||||
case 17: ABI_CallFunction(SlowRead7<u16, 1>); break;
|
||||
case 8: ABI_CallFunction(SlowRead9<u8, 1>); break;
|
||||
case 9: ABI_CallFunction(SlowRead7<u8, 1>); break;
|
||||
}
|
||||
}
|
||||
ABI_PopRegistersAndAdjustStack(CallerSavedPushRegs, 8);
|
||||
if (signextend)
|
||||
MOVSX(32, 8 << size, rdMapped, R(RSCRATCH));
|
||||
else
|
||||
MOVZX(32, 8 << size, rdMapped, R(RSCRATCH));
|
||||
RET();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// move the region forward to prevent overwriting the generated functions
|
||||
CodeMemSize -= GetWritableCodePtr() - ResetStart;
|
||||
ResetStart = GetWritableCodePtr();
|
||||
|
@ -500,6 +607,8 @@ void Compiler::Reset()
|
|||
|
||||
NearCode = NearStart;
|
||||
FarCode = FarStart;
|
||||
|
||||
LoadStorePatches.clear();
|
||||
}
|
||||
|
||||
bool Compiler::IsJITFault(u64 addr)
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "../ARMJIT_Internal.h"
|
||||
#include "../ARMJIT_RegisterCache.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ARMJIT
|
||||
{
|
||||
|
||||
|
@ -18,6 +20,13 @@ const Gen::X64Reg RSCRATCH2 = Gen::EDX;
|
|||
const Gen::X64Reg RSCRATCH3 = Gen::ECX;
|
||||
const Gen::X64Reg RSCRATCH4 = Gen::R8;
|
||||
|
||||
struct LoadStorePatch
|
||||
{
|
||||
void* PatchFunc;
|
||||
s16 Offset;
|
||||
u16 Size;
|
||||
};
|
||||
|
||||
struct Op2
|
||||
{
|
||||
Op2()
|
||||
|
@ -211,6 +220,11 @@ public:
|
|||
u8* NearStart;
|
||||
u8* FarStart;
|
||||
|
||||
void* PatchedStoreFuncs[2][2][3][16];
|
||||
void* PatchedLoadFuncs[2][2][3][2][16];
|
||||
|
||||
std::unordered_map<u8*, LoadStorePatch> LoadStorePatches;
|
||||
|
||||
u8* ResetStart;
|
||||
u32 CodeMemSize;
|
||||
|
||||
|
|
|
@ -17,7 +17,30 @@ int squeezePointer(T* ptr)
|
|||
|
||||
s32 Compiler::RewriteMemAccess(u64 pc)
|
||||
{
|
||||
return 0;
|
||||
auto it = LoadStorePatches.find((u8*)pc);
|
||||
if (it != LoadStorePatches.end())
|
||||
{
|
||||
LoadStorePatch patch = it->second;
|
||||
LoadStorePatches.erase(it);
|
||||
|
||||
u8* curCodePtr = GetWritableCodePtr();
|
||||
u8* rewritePtr = (u8*)pc + (ptrdiff_t)patch.Offset;
|
||||
SetCodePtr(rewritePtr);
|
||||
|
||||
CALL(patch.PatchFunc);
|
||||
u32 remainingSize = patch.Size - (GetWritableCodePtr() - rewritePtr);
|
||||
if (remainingSize > 0)
|
||||
NOP(remainingSize);
|
||||
|
||||
//printf("rewriting memory access %p %d %d\n", patch.PatchFunc, patch.Offset, patch.Size);
|
||||
|
||||
SetCodePtr(curCodePtr);
|
||||
|
||||
return patch.Offset;
|
||||
}
|
||||
|
||||
printf("this is a JIT bug %x\n", pc);
|
||||
abort();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -91,369 +114,213 @@ void Compiler::Comp_MemAccess(int rd, int rn, const Op2& op2, int size, int flag
|
|||
return;
|
||||
}
|
||||
|
||||
if (flags & memop_Store)
|
||||
{
|
||||
if (flags & memop_Store)
|
||||
Comp_AddCycles_CD();
|
||||
}
|
||||
else
|
||||
{
|
||||
Comp_AddCycles_CDI();
|
||||
}
|
||||
|
||||
bool addrIsStatic = Config::JIT_LiteralOptimisations
|
||||
&& RegCache.IsLiteral(rn) && op2.IsImm && !(flags & (memop_Writeback|memop_Post));
|
||||
u32 staticAddress;
|
||||
if (addrIsStatic)
|
||||
staticAddress = RegCache.LiteralValues[rn] + op2.Imm * ((flags & memop_SubtractOffset) ? -1 : 1);
|
||||
OpArg rdMapped = MapReg(rd);
|
||||
|
||||
OpArg rnMapped = MapReg(rn);
|
||||
if (Thumb && rn == 15)
|
||||
rnMapped = Imm32(R15 & ~0x2);
|
||||
|
||||
X64Reg finalAddr = RSCRATCH3;
|
||||
if (flags & memop_Post)
|
||||
{
|
||||
MOV(32, R(RSCRATCH3), rnMapped);
|
||||
|
||||
finalAddr = rnMapped.GetSimpleReg();
|
||||
}
|
||||
|
||||
if (op2.IsImm)
|
||||
{
|
||||
MOV_sum(32, finalAddr, rnMapped, Imm32(op2.Imm * ((flags & memop_SubtractOffset) ? -1 : 1)));
|
||||
}
|
||||
else
|
||||
{
|
||||
OpArg rm = MapReg(op2.Reg.Reg);
|
||||
|
||||
if (!(flags & memop_SubtractOffset) && rm.IsSimpleReg() && rnMapped.IsSimpleReg()
|
||||
&& op2.Reg.Op == 0 && op2.Reg.Amount > 0 && op2.Reg.Amount <= 3)
|
||||
{
|
||||
Comp_AddCycles_CD();
|
||||
LEA(32, finalAddr,
|
||||
MComplex(rnMapped.GetSimpleReg(), rm.GetSimpleReg(), 1 << op2.Reg.Amount, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
Comp_AddCycles_CDI();
|
||||
}
|
||||
bool throwAway;
|
||||
OpArg offset =
|
||||
Comp_RegShiftImm(op2.Reg.Op, op2.Reg.Amount, rm, false, throwAway);
|
||||
|
||||
bool addrIsStatic = Config::JIT_LiteralOptimisations
|
||||
&& RegCache.IsLiteral(rn) && op2.IsImm && !(flags & (memop_Writeback|memop_Post));
|
||||
u32 staticAddress;
|
||||
if (addrIsStatic)
|
||||
staticAddress = RegCache.LiteralValues[rn] + op2.Imm * ((flags & memop_SubtractOffset) ? -1 : 1);
|
||||
OpArg rdMapped = MapReg(rd);
|
||||
|
||||
if (true)
|
||||
{
|
||||
OpArg rnMapped = MapReg(rn);
|
||||
if (Thumb && rn == 15)
|
||||
rnMapped = Imm32(R15 & ~0x2);
|
||||
|
||||
X64Reg finalAddr = RSCRATCH3;
|
||||
if (flags & memop_Post)
|
||||
if (flags & memop_SubtractOffset)
|
||||
{
|
||||
MOV(32, R(RSCRATCH3), rnMapped);
|
||||
|
||||
finalAddr = rnMapped.GetSimpleReg();
|
||||
}
|
||||
|
||||
if (op2.IsImm)
|
||||
{
|
||||
MOV_sum(32, finalAddr, rnMapped, Imm32(op2.Imm * ((flags & memop_SubtractOffset) ? -1 : 1)));
|
||||
if (R(finalAddr) != rnMapped)
|
||||
MOV(32, R(finalAddr), rnMapped);
|
||||
if (!offset.IsZero())
|
||||
SUB(32, R(finalAddr), offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
OpArg rm = MapReg(op2.Reg.Reg);
|
||||
MOV_sum(32, finalAddr, rnMapped, offset);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flags & memop_SubtractOffset) && rm.IsSimpleReg() && rnMapped.IsSimpleReg()
|
||||
&& op2.Reg.Op == 0 && op2.Reg.Amount > 0 && op2.Reg.Amount <= 3)
|
||||
{
|
||||
LEA(32, finalAddr,
|
||||
MComplex(rnMapped.GetSimpleReg(), rm.GetSimpleReg(), 1 << op2.Reg.Amount, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
bool throwAway;
|
||||
OpArg offset =
|
||||
Comp_RegShiftImm(op2.Reg.Op, op2.Reg.Amount, rm, false, throwAway);
|
||||
if ((flags & memop_Writeback) && !(flags & memop_Post))
|
||||
MOV(32, rnMapped, R(finalAddr));
|
||||
|
||||
if (flags & memop_SubtractOffset)
|
||||
{
|
||||
if (R(finalAddr) != rnMapped)
|
||||
MOV(32, R(finalAddr), rnMapped);
|
||||
if (!offset.IsZero())
|
||||
SUB(32, R(finalAddr), offset);
|
||||
}
|
||||
else
|
||||
MOV_sum(32, finalAddr, rnMapped, offset);
|
||||
}
|
||||
}
|
||||
u32 expectedTarget = Num == 0
|
||||
? ARMJIT_Memory::ClassifyAddress9(CurInstr.DataRegion)
|
||||
: ARMJIT_Memory::ClassifyAddress7(CurInstr.DataRegion);
|
||||
|
||||
if ((flags & memop_Writeback) && !(flags & memop_Post))
|
||||
MOV(32, rnMapped, R(finalAddr));
|
||||
if (Config::JIT_FastMemory && ((!Thumb && CurInstr.Cond() != 0xE) || ARMJIT_Memory::IsFastmemCompatible(expectedTarget)))
|
||||
{
|
||||
u8* memopStart = GetWritableCodePtr();
|
||||
LoadStorePatch patch;
|
||||
|
||||
patch.PatchFunc = flags & memop_Store
|
||||
? PatchedStoreFuncs[NDS::ConsoleType][Num][__builtin_ctz(size) - 3][rdMapped.GetSimpleReg()]
|
||||
: PatchedLoadFuncs[NDS::ConsoleType][Num][__builtin_ctz(size) - 3][!!(flags & memop_SignExtend)][rdMapped.GetSimpleReg()];
|
||||
|
||||
assert(patch.PatchFunc != NULL);
|
||||
|
||||
MOV(64, R(RSCRATCH), ImmPtr(Num == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start));
|
||||
|
||||
X64Reg maskedAddr = RSCRATCH3;
|
||||
if (size > 8)
|
||||
{
|
||||
maskedAddr = RSCRATCH2;
|
||||
MOV(32, R(RSCRATCH2), R(RSCRATCH3));
|
||||
AND(32, R(RSCRATCH2), Imm8(addressMask));
|
||||
}
|
||||
|
||||
/*int expectedTarget = Num == 0
|
||||
? ClassifyAddress9(addrIsStatic ? staticAddress : CurInstr.DataRegion)
|
||||
: ClassifyAddress7(addrIsStatic ? staticAddress : CurInstr.DataRegion);
|
||||
if (CurInstr.Cond() < 0xE)
|
||||
expectedTarget = memregion_Other;
|
||||
|
||||
bool compileFastPath = false, compileSlowPath = !addrIsStatic || (flags & memop_Store);
|
||||
|
||||
switch (expectedTarget)
|
||||
u8* memopLoadStoreLocation = GetWritableCodePtr();
|
||||
if (flags & memop_Store)
|
||||
{
|
||||
case memregion_MainRAM:
|
||||
case memregion_DTCM:
|
||||
case memregion_WRAM7:
|
||||
case memregion_SWRAM9:
|
||||
case memregion_SWRAM7:
|
||||
case memregion_IO9:
|
||||
case memregion_IO7:
|
||||
case memregion_VWRAM:
|
||||
compileFastPath = true;
|
||||
break;
|
||||
case memregion_Wifi:
|
||||
compileFastPath = size >= 16;
|
||||
break;
|
||||
case memregion_VRAM:
|
||||
compileFastPath = !(flags & memop_Store) || size >= 16;
|
||||
case memregion_BIOS9:
|
||||
compileFastPath = !(flags & memop_Store);
|
||||
break;
|
||||
default: break;
|
||||
MOV(size, MRegSum(RSCRATCH, maskedAddr), rdMapped);
|
||||
}
|
||||
|
||||
if (addrIsStatic && !compileFastPath)
|
||||
else
|
||||
{
|
||||
compileFastPath = false;
|
||||
compileSlowPath = true;
|
||||
}
|
||||
|
||||
if (addrIsStatic && compileSlowPath)
|
||||
MOV(32, R(RSCRATCH3), Imm32(staticAddress));
|
||||
*/
|
||||
/*if (compileFastPath)
|
||||
{
|
||||
FixupBranch slowPath;
|
||||
if (compileSlowPath)
|
||||
{
|
||||
MOV(32, R(RSCRATCH), R(RSCRATCH3));
|
||||
SHR(32, R(RSCRATCH), Imm8(9));
|
||||
if (flags & memop_Store)
|
||||
{
|
||||
CMP(8, MDisp(RSCRATCH, squeezePointer(Num == 0 ? MemoryStatus9 : MemoryStatus7)), Imm8(expectedTarget));
|
||||
}
|
||||
else
|
||||
{
|
||||
MOVZX(32, 8, RSCRATCH, MDisp(RSCRATCH, squeezePointer(Num == 0 ? MemoryStatus9 : MemoryStatus7)));
|
||||
AND(32, R(RSCRATCH), Imm8(~0x80));
|
||||
CMP(32, R(RSCRATCH), Imm8(expectedTarget));
|
||||
}
|
||||
|
||||
slowPath = J_CC(CC_NE, true);
|
||||
}
|
||||
|
||||
if (expectedTarget == memregion_MainRAM || expectedTarget == memregion_WRAM7
|
||||
|| expectedTarget == memregion_BIOS9)
|
||||
{
|
||||
u8* data;
|
||||
u32 mask;
|
||||
if (expectedTarget == memregion_MainRAM)
|
||||
{
|
||||
data = NDS::MainRAM;
|
||||
mask = MAIN_RAM_SIZE - 1;
|
||||
}
|
||||
else if (expectedTarget == memregion_BIOS9)
|
||||
{
|
||||
data = NDS::ARM9BIOS;
|
||||
mask = 0xFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
data = NDS::ARM7WRAM;
|
||||
mask = 0xFFFF;
|
||||
}
|
||||
OpArg memLoc;
|
||||
if (addrIsStatic)
|
||||
{
|
||||
memLoc = M(data + ((staticAddress & mask & addressMask)));
|
||||
}
|
||||
else
|
||||
{
|
||||
MOV(32, R(RSCRATCH), R(RSCRATCH3));
|
||||
AND(32, R(RSCRATCH), Imm32(mask & addressMask));
|
||||
memLoc = MDisp(RSCRATCH, squeezePointer(data));
|
||||
}
|
||||
if (flags & memop_Store)
|
||||
MOV(size, memLoc, rdMapped);
|
||||
else if (flags & memop_SignExtend)
|
||||
MOVSX(32, size, rdMapped.GetSimpleReg(), memLoc);
|
||||
else
|
||||
MOVZX(32, size, rdMapped.GetSimpleReg(), memLoc);
|
||||
}
|
||||
else if (expectedTarget == memregion_DTCM)
|
||||
{
|
||||
if (addrIsStatic)
|
||||
MOV(32, R(RSCRATCH), Imm32(staticAddress));
|
||||
else
|
||||
MOV(32, R(RSCRATCH), R(RSCRATCH3));
|
||||
SUB(32, R(RSCRATCH), MDisp(RCPU, offsetof(ARMv5, DTCMBase)));
|
||||
AND(32, R(RSCRATCH), Imm32(0x3FFF & addressMask));
|
||||
OpArg memLoc = MComplex(RCPU, RSCRATCH, SCALE_1, offsetof(ARMv5, DTCM));
|
||||
if (flags & memop_Store)
|
||||
MOV(size, memLoc, rdMapped);
|
||||
else if (flags & memop_SignExtend)
|
||||
MOVSX(32, size, rdMapped.GetSimpleReg(), memLoc);
|
||||
else
|
||||
MOVZX(32, size, rdMapped.GetSimpleReg(), memLoc);
|
||||
}
|
||||
else if (expectedTarget == memregion_SWRAM9 || expectedTarget == memregion_SWRAM7)
|
||||
{
|
||||
MOV(64, R(RSCRATCH2), M(expectedTarget == memregion_SWRAM9 ? &NDS::SWRAM_ARM9 : &NDS::SWRAM_ARM7));
|
||||
if (addrIsStatic)
|
||||
{
|
||||
MOV(32, R(RSCRATCH), Imm32(staticAddress & addressMask));
|
||||
}
|
||||
else
|
||||
{
|
||||
MOV(32, R(RSCRATCH), R(RSCRATCH3));
|
||||
AND(32, R(RSCRATCH), Imm8(addressMask));
|
||||
}
|
||||
AND(32, R(RSCRATCH), M(expectedTarget == memregion_SWRAM9 ? &NDS::SWRAM_ARM9Mask : &NDS::SWRAM_ARM7Mask));
|
||||
OpArg memLoc = MRegSum(RSCRATCH, RSCRATCH2);
|
||||
if (flags & memop_Store)
|
||||
MOV(size, memLoc, rdMapped);
|
||||
else if (flags & memop_SignExtend)
|
||||
MOVSX(32, size, rdMapped.GetSimpleReg(), memLoc);
|
||||
else
|
||||
MOVZX(32, size, rdMapped.GetSimpleReg(), memLoc);
|
||||
}
|
||||
if (flags & memop_SignExtend)
|
||||
MOVSX(32, size, rdMapped.GetSimpleReg(), MRegSum(RSCRATCH, maskedAddr));
|
||||
else
|
||||
MOVZX(32, size, rdMapped.GetSimpleReg(), MRegSum(RSCRATCH, maskedAddr));
|
||||
|
||||
if (size == 32)
|
||||
{
|
||||
u32 maskedDataRegion;
|
||||
|
||||
if (addrIsStatic)
|
||||
{
|
||||
maskedDataRegion = staticAddress;
|
||||
MOV(32, R(ABI_PARAM1), Imm32(staticAddress));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ABI_PARAM1 != RSCRATCH3)
|
||||
MOV(32, R(ABI_PARAM1), R(RSCRATCH3));
|
||||
AND(32, R(ABI_PARAM1), Imm8(addressMask));
|
||||
|
||||
maskedDataRegion = CurInstr.DataRegion;
|
||||
if (Num == 0)
|
||||
maskedDataRegion &= ~0xFFFFFF;
|
||||
else
|
||||
maskedDataRegion &= ~0x7FFFFF;
|
||||
}
|
||||
|
||||
void* func = GetFuncForAddr(CurCPU, maskedDataRegion, flags & memop_Store, size);
|
||||
|
||||
if (flags & memop_Store)
|
||||
{
|
||||
PushRegs(false);
|
||||
|
||||
MOV(32, R(ABI_PARAM2), rdMapped);
|
||||
|
||||
ABI_CallFunction((void(*)())func);
|
||||
|
||||
PopRegs(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!addrIsStatic)
|
||||
MOV(32, rdMapped, R(RSCRATCH3));
|
||||
|
||||
PushRegs(false);
|
||||
|
||||
ABI_CallFunction((void(*)())func);
|
||||
|
||||
PopRegs(false);
|
||||
|
||||
if (!addrIsStatic)
|
||||
MOV(32, R(RSCRATCH3), rdMapped);
|
||||
|
||||
if (flags & memop_SignExtend)
|
||||
MOVSX(32, size, rdMapped.GetSimpleReg(), R(RSCRATCH));
|
||||
else
|
||||
MOVZX(32, size, rdMapped.GetSimpleReg(), R(RSCRATCH));
|
||||
}
|
||||
}
|
||||
|
||||
if ((size == 32 && !(flags & memop_Store)))
|
||||
{
|
||||
if (addrIsStatic)
|
||||
{
|
||||
if (staticAddress & 0x3)
|
||||
ROR_(32, rdMapped, Imm8((staticAddress & 0x3) * 8));
|
||||
}
|
||||
else
|
||||
{
|
||||
AND(32, R(RSCRATCH3), Imm8(0x3));
|
||||
SHL(32, R(RSCRATCH3), Imm8(3));
|
||||
ROR_(32, rdMapped, R(RSCRATCH3));
|
||||
}
|
||||
}
|
||||
|
||||
if (compileSlowPath)
|
||||
{
|
||||
SwitchToFarCode();
|
||||
SetJumpTarget(slowPath);
|
||||
AND(32, R(RSCRATCH3), Imm8(0x3));
|
||||
SHL(32, R(RSCRATCH3), Imm8(3));
|
||||
ROR_(32, rdMapped, R(RSCRATCH3));
|
||||
}
|
||||
}
|
||||
*/
|
||||
if (true)
|
||||
|
||||
patch.Offset = memopStart - memopLoadStoreLocation;
|
||||
patch.Size = GetWritableCodePtr() - memopStart;
|
||||
|
||||
assert(patch.Size >= 5);
|
||||
|
||||
LoadStorePatches[memopLoadStoreLocation] = patch;
|
||||
}
|
||||
else
|
||||
{
|
||||
PushRegs(false);
|
||||
|
||||
if (Num == 0)
|
||||
{
|
||||
PushRegs(false);
|
||||
|
||||
if (Num == 0)
|
||||
MOV(64, R(ABI_PARAM2), R(RCPU));
|
||||
if (ABI_PARAM1 != RSCRATCH3)
|
||||
MOV(32, R(ABI_PARAM1), R(RSCRATCH3));
|
||||
if (flags & memop_Store)
|
||||
{
|
||||
MOV(64, R(ABI_PARAM2), R(RCPU));
|
||||
if (ABI_PARAM1 != RSCRATCH3)
|
||||
MOV(32, R(ABI_PARAM1), R(RSCRATCH3));
|
||||
if (flags & memop_Store)
|
||||
{
|
||||
MOV(32, R(ABI_PARAM3), rdMapped);
|
||||
MOV(32, R(ABI_PARAM3), rdMapped);
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case 32: CALL((void*)&SlowWrite9<u32>); break;
|
||||
case 16: CALL((void*)&SlowWrite9<u16>); break;
|
||||
case 8: CALL((void*)&SlowWrite9<u8>); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
switch (size | NDS::ConsoleType)
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case 32: CALL((void*)&SlowRead9<u32>); break;
|
||||
case 16: CALL((void*)&SlowRead9<u16>); break;
|
||||
case 8: CALL((void*)&SlowRead9<u8>); break;
|
||||
}
|
||||
case 32: CALL((void*)&SlowWrite9<u32, 0>); break;
|
||||
case 16: CALL((void*)&SlowWrite9<u16, 0>); break;
|
||||
case 8: CALL((void*)&SlowWrite9<u8, 0>); break;
|
||||
case 33: CALL((void*)&SlowWrite9<u32, 1>); break;
|
||||
case 17: CALL((void*)&SlowWrite9<u16, 1>); break;
|
||||
case 9: CALL((void*)&SlowWrite9<u8, 1>); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ABI_PARAM1 != RSCRATCH3)
|
||||
MOV(32, R(ABI_PARAM1), R(RSCRATCH3));
|
||||
if (flags & memop_Store)
|
||||
switch (size | NDS::ConsoleType)
|
||||
{
|
||||
MOV(32, R(ABI_PARAM2), rdMapped);
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case 32: CALL((void*)&SlowWrite7<u32>); break;
|
||||
case 16: CALL((void*)&SlowWrite7<u16>); break;
|
||||
case 8: CALL((void*)&SlowWrite7<u8>); break;
|
||||
}
|
||||
case 32: CALL((void*)&SlowRead9<u32, 0>); break;
|
||||
case 16: CALL((void*)&SlowRead9<u16, 0>); break;
|
||||
case 8: CALL((void*)&SlowRead9<u8, 0>); break;
|
||||
case 33: CALL((void*)&SlowRead9<u32, 1>); break;
|
||||
case 17: CALL((void*)&SlowRead9<u16, 1>); break;
|
||||
case 9: CALL((void*)&SlowRead9<u8, 1>); break;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case 32: CALL((void*)&SlowRead7<u32>); break;
|
||||
case 16: CALL((void*)&SlowRead7<u16>); break;
|
||||
case 8: CALL((void*)&SlowRead7<u8>); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PopRegs(false);
|
||||
|
||||
if (!(flags & memop_Store))
|
||||
{
|
||||
if (flags & memop_SignExtend)
|
||||
MOVSX(32, size, rdMapped.GetSimpleReg(), R(RSCRATCH));
|
||||
else
|
||||
MOVZX(32, size, rdMapped.GetSimpleReg(), R(RSCRATCH));
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (compileFastPath && compileSlowPath)
|
||||
else
|
||||
{
|
||||
FixupBranch ret = J(true);
|
||||
SwitchToNearCode();
|
||||
SetJumpTarget(ret);
|
||||
}*/
|
||||
|
||||
if (!(flags & memop_Store) && rd == 15)
|
||||
{
|
||||
if (size < 32)
|
||||
printf("!!! LDR <32 bit PC %08X %x\n", R15, CurInstr.Instr);
|
||||
if (ABI_PARAM1 != RSCRATCH3)
|
||||
MOV(32, R(ABI_PARAM1), R(RSCRATCH3));
|
||||
if (flags & memop_Store)
|
||||
{
|
||||
if (Num == 1)
|
||||
AND(32, rdMapped, Imm8(0xFE)); // immediate is sign extended
|
||||
Comp_JumpTo(rdMapped.GetSimpleReg());
|
||||
MOV(32, R(ABI_PARAM2), rdMapped);
|
||||
|
||||
switch (size | NDS::ConsoleType)
|
||||
{
|
||||
case 32: CALL((void*)&SlowWrite7<u32, 0>); break;
|
||||
case 16: CALL((void*)&SlowWrite7<u16, 0>); break;
|
||||
case 8: CALL((void*)&SlowWrite7<u8, 0>); break;
|
||||
case 33: CALL((void*)&SlowWrite7<u32, 1>); break;
|
||||
case 17: CALL((void*)&SlowWrite7<u16, 1>); break;
|
||||
case 9: CALL((void*)&SlowWrite7<u8, 1>); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (size | NDS::ConsoleType)
|
||||
{
|
||||
case 32: CALL((void*)&SlowRead7<u32, 0>); break;
|
||||
case 16: CALL((void*)&SlowRead7<u16, 0>); break;
|
||||
case 8: CALL((void*)&SlowRead7<u8, 0>); break;
|
||||
case 33: CALL((void*)&SlowRead7<u32, 1>); break;
|
||||
case 17: CALL((void*)&SlowRead7<u16, 1>); break;
|
||||
case 9: CALL((void*)&SlowRead7<u8, 1>); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PopRegs(false);
|
||||
|
||||
if (!(flags & memop_Store))
|
||||
{
|
||||
if (flags & memop_SignExtend)
|
||||
MOVSX(32, size, rdMapped.GetSimpleReg(), R(RSCRATCH));
|
||||
else
|
||||
MOVZX(32, size, rdMapped.GetSimpleReg(), R(RSCRATCH));
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flags & memop_Store) && rd == 15)
|
||||
{
|
||||
if (size < 32)
|
||||
printf("!!! LDR <32 bit PC %08X %x\n", R15, CurInstr.Instr);
|
||||
{
|
||||
if (Num == 1)
|
||||
{
|
||||
if (Thumb)
|
||||
OR(32, rdMapped, Imm8(0x1));
|
||||
else
|
||||
AND(32, rdMapped, Imm8(0xFE));
|
||||
}
|
||||
Comp_JumpTo(rdMapped.GetSimpleReg());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -470,7 +337,7 @@ s32 Compiler::Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc
|
|||
int flags = 0;
|
||||
if (store)
|
||||
flags |= memop_Store;
|
||||
if (decrement)
|
||||
if (decrement && preinc)
|
||||
flags |= memop_SubtractOffset;
|
||||
Op2 offset = preinc ? Op2(4) : Op2(0);
|
||||
|
||||
|
@ -481,96 +348,52 @@ s32 Compiler::Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc
|
|||
|
||||
s32 offset = (regsCount * 4) * (decrement ? -1 : 1);
|
||||
|
||||
// we need to make sure that the stack stays aligned to 16 bytes
|
||||
#ifdef _WIN32
|
||||
// include shadow
|
||||
u32 stackAlloc = ((regsCount + 4 + 1) & ~1) * 8;
|
||||
#else
|
||||
u32 stackAlloc = ((regsCount + 1) & ~1) * 8;
|
||||
#endif
|
||||
u32 allocOffset = stackAlloc - regsCount * 8;
|
||||
/*
|
||||
int expectedTarget = Num == 0
|
||||
? ClassifyAddress9(CurInstr.DataRegion)
|
||||
: ClassifyAddress7(CurInstr.DataRegion);
|
||||
if (usermode || CurInstr.Cond() < 0xE)
|
||||
expectedTarget = memregion_Other;
|
||||
? ARMJIT_Memory::ClassifyAddress9(CurInstr.DataRegion)
|
||||
: ARMJIT_Memory::ClassifyAddress7(CurInstr.DataRegion);
|
||||
|
||||
bool compileFastPath = false;
|
||||
|
||||
switch (expectedTarget)
|
||||
{
|
||||
case memregion_DTCM:
|
||||
case memregion_MainRAM:
|
||||
case memregion_SWRAM9:
|
||||
case memregion_SWRAM7:
|
||||
case memregion_WRAM7:
|
||||
compileFastPath = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
*/
|
||||
if (!store)
|
||||
Comp_AddCycles_CDI();
|
||||
else
|
||||
Comp_AddCycles_CD();
|
||||
|
||||
bool compileFastPath = Config::JIT_FastMemory
|
||||
&& !usermode && (CurInstr.Cond() < 0xE || ARMJIT_Memory::IsFastmemCompatible(expectedTarget));
|
||||
|
||||
// we need to make sure that the stack stays aligned to 16 bytes
|
||||
#ifdef _WIN32
|
||||
// include shadow
|
||||
u32 stackAlloc = (((regsCount + 4 + 1) & ~1) + (compileFastPath ? 1 : 0)) * 8;
|
||||
#else
|
||||
u32 stackAlloc = (((regsCount + 1) & ~1) + (compileFastPath ? 1 : 0)) * 8;
|
||||
#endif
|
||||
u32 allocOffset = stackAlloc - regsCount * 8;
|
||||
|
||||
if (decrement)
|
||||
{
|
||||
MOV_sum(32, RSCRATCH4, MapReg(rn), Imm32(-regsCount * 4));
|
||||
preinc ^= true;
|
||||
}
|
||||
MOV_sum(32, RSCRATCH4, MapReg(rn), Imm32(-regsCount * 4 + (preinc ? 0 : 4)));
|
||||
else
|
||||
MOV(32, R(RSCRATCH4), MapReg(rn));
|
||||
/*
|
||||
MOV_sum(32, RSCRATCH4, MapReg(rn), Imm32(preinc ? 4 : 0));
|
||||
|
||||
if (compileFastPath)
|
||||
{
|
||||
assert(!usermode);
|
||||
AND(32, R(RSCRATCH4), Imm8(~3));
|
||||
|
||||
MOV(32, R(RSCRATCH), R(RSCRATCH4));
|
||||
SHR(32, R(RSCRATCH), Imm8(9));
|
||||
u8* fastPathStart = GetWritableCodePtr();
|
||||
u8* firstLoadStoreAddr;
|
||||
|
||||
if (store)
|
||||
{
|
||||
CMP(8, MDisp(RSCRATCH, squeezePointer(Num == 0 ? MemoryStatus9 : MemoryStatus7)), Imm8(expectedTarget));
|
||||
}
|
||||
else
|
||||
{
|
||||
MOVZX(32, 8, RSCRATCH, MDisp(RSCRATCH, squeezePointer(Num == 0 ? MemoryStatus9 : MemoryStatus7)));
|
||||
AND(32, R(RSCRATCH), Imm8(~0x80));
|
||||
CMP(32, R(RSCRATCH), Imm8(expectedTarget));
|
||||
}
|
||||
FixupBranch slowPath = J_CC(CC_NE, true);
|
||||
bool firstLoadStore = true;
|
||||
|
||||
MOV(64, R(RSCRATCH2), ImmPtr(Num == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start));
|
||||
ADD(64, R(RSCRATCH2), R(RSCRATCH4));
|
||||
MOV(32, R(RSCRATCH3), R(RSCRATCH4));
|
||||
|
||||
if (expectedTarget == memregion_DTCM)
|
||||
{
|
||||
SUB(32, R(RSCRATCH4), MDisp(RCPU, offsetof(ARMv5, DTCMBase)));
|
||||
AND(32, R(RSCRATCH4), Imm32(0x3FFF & ~3));
|
||||
LEA(64, RSCRATCH4, MComplex(RCPU, RSCRATCH4, 1, offsetof(ARMv5, DTCM)));
|
||||
}
|
||||
else if (expectedTarget == memregion_MainRAM)
|
||||
{
|
||||
AND(32, R(RSCRATCH4), Imm32((MAIN_RAM_SIZE - 1) & ~3));
|
||||
ADD(64, R(RSCRATCH4), Imm32(squeezePointer(NDS::MainRAM)));
|
||||
}
|
||||
else if (expectedTarget == memregion_WRAM7)
|
||||
{
|
||||
AND(32, R(RSCRATCH4), Imm32(0xFFFF & ~3));
|
||||
ADD(64, R(RSCRATCH4), Imm32(squeezePointer(NDS::ARM7WRAM)));
|
||||
}
|
||||
else // SWRAM
|
||||
{
|
||||
AND(32, R(RSCRATCH4), Imm8(~3));
|
||||
AND(32, R(RSCRATCH4), M(expectedTarget == memregion_SWRAM9 ? &NDS::SWRAM_ARM9Mask : &NDS::SWRAM_ARM7Mask));
|
||||
ADD(64, R(RSCRATCH4), M(expectedTarget == memregion_SWRAM9 ? &NDS::SWRAM_ARM9 : &NDS::SWRAM_ARM7));
|
||||
}
|
||||
u32 offset = 0;
|
||||
for (int reg : regs)
|
||||
{
|
||||
if (preinc)
|
||||
offset += 4;
|
||||
OpArg mem = MDisp(RSCRATCH4, offset);
|
||||
if (firstLoadStore)
|
||||
firstLoadStoreAddr = GetWritableCodePtr();
|
||||
|
||||
OpArg mem = MDisp(RSCRATCH2, offset);
|
||||
if (store)
|
||||
{
|
||||
if (RegCache.LoadedRegs & (1 << reg))
|
||||
|
@ -580,6 +403,8 @@ s32 Compiler::Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc
|
|||
else
|
||||
{
|
||||
LoadReg(reg, RSCRATCH);
|
||||
if (firstLoadStore)
|
||||
firstLoadStoreAddr = GetWritableCodePtr();
|
||||
MOV(32, mem, R(RSCRATCH));
|
||||
}
|
||||
}
|
||||
|
@ -595,13 +420,19 @@ s32 Compiler::Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc
|
|||
SaveReg(reg, RSCRATCH);
|
||||
}
|
||||
}
|
||||
if (!preinc)
|
||||
offset += 4;
|
||||
offset += 4;
|
||||
|
||||
firstLoadStore = false;
|
||||
}
|
||||
|
||||
LoadStorePatch patch;
|
||||
patch.Size = GetWritableCodePtr() - fastPathStart;
|
||||
patch.Offset = fastPathStart - firstLoadStoreAddr;
|
||||
SwitchToFarCode();
|
||||
SetJumpTarget(slowPath);
|
||||
}*/
|
||||
patch.PatchFunc = GetWritableCodePtr();
|
||||
|
||||
LoadStorePatches[firstLoadStoreAddr] = patch;
|
||||
}
|
||||
|
||||
if (!store)
|
||||
{
|
||||
|
@ -618,12 +449,12 @@ s32 Compiler::Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc
|
|||
if (Num == 0)
|
||||
MOV(64, R(ABI_PARAM4), R(RCPU));
|
||||
|
||||
switch (Num * 2 | preinc)
|
||||
switch (Num * 2 | NDS::ConsoleType)
|
||||
{
|
||||
case 0: CALL((void*)&SlowBlockTransfer9<false, false>); break;
|
||||
case 1: CALL((void*)&SlowBlockTransfer9<true, false>); break;
|
||||
case 2: CALL((void*)&SlowBlockTransfer7<false, false>); break;
|
||||
case 3: CALL((void*)&SlowBlockTransfer7<true, false>); break;
|
||||
case 0: CALL((void*)&SlowBlockTransfer9<false, 0>); break;
|
||||
case 1: CALL((void*)&SlowBlockTransfer9<false, 1>); break;
|
||||
case 2: CALL((void*)&SlowBlockTransfer7<false, 0>); break;
|
||||
case 3: CALL((void*)&SlowBlockTransfer7<false, 1>); break;
|
||||
}
|
||||
|
||||
PopRegs(false);
|
||||
|
@ -715,25 +546,24 @@ s32 Compiler::Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc
|
|||
if (Num == 0)
|
||||
MOV(64, R(ABI_PARAM4), R(RCPU));
|
||||
|
||||
switch (Num * 2 | preinc)
|
||||
switch (Num * 2 | NDS::ConsoleType)
|
||||
{
|
||||
case 0: CALL((void*)&SlowBlockTransfer9<false, true>); break;
|
||||
case 1: CALL((void*)&SlowBlockTransfer9<true, true>); break;
|
||||
case 2: CALL((void*)&SlowBlockTransfer7<false, true>); break;
|
||||
case 3: CALL((void*)&SlowBlockTransfer7<true, true>); break;
|
||||
case 0: CALL((void*)&SlowBlockTransfer9<true, 0>); break;
|
||||
case 1: CALL((void*)&SlowBlockTransfer9<true, 1>); break;
|
||||
case 2: CALL((void*)&SlowBlockTransfer7<true, 0>); break;
|
||||
case 3: CALL((void*)&SlowBlockTransfer7<true, 1>); break;
|
||||
}
|
||||
|
||||
ADD(64, R(RSP), stackAlloc <= INT8_MAX ? Imm8(stackAlloc) : Imm32(stackAlloc));
|
||||
|
||||
PopRegs(false);
|
||||
}
|
||||
/*
|
||||
|
||||
if (compileFastPath)
|
||||
{
|
||||
FixupBranch ret = J(true);
|
||||
RET();
|
||||
SwitchToNearCode();
|
||||
SetJumpTarget(ret);
|
||||
}*/
|
||||
}
|
||||
|
||||
if (!store && regs[15])
|
||||
{
|
||||
|
|
21
src/CP15.cpp
21
src/CP15.cpp
|
@ -608,6 +608,27 @@ void ARMv5::CP15Write(u32 id, u32 val)
|
|||
ITCMSetting = val;
|
||||
UpdateITCMSetting();
|
||||
return;
|
||||
|
||||
case 0xF00:
|
||||
//printf("cache debug index register %08X\n", val);
|
||||
return;
|
||||
|
||||
case 0xF10:
|
||||
//printf("cache debug instruction tag %08X\n", val);
|
||||
return;
|
||||
|
||||
case 0xF20:
|
||||
//printf("cache debug data tag %08X\n", val);
|
||||
return;
|
||||
|
||||
case 0xF30:
|
||||
//printf("cache debug instruction cache %08X\n", val);
|
||||
return;
|
||||
|
||||
case 0xF40:
|
||||
//printf("cache debug data cache %08X\n", val);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if ((id&0xF00)!=0x700)
|
||||
|
|
|
@ -40,14 +40,7 @@ char DSiNANDPath[1024];
|
|||
#ifdef JIT_ENABLED
|
||||
int JIT_Enable = false;
|
||||
int JIT_MaxBlockSize = 32;
|
||||
int JIT_BrancheOptimisations = 2;
|
||||
int JIT_LiteralOptimisations = true;
|
||||
#endif
|
||||
|
||||
#ifdef JIT_ENABLED
|
||||
int JIT_Enable = false;
|
||||
int JIT_MaxBlockSize = 32;
|
||||
int JIT_BrancheOptimisations = true;
|
||||
int JIT_BranchOptimisations = 2;
|
||||
int JIT_LiteralOptimisations = true;
|
||||
int JIT_FastMemory = true;
|
||||
#endif
|
||||
|
@ -66,16 +59,9 @@ ConfigEntry ConfigFile[] =
|
|||
#ifdef JIT_ENABLED
|
||||
{"JIT_Enable", 0, &JIT_Enable, 0, NULL, 0},
|
||||
{"JIT_MaxBlockSize", 0, &JIT_MaxBlockSize, 32, NULL, 0},
|
||||
{"JIT_BranchOptimisations", 0, &JIT_BrancheOptimisations, 2, NULL, 0},
|
||||
{"JIT_BranchOptimisations", 0, &JIT_BranchOptimisations, 2, NULL, 0},
|
||||
{"JIT_LiteralOptimisations", 0, &JIT_LiteralOptimisations, 1, NULL, 0},
|
||||
#endif
|
||||
|
||||
#ifdef JIT_ENABLED
|
||||
{"JIT_Enable", 0, &JIT_Enable, 0, NULL, 0},
|
||||
{"JIT_MaxBlockSize", 0, &JIT_MaxBlockSize, 32, NULL, 0},
|
||||
{"JIT_BranchOptimisations", 0, &JIT_BrancheOptimisations, 1, NULL, 0},
|
||||
{"JIT_LiteralOptimisations", 0, &JIT_LiteralOptimisations, 1, NULL, 0},
|
||||
{"JIT_FastMem", 0, &JIT_FastMemory, 1, NULL, 0},
|
||||
{"JIT_FastMemory", 0, &JIT_FastMemory, 1, NULL, 0},
|
||||
#endif
|
||||
|
||||
{"", -1, NULL, 0, NULL, 0}
|
||||
|
|
|
@ -54,14 +54,7 @@ extern char DSiNANDPath[1024];
|
|||
#ifdef JIT_ENABLED
|
||||
extern int JIT_Enable;
|
||||
extern int JIT_MaxBlockSize;
|
||||
extern int JIT_BrancheOptimisations;
|
||||
extern int JIT_LiteralOptimisations;
|
||||
#endif
|
||||
|
||||
#ifdef JIT_ENABLED
|
||||
extern int JIT_Enable;
|
||||
extern int JIT_MaxBlockSize;
|
||||
extern int JIT_BrancheOptimisations;
|
||||
extern int JIT_BranchOptimisations;
|
||||
extern int JIT_LiteralOptimisations;
|
||||
extern int JIT_FastMemory;
|
||||
#endif
|
||||
|
|
167
src/DSi.cpp
167
src/DSi.cpp
|
@ -26,6 +26,11 @@
|
|||
#include "NDSCart.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#ifdef JIT_ENABLED
|
||||
#include "ARMJIT.h"
|
||||
#include "ARMJIT_Memory.h"
|
||||
#endif
|
||||
|
||||
#include "DSi_NDMA.h"
|
||||
#include "DSi_I2C.h"
|
||||
#include "DSi_SD.h"
|
||||
|
@ -34,15 +39,6 @@
|
|||
#include "tiny-AES-c/aes.hpp"
|
||||
|
||||
|
||||
namespace NDS
|
||||
{
|
||||
|
||||
extern ARMv5* ARM9;
|
||||
extern ARMv4* ARM7;
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace DSi
|
||||
{
|
||||
|
||||
|
@ -59,9 +55,9 @@ u8 ARM7iBIOS[0x10000];
|
|||
|
||||
u32 MBK[2][9];
|
||||
|
||||
u8 NWRAM_A[0x40000];
|
||||
u8 NWRAM_B[0x40000];
|
||||
u8 NWRAM_C[0x40000];
|
||||
u8* NWRAM_A;
|
||||
u8* NWRAM_B;
|
||||
u8* NWRAM_C;
|
||||
|
||||
u8* NWRAMMap_A[2][4];
|
||||
u8* NWRAMMap_B[3][8];
|
||||
|
@ -86,6 +82,12 @@ u8 ARM7Init[0x3C00];
|
|||
|
||||
bool Init()
|
||||
{
|
||||
#ifndef JIT_ENABLED
|
||||
NWRAM_A = new u8[NWRAMSize];
|
||||
NWRAM_B = new u8[NWRAMSize];
|
||||
NWRAM_C = new u8[NWRAMSize];
|
||||
#endif
|
||||
|
||||
if (!DSi_I2C::Init()) return false;
|
||||
if (!DSi_AES::Init()) return false;
|
||||
|
||||
|
@ -106,6 +108,12 @@ bool Init()
|
|||
|
||||
void DeInit()
|
||||
{
|
||||
#ifndef JIT_ENABLED
|
||||
delete[] NWRAM_A;
|
||||
delete[] NWRAM_B;
|
||||
delete[] NWRAM_C;
|
||||
#endif
|
||||
|
||||
DSi_I2C::DeInit();
|
||||
DSi_AES::DeInit();
|
||||
|
||||
|
@ -176,7 +184,12 @@ void SoftReset()
|
|||
NDS::ARM9->Reset();
|
||||
NDS::ARM7->Reset();
|
||||
|
||||
NDS::ARM9->CP15Reset();
|
||||
|
||||
memcpy(NDS::ARM9->ITCM, ITCMInit, 0x8000);
|
||||
#ifdef JIT_ENABLED
|
||||
ARMJIT::CheckAndInvalidateITCM();
|
||||
#endif
|
||||
|
||||
DSi_AES::Reset();
|
||||
|
||||
|
@ -274,9 +287,9 @@ bool LoadNAND()
|
|||
{
|
||||
printf("Loading DSi NAND\n");
|
||||
|
||||
memset(NWRAM_A, 0, 0x40000);
|
||||
memset(NWRAM_B, 0, 0x40000);
|
||||
memset(NWRAM_C, 0, 0x40000);
|
||||
memset(NWRAM_A, 0, NWRAMSize);
|
||||
memset(NWRAM_B, 0, NWRAMSize);
|
||||
memset(NWRAM_C, 0, NWRAMSize);
|
||||
|
||||
memset(MBK, 0, sizeof(MBK));
|
||||
memset(NWRAMMap_A, 0, sizeof(NWRAMMap_A));
|
||||
|
@ -527,6 +540,8 @@ void MapNWRAM_A(u32 num, u8 val)
|
|||
return;
|
||||
}
|
||||
|
||||
ARMJIT_Memory::RemapNWRAM(0);
|
||||
|
||||
int mbkn = 0, mbks = 8*num;
|
||||
|
||||
u8 oldval = (MBK[0][mbkn] >> mbks) & 0xFF;
|
||||
|
@ -558,6 +573,8 @@ void MapNWRAM_B(u32 num, u8 val)
|
|||
return;
|
||||
}
|
||||
|
||||
ARMJIT_Memory::RemapNWRAM(1);
|
||||
|
||||
int mbkn = 1+(num>>2), mbks = 8*(num&3);
|
||||
|
||||
u8 oldval = (MBK[0][mbkn] >> mbks) & 0xFF;
|
||||
|
@ -593,6 +610,8 @@ void MapNWRAM_C(u32 num, u8 val)
|
|||
return;
|
||||
}
|
||||
|
||||
ARMJIT_Memory::RemapNWRAM(2);
|
||||
|
||||
int mbkn = 3+(num>>2), mbks = 8*(num&3);
|
||||
|
||||
u8 oldval = (MBK[0][mbkn] >> mbks) & 0xFF;
|
||||
|
@ -625,6 +644,8 @@ void MapNWRAMRange(u32 cpu, u32 num, u32 val)
|
|||
u32 oldval = MBK[cpu][5+num];
|
||||
if (oldval == val) return;
|
||||
|
||||
ARMJIT_Memory::RemapNWRAM(num);
|
||||
|
||||
MBK[cpu][5+num] = val;
|
||||
|
||||
// TODO: what happens when the ranges are 'out of range'????
|
||||
|
@ -826,19 +847,31 @@ void ARM9Write8(u32 addr, u8 val)
|
|||
if (addr >= NWRAMStart[0][0] && addr < NWRAMEnd[0][0])
|
||||
{
|
||||
u8* ptr = NWRAMMap_A[0][(addr >> 16) & NWRAMMask[0][0]];
|
||||
if (ptr) *(u8*)&ptr[addr & 0xFFFF] = val;
|
||||
if (ptr)
|
||||
{
|
||||
*(u8*)&ptr[addr & 0xFFFF] = val;
|
||||
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_A>(addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (addr >= NWRAMStart[0][1] && addr < NWRAMEnd[0][1])
|
||||
{
|
||||
u8* ptr = NWRAMMap_B[0][(addr >> 15) & NWRAMMask[0][1]];
|
||||
if (ptr) *(u8*)&ptr[addr & 0x7FFF] = val;
|
||||
if (ptr)
|
||||
{
|
||||
*(u8*)&ptr[addr & 0x7FFF] = val;
|
||||
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_B>(addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (addr >= NWRAMStart[0][2] && addr < NWRAMEnd[0][2])
|
||||
{
|
||||
u8* ptr = NWRAMMap_C[0][(addr >> 15) & NWRAMMask[0][2]];
|
||||
if (ptr) *(u8*)&ptr[addr & 0x7FFF] = val;
|
||||
if (ptr)
|
||||
{
|
||||
*(u8*)&ptr[addr & 0x7FFF] = val;
|
||||
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_C>(addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return NDS::ARM9Write8(addr, val);
|
||||
|
@ -859,19 +892,31 @@ void ARM9Write16(u32 addr, u16 val)
|
|||
if (addr >= NWRAMStart[0][0] && addr < NWRAMEnd[0][0])
|
||||
{
|
||||
u8* ptr = NWRAMMap_A[0][(addr >> 16) & NWRAMMask[0][0]];
|
||||
if (ptr) *(u16*)&ptr[addr & 0xFFFF] = val;
|
||||
if (ptr)
|
||||
{
|
||||
*(u16*)&ptr[addr & 0xFFFF] = val;
|
||||
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_A>(addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (addr >= NWRAMStart[0][1] && addr < NWRAMEnd[0][1])
|
||||
{
|
||||
u8* ptr = NWRAMMap_B[0][(addr >> 15) & NWRAMMask[0][1]];
|
||||
if (ptr) *(u16*)&ptr[addr & 0x7FFF] = val;
|
||||
if (ptr)
|
||||
{
|
||||
*(u16*)&ptr[addr & 0x7FFF] = val;
|
||||
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_B>(addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (addr >= NWRAMStart[0][2] && addr < NWRAMEnd[0][2])
|
||||
{
|
||||
u8* ptr = NWRAMMap_C[0][(addr >> 15) & NWRAMMask[0][2]];
|
||||
if (ptr) *(u16*)&ptr[addr & 0x7FFF] = val;
|
||||
if (ptr)
|
||||
{
|
||||
*(u16*)&ptr[addr & 0x7FFF] = val;
|
||||
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_C>(addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return NDS::ARM9Write16(addr, val);
|
||||
|
@ -892,19 +937,31 @@ void ARM9Write32(u32 addr, u32 val)
|
|||
if (addr >= NWRAMStart[0][0] && addr < NWRAMEnd[0][0])
|
||||
{
|
||||
u8* ptr = NWRAMMap_A[0][(addr >> 16) & NWRAMMask[0][0]];
|
||||
if (ptr) *(u32*)&ptr[addr & 0xFFFF] = val;
|
||||
if (ptr)
|
||||
{
|
||||
*(u32*)&ptr[addr & 0xFFFF] = val;
|
||||
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_A>(addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (addr >= NWRAMStart[0][1] && addr < NWRAMEnd[0][1])
|
||||
{
|
||||
u8* ptr = NWRAMMap_B[0][(addr >> 15) & NWRAMMask[0][1]];
|
||||
if (ptr) *(u32*)&ptr[addr & 0x7FFF] = val;
|
||||
if (ptr)
|
||||
{
|
||||
*(u32*)&ptr[addr & 0x7FFF] = val;
|
||||
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_B>(addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (addr >= NWRAMStart[0][2] && addr < NWRAMEnd[0][2])
|
||||
{
|
||||
u8* ptr = NWRAMMap_C[0][(addr >> 15) & NWRAMMask[0][2]];
|
||||
if (ptr) *(u32*)&ptr[addr & 0x7FFF] = val;
|
||||
if (ptr)
|
||||
{
|
||||
*(u32*)&ptr[addr & 0x7FFF] = val;
|
||||
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_NewSharedWRAM_C>(addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return NDS::ARM9Write32(addr, val);
|
||||
|
@ -1085,19 +1142,37 @@ void ARM7Write8(u32 addr, u8 val)
|
|||
if (addr >= NWRAMStart[1][0] && addr < NWRAMEnd[1][0])
|
||||
{
|
||||
u8* ptr = NWRAMMap_A[1][(addr >> 16) & NWRAMMask[1][0]];
|
||||
if (ptr) *(u8*)&ptr[addr & 0xFFFF] = val;
|
||||
if (ptr)
|
||||
{
|
||||
*(u8*)&ptr[addr & 0xFFFF] = val;
|
||||
#ifdef JIT_ENABLED
|
||||
ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_NewSharedWRAM_A>(addr);
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (addr >= NWRAMStart[1][1] && addr < NWRAMEnd[1][1])
|
||||
{
|
||||
u8* ptr = NWRAMMap_B[1][(addr >> 15) & NWRAMMask[1][1]];
|
||||
if (ptr) *(u8*)&ptr[addr & 0x7FFF] = val;
|
||||
if (ptr)
|
||||
{
|
||||
*(u8*)&ptr[addr & 0x7FFF] = val;
|
||||
#ifdef JIT_ENABLED
|
||||
ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_NewSharedWRAM_B>(addr);
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (addr >= NWRAMStart[1][2] && addr < NWRAMEnd[1][2])
|
||||
{
|
||||
u8* ptr = NWRAMMap_C[1][(addr >> 15) & NWRAMMask[1][2]];
|
||||
if (ptr) *(u8*)&ptr[addr & 0x7FFF] = val;
|
||||
if (ptr)
|
||||
{
|
||||
*(u8*)&ptr[addr & 0x7FFF] = val;
|
||||
#ifdef JIT_ENABLED
|
||||
ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_NewSharedWRAM_C>(addr);
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
return NDS::ARM7Write8(addr, val);
|
||||
|
@ -1118,19 +1193,31 @@ void ARM7Write16(u32 addr, u16 val)
|
|||
if (addr >= NWRAMStart[1][0] && addr < NWRAMEnd[1][0])
|
||||
{
|
||||
u8* ptr = NWRAMMap_A[1][(addr >> 16) & NWRAMMask[1][0]];
|
||||
if (ptr) *(u16*)&ptr[addr & 0xFFFF] = val;
|
||||
if (ptr)
|
||||
{
|
||||
*(u16*)&ptr[addr & 0xFFFF] = val;
|
||||
ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_NewSharedWRAM_A>(addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (addr >= NWRAMStart[1][1] && addr < NWRAMEnd[1][1])
|
||||
{
|
||||
u8* ptr = NWRAMMap_B[1][(addr >> 15) & NWRAMMask[1][1]];
|
||||
if (ptr) *(u16*)&ptr[addr & 0x7FFF] = val;
|
||||
if (ptr)
|
||||
{
|
||||
*(u16*)&ptr[addr & 0x7FFF] = val;
|
||||
ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_NewSharedWRAM_B>(addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (addr >= NWRAMStart[1][2] && addr < NWRAMEnd[1][2])
|
||||
{
|
||||
u8* ptr = NWRAMMap_C[1][(addr >> 15) & NWRAMMask[1][2]];
|
||||
if (ptr) *(u16*)&ptr[addr & 0x7FFF] = val;
|
||||
if (ptr)
|
||||
{
|
||||
*(u16*)&ptr[addr & 0x7FFF] = val;
|
||||
ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_NewSharedWRAM_C>(addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return NDS::ARM7Write16(addr, val);
|
||||
|
@ -1151,19 +1238,31 @@ void ARM7Write32(u32 addr, u32 val)
|
|||
if (addr >= NWRAMStart[1][0] && addr < NWRAMEnd[1][0])
|
||||
{
|
||||
u8* ptr = NWRAMMap_A[1][(addr >> 16) & NWRAMMask[1][0]];
|
||||
if (ptr) *(u32*)&ptr[addr & 0xFFFF] = val;
|
||||
if (ptr)
|
||||
{
|
||||
*(u32*)&ptr[addr & 0xFFFF] = val;
|
||||
ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_NewSharedWRAM_A>(addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (addr >= NWRAMStart[1][1] && addr < NWRAMEnd[1][1])
|
||||
{
|
||||
u8* ptr = NWRAMMap_B[1][(addr >> 15) & NWRAMMask[1][1]];
|
||||
if (ptr) *(u32*)&ptr[addr & 0x7FFF] = val;
|
||||
if (ptr)
|
||||
{
|
||||
*(u32*)&ptr[addr & 0x7FFF] = val;
|
||||
ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_NewSharedWRAM_B>(addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (addr >= NWRAMStart[1][2] && addr < NWRAMEnd[1][2])
|
||||
{
|
||||
u8* ptr = NWRAMMap_C[1][(addr >> 15) & NWRAMMask[1][2]];
|
||||
if (ptr) *(u32*)&ptr[addr & 0x7FFF] = val;
|
||||
if (ptr)
|
||||
{
|
||||
*(u32*)&ptr[addr & 0x7FFF] = val;
|
||||
ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_NewSharedWRAM_C>(addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return NDS::ARM7Write32(addr, val);
|
||||
|
@ -1521,7 +1620,7 @@ u8 ARM7IORead8(u32 addr)
|
|||
case 0x04004501: return DSi_I2C::Cnt;
|
||||
|
||||
case 0x04004D00: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID & 0xFF;
|
||||
case 0x04004D01: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 8) & 0xFF;
|
||||
case 0x04004fD01: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 8) & 0xFF;
|
||||
case 0x04004D02: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 16) & 0xFF;
|
||||
case 0x04004D03: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 24) & 0xFF;
|
||||
case 0x04004D04: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 32) & 0xFF;
|
||||
|
|
15
src/DSi.h
15
src/DSi.h
|
@ -25,6 +25,8 @@
|
|||
namespace DSi
|
||||
{
|
||||
|
||||
extern u16 SCFG_BIOS;
|
||||
|
||||
extern u8 ARM9iBIOS[0x10000];
|
||||
extern u8 ARM7iBIOS[0x10000];
|
||||
|
||||
|
@ -34,6 +36,19 @@ extern u64 ConsoleID;
|
|||
extern DSi_SDHost* SDMMC;
|
||||
extern DSi_SDHost* SDIO;
|
||||
|
||||
const u32 NWRAMSize = 0x40000;
|
||||
|
||||
extern u8* NWRAM_A;
|
||||
extern u8* NWRAM_B;
|
||||
extern u8* NWRAM_C;
|
||||
|
||||
extern u8* NWRAMMap_A[2][4];
|
||||
extern u8* NWRAMMap_B[3][8];
|
||||
extern u8* NWRAMMap_C[3][8];
|
||||
|
||||
extern u32 NWRAMStart[2][3];
|
||||
extern u32 NWRAMEnd[2][3];
|
||||
extern u32 NWRAMMask[2][3];
|
||||
|
||||
bool Init();
|
||||
void DeInit();
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "DSi.h"
|
||||
#include "DSi_I2C.h"
|
||||
#include "DSi_Camera.h"
|
||||
#include "ARM.h"
|
||||
|
||||
|
||||
namespace DSi_BPTWL
|
||||
|
@ -108,7 +109,8 @@ void Write(u8 val, bool last)
|
|||
printf("BPTWL: soft-reset\n");
|
||||
val = 0; // checkme
|
||||
// TODO: soft-reset might need to be scheduled later!
|
||||
DSi::SoftReset();
|
||||
// TODO: this has been moved for the JIT to work, nothing is confirmed here
|
||||
NDS::ARM7->Halt(4);
|
||||
CurPos = -1;
|
||||
return;
|
||||
}
|
||||
|
|
41
src/NDS.cpp
41
src/NDS.cpp
|
@ -32,8 +32,11 @@
|
|||
#include "Wifi.h"
|
||||
#include "AREngine.h"
|
||||
#include "Platform.h"
|
||||
|
||||
#ifdef JIT_ENABLED
|
||||
#include "ARMJIT.h"
|
||||
#include "ARMJIT_Memory.h"
|
||||
#endif
|
||||
|
||||
#include "DSi.h"
|
||||
#include "DSi_SPI_TSC.h"
|
||||
|
@ -173,7 +176,7 @@ bool Init()
|
|||
#ifdef JIT_ENABLED
|
||||
ARMJIT::Init();
|
||||
#else
|
||||
MainRAM = new u8[MainRAMSize];
|
||||
MainRAM = new u8[0x1000000];
|
||||
ARM7WRAM = new u8[ARM7WRAMSize];
|
||||
SharedWRAM = new u8[SharedWRAMSize];
|
||||
#endif
|
||||
|
@ -1837,7 +1840,7 @@ u8 ARM9Read8(u32 addr)
|
|||
switch (addr & 0xFF000000)
|
||||
{
|
||||
case 0x02000000:
|
||||
return *(u8*)&MainRAM[addr & (MainRAMSize - 1)];
|
||||
return *(u8*)&MainRAM[addr & MainRAMMask];
|
||||
|
||||
case 0x03000000:
|
||||
if (SWRAM_ARM9.Mem)
|
||||
|
@ -1902,7 +1905,7 @@ u16 ARM9Read16(u32 addr)
|
|||
switch (addr & 0xFF000000)
|
||||
{
|
||||
case 0x02000000:
|
||||
return *(u16*)&MainRAM[addr & (MainRAMSize - 1)];
|
||||
return *(u16*)&MainRAM[addr & MainRAMMask];
|
||||
|
||||
case 0x03000000:
|
||||
if (SWRAM_ARM9.Mem)
|
||||
|
@ -2031,16 +2034,13 @@ void ARM9Write8(u32 addr, u8 val)
|
|||
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_MainRAM>(addr);
|
||||
#endif
|
||||
*(u8*)&MainRAM[addr & MainRAMMask] = val;
|
||||
#ifdef JIT_ENABLED
|
||||
ARMJIT::InvalidateMainRAMIfNecessary(addr);
|
||||
#endif
|
||||
return;
|
||||
|
||||
case 0x03000000:
|
||||
if (SWRAM_ARM9.Mem)
|
||||
{
|
||||
#ifdef JIT_ENABLED
|
||||
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_SWRAM>(addr);
|
||||
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_SharedWRAM>(addr);
|
||||
#endif
|
||||
*(u8*)&SWRAM_ARM9.Mem[addr & SWRAM_ARM9.Mask] = val;
|
||||
}
|
||||
|
@ -2090,16 +2090,13 @@ void ARM9Write16(u32 addr, u16 val)
|
|||
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_MainRAM>(addr);
|
||||
#endif
|
||||
*(u16*)&MainRAM[addr & MainRAMMask] = val;
|
||||
#ifdef JIT_ENABLED
|
||||
ARMJIT::InvalidateMainRAMIfNecessary(addr);
|
||||
#endif
|
||||
return;
|
||||
|
||||
case 0x03000000:
|
||||
if (SWRAM_ARM9.Mem)
|
||||
{
|
||||
#ifdef JIT_ENABLED
|
||||
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_SWRAM>(addr);
|
||||
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_SharedWRAM>(addr);
|
||||
#endif
|
||||
*(u16*)&SWRAM_ARM9.Mem[addr & SWRAM_ARM9.Mask] = val;
|
||||
}
|
||||
|
@ -2168,16 +2165,13 @@ void ARM9Write32(u32 addr, u32 val)
|
|||
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_MainRAM>(addr);
|
||||
#endif
|
||||
*(u32*)&MainRAM[addr & MainRAMMask] = val;
|
||||
#ifdef JIT_ENABLED
|
||||
ARMJIT::InvalidateMainRAMIfNecessary(addr);
|
||||
#endif
|
||||
return ;
|
||||
|
||||
case 0x03000000:
|
||||
if (SWRAM_ARM9.Mem)
|
||||
{
|
||||
#ifdef JIT_ENABLED
|
||||
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_SWRAM>(addr);
|
||||
ARMJIT::CheckAndInvalidate<0, ARMJIT_Memory::memregion_SharedWRAM>(addr);
|
||||
#endif
|
||||
*(u32*)&SWRAM_ARM9.Mem[addr & SWRAM_ARM9.Mask] = val;
|
||||
}
|
||||
|
@ -2235,7 +2229,7 @@ void ARM9Write32(u32 addr, u32 val)
|
|||
return;
|
||||
}
|
||||
|
||||
printf("unknown arm9 write32 %08X %08X | %08X\n", addr, val, ARM9->R[15]);
|
||||
//printf("unknown arm9 write32 %08X %08X | %08X\n", addr, val, ARM9->R[15]);
|
||||
}
|
||||
|
||||
bool ARM9GetMemRegion(u32 addr, bool write, MemRegion* region)
|
||||
|
@ -2475,16 +2469,13 @@ void ARM7Write8(u32 addr, u8 val)
|
|||
ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_MainRAM>(addr);
|
||||
#endif
|
||||
*(u8*)&MainRAM[addr & MainRAMMask] = val;
|
||||
#ifdef JIT_ENABLED
|
||||
ARMJIT::InvalidateMainRAMIfNecessary(addr);
|
||||
#endif
|
||||
return;
|
||||
|
||||
case 0x03000000:
|
||||
if (SWRAM_ARM7.Mem)
|
||||
{
|
||||
#ifdef JIT_ENABLED
|
||||
ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_SWRAM>(addr);
|
||||
ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_SharedWRAM>(addr);
|
||||
#endif
|
||||
*(u8*)&SWRAM_ARM7.Mem[addr & SWRAM_ARM7.Mask] = val;
|
||||
return;
|
||||
|
@ -2552,16 +2543,13 @@ void ARM7Write16(u32 addr, u16 val)
|
|||
ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_MainRAM>(addr);
|
||||
#endif
|
||||
*(u16*)&MainRAM[addr & MainRAMMask] = val;
|
||||
#ifdef JIT_ENABLED
|
||||
ARMJIT::InvalidateMainRAMIfNecessary(addr);
|
||||
#endif
|
||||
return;
|
||||
|
||||
case 0x03000000:
|
||||
if (SWRAM_ARM7.Mem)
|
||||
{
|
||||
#ifdef JIT_ENABLED
|
||||
ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_SWRAM>(addr);
|
||||
ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_SharedWRAM>(addr);
|
||||
#endif
|
||||
*(u16*)&SWRAM_ARM7.Mem[addr & SWRAM_ARM7.Mask] = val;
|
||||
return;
|
||||
|
@ -2639,16 +2627,13 @@ void ARM7Write32(u32 addr, u32 val)
|
|||
ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_MainRAM>(addr);
|
||||
#endif
|
||||
*(u32*)&MainRAM[addr & MainRAMMask] = val;
|
||||
#ifdef JIT_ENABLED
|
||||
ARMJIT::InvalidateMainRAMIfNecessary(addr);
|
||||
#endif
|
||||
return;
|
||||
|
||||
case 0x03000000:
|
||||
if (SWRAM_ARM7.Mem)
|
||||
{
|
||||
#ifdef JIT_ENABLED
|
||||
ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_SWRAM>(addr);
|
||||
ARMJIT::CheckAndInvalidate<1, ARMJIT_Memory::memregion_SharedWRAM>(addr);
|
||||
#endif
|
||||
*(u32*)&SWRAM_ARM7.Mem[addr & SWRAM_ARM7.Mask] = val;
|
||||
return;
|
||||
|
|
|
@ -165,6 +165,8 @@ extern u16 ARM7BIOSProt;
|
|||
extern u8* MainRAM;
|
||||
extern u32 MainRAMMask;
|
||||
|
||||
const u32 MainRAMMaxSize = 0x1000000;
|
||||
|
||||
const u32 SharedWRAMSize = 0x8000;
|
||||
extern u8* SharedWRAM;
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
EmuSettingsDialog* EmuSettingsDialog::currentDlg = nullptr;
|
||||
|
||||
extern char* EmuDirectory;
|
||||
extern bool RunningSomething;
|
||||
|
||||
|
||||
EmuSettingsDialog::EmuSettingsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::EmuSettingsDialog)
|
||||
|
@ -53,6 +54,22 @@ EmuSettingsDialog::EmuSettingsDialog(QWidget* parent) : QDialog(parent), ui(new
|
|||
ui->cbxConsoleType->setCurrentIndex(Config::ConsoleType);
|
||||
|
||||
ui->chkDirectBoot->setChecked(Config::DirectBoot != 0);
|
||||
|
||||
#ifdef JIT_ENABLED
|
||||
ui->chkEnableJIT->setChecked(Config::JIT_Enable != 0);
|
||||
ui->chkJITBranchOptimisations->setChecked(Config::JIT_BranchOptimisations != 0);
|
||||
ui->chkJITLiteralOptimisations->setChecked(Config::JIT_LiteralOptimisations != 0);
|
||||
ui->chkJITFastMemory->setChecked(Config::JIT_FastMemory != 0);
|
||||
ui->spnJITMaximumBlockSize->setValue(Config::JIT_MaxBlockSize);
|
||||
#else
|
||||
ui->chkEnableJIT->setDisabled(true);
|
||||
ui->chkJITBranchOptimisations->setDisabled(true);
|
||||
ui->chkJITLiteralOptimisations->setDisabled(true);
|
||||
ui->chkJITFastMemory->setDisabled(true);
|
||||
ui->spnJITMaximumBlockSize->setDisabled(true);
|
||||
#endif
|
||||
|
||||
on_chkEnableJIT_toggled();
|
||||
}
|
||||
|
||||
EmuSettingsDialog::~EmuSettingsDialog()
|
||||
|
@ -102,29 +119,78 @@ void EmuSettingsDialog::verifyFirmware()
|
|||
}
|
||||
}
|
||||
|
||||
void EmuSettingsDialog::on_EmuSettingsDialog_accepted()
|
||||
void EmuSettingsDialog::done(int r)
|
||||
{
|
||||
verifyFirmware();
|
||||
if (r == QDialog::Accepted)
|
||||
{
|
||||
verifyFirmware();
|
||||
|
||||
strncpy(Config::BIOS9Path, ui->txtBIOS9Path->text().toStdString().c_str(), 1023); Config::BIOS9Path[1023] = '\0';
|
||||
strncpy(Config::BIOS7Path, ui->txtBIOS7Path->text().toStdString().c_str(), 1023); Config::BIOS7Path[1023] = '\0';
|
||||
strncpy(Config::FirmwarePath, ui->txtFirmwarePath->text().toStdString().c_str(), 1023); Config::FirmwarePath[1023] = '\0';
|
||||
int consoleType = ui->cbxConsoleType->currentIndex();
|
||||
int directBoot = ui->chkDirectBoot->isChecked() ? 1:0;
|
||||
|
||||
strncpy(Config::DSiBIOS9Path, ui->txtDSiBIOS9Path->text().toStdString().c_str(), 1023); Config::DSiBIOS9Path[1023] = '\0';
|
||||
strncpy(Config::DSiBIOS7Path, ui->txtDSiBIOS7Path->text().toStdString().c_str(), 1023); Config::DSiBIOS7Path[1023] = '\0';
|
||||
strncpy(Config::DSiFirmwarePath, ui->txtDSiFirmwarePath->text().toStdString().c_str(), 1023); Config::DSiFirmwarePath[1023] = '\0';
|
||||
strncpy(Config::DSiNANDPath, ui->txtDSiNANDPath->text().toStdString().c_str(), 1023); Config::DSiNANDPath[1023] = '\0';
|
||||
int jitEnable = ui->chkEnableJIT->isChecked() ? 1:0;
|
||||
int jitMaxBlockSize = ui->spnJITMaximumBlockSize->value();
|
||||
int jitBranchOptimisations = ui->chkJITBranchOptimisations->isChecked() ? 1:0;
|
||||
int jitLiteralOptimisations = ui->chkJITLiteralOptimisations->isChecked() ? 1:0;
|
||||
int jitFastMemory = ui->chkJITFastMemory->isChecked() ? 1:0;
|
||||
|
||||
Config::ConsoleType = ui->cbxConsoleType->currentIndex();
|
||||
Config::DirectBoot = ui->chkDirectBoot->isChecked() ? 1:0;
|
||||
std::string bios9Path = ui->txtBIOS9Path->text().toStdString();
|
||||
std::string bios7Path = ui->txtBIOS7Path->text().toStdString();
|
||||
std::string firmwarePath = ui->txtFirmwarePath->text().toStdString();
|
||||
std::string dsiBios9Path = ui->txtDSiBIOS9Path->text().toStdString();
|
||||
std::string dsiBios7Path = ui->txtDSiBIOS7Path->text().toStdString();
|
||||
std::string dsiFirmwarePath = ui->txtDSiFirmwarePath->text().toStdString();
|
||||
std::string dsiNANDPath = ui->txtDSiNANDPath->text().toStdString();
|
||||
|
||||
Config::Save();
|
||||
if (consoleType != Config::ConsoleType
|
||||
|| directBoot != Config::DirectBoot
|
||||
#ifdef JIT_ENABLED
|
||||
|| jitEnable != Config::JIT_Enable
|
||||
|| jitMaxBlockSize != Config::JIT_MaxBlockSize
|
||||
|| jitBranchOptimisations != Config::JIT_BranchOptimisations
|
||||
|| jitLiteralOptimisations != Config::JIT_LiteralOptimisations
|
||||
|| jitFastMemory != Config::JIT_FastMemory
|
||||
#endif
|
||||
|| strcmp(Config::BIOS9Path, bios9Path.c_str()) != 0
|
||||
|| strcmp(Config::BIOS7Path, bios7Path.c_str()) != 0
|
||||
|| strcmp(Config::FirmwarePath, firmwarePath.c_str()) != 0
|
||||
|| strcmp(Config::DSiBIOS9Path, dsiBios9Path.c_str()) != 0
|
||||
|| strcmp(Config::DSiBIOS7Path, dsiBios7Path.c_str()) != 0
|
||||
|| strcmp(Config::DSiFirmwarePath, dsiFirmwarePath.c_str()) != 0
|
||||
|| strcmp(Config::DSiNANDPath, dsiNANDPath.c_str()) != 0)
|
||||
{
|
||||
if (RunningSomething
|
||||
&& QMessageBox::warning(this, "Reset necessary to apply changes",
|
||||
"The emulation will be reset for the changes to take place",
|
||||
QMessageBox::Yes, QMessageBox::Cancel) != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
closeDlg();
|
||||
}
|
||||
strncpy(Config::BIOS9Path, bios9Path.c_str(), 1023); Config::BIOS9Path[1023] = '\0';
|
||||
strncpy(Config::BIOS7Path, bios7Path.c_str(), 1023); Config::BIOS7Path[1023] = '\0';
|
||||
strncpy(Config::FirmwarePath, firmwarePath.c_str(), 1023); Config::FirmwarePath[1023] = '\0';
|
||||
|
||||
strncpy(Config::DSiBIOS9Path, dsiBios9Path.c_str(), 1023); Config::DSiBIOS9Path[1023] = '\0';
|
||||
strncpy(Config::DSiBIOS7Path, dsiBios7Path.c_str(), 1023); Config::DSiBIOS7Path[1023] = '\0';
|
||||
strncpy(Config::DSiFirmwarePath, dsiFirmwarePath.c_str(), 1023); Config::DSiFirmwarePath[1023] = '\0';
|
||||
strncpy(Config::DSiNANDPath, dsiNANDPath.c_str(), 1023); Config::DSiNANDPath[1023] = '\0';
|
||||
|
||||
#ifdef JIT_ENABLED
|
||||
Config::JIT_Enable = jitEnable;
|
||||
Config::JIT_MaxBlockSize = jitMaxBlockSize;
|
||||
Config::JIT_BranchOptimisations = jitBranchOptimisations;
|
||||
Config::JIT_LiteralOptimisations = jitLiteralOptimisations;
|
||||
Config::JIT_FastMemory = jitFastMemory;
|
||||
#endif
|
||||
|
||||
Config::ConsoleType = consoleType;
|
||||
Config::DirectBoot = directBoot;
|
||||
|
||||
Config::Save();
|
||||
}
|
||||
}
|
||||
|
||||
QDialog::done(r);
|
||||
|
||||
void EmuSettingsDialog::on_EmuSettingsDialog_rejected()
|
||||
{
|
||||
closeDlg();
|
||||
}
|
||||
|
||||
|
@ -211,3 +277,12 @@ void EmuSettingsDialog::on_btnDSiNANDBrowse_clicked()
|
|||
|
||||
ui->txtDSiNANDPath->setText(file);
|
||||
}
|
||||
|
||||
void EmuSettingsDialog::on_chkEnableJIT_toggled()
|
||||
{
|
||||
bool disabled = !ui->chkEnableJIT->isChecked();
|
||||
ui->chkJITBranchOptimisations->setDisabled(disabled);
|
||||
ui->chkJITLiteralOptimisations->setDisabled(disabled);
|
||||
ui->chkJITFastMemory->setDisabled(disabled);
|
||||
ui->spnJITMaximumBlockSize->setDisabled(disabled);
|
||||
}
|
|
@ -51,8 +51,7 @@ public:
|
|||
}
|
||||
|
||||
private slots:
|
||||
void on_EmuSettingsDialog_accepted();
|
||||
void on_EmuSettingsDialog_rejected();
|
||||
void done(int r);
|
||||
|
||||
void on_btnBIOS9Browse_clicked();
|
||||
void on_btnBIOS7Browse_clicked();
|
||||
|
@ -63,6 +62,8 @@ private slots:
|
|||
void on_btnDSiFirmwareBrowse_clicked();
|
||||
void on_btnDSiNANDBrowse_clicked();
|
||||
|
||||
void on_chkEnableJIT_toggled();
|
||||
|
||||
private:
|
||||
void verifyFirmware();
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>490</width>
|
||||
<height>392</height>
|
||||
<width>514</width>
|
||||
<height>359</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -24,243 +24,336 @@
|
|||
<enum>QLayout::SetFixedSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>DS mode</string>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="txtBIOS9Path">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>290</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>DS-mode ARM9 BIOS</p><p>Size should be 4 KB</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>DS firmware:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>DS ARM7 BIOS:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>DS ARM9 BIOS:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="btnBIOS9Browse">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="txtBIOS7Path">
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>DS-mode ARM7 BIOS</p><p>Size should be 16 KB</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="btnBIOS7Browse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="txtFirmwarePath">
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>DS-mode firmware</p><p><br/></p><p>Possible firmwares:</p><p>* 128 KB: DS-mode firmware from a DSi or 3DS. Not bootable.</p><p>* 256 KB: regular DS firmware.</p><p>* 512 KB: iQue DS firmware.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QPushButton" name="btnFirmwareBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>DSi mode</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="btnDSiBIOS9Browse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>DSi ARM9 BIOS:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QPushButton" name="btnDSiFirmwareBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="txtDSiBIOS7Path">
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>DSi-mode ARM7 BIOS</p><p><br/></p><p>Size should be 64 KB</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="txtDSiFirmwarePath">
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>DSi-mode firmware (used for DS-mode backwards compatibility)</p><p><br/></p><p>Size should be 128 KB</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>DSi ARM7 BIOS:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>DSi firmware:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="btnDSiBIOS7Browse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="txtDSiBIOS9Path">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>DSi-mode ARM9 BIOS</p><p><br/></p><p>Size should be 64 KB</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>DSi NAND:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="txtDSiNANDPath">
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>DSi NAND dump</p><p><br/></p><p>Should have 'nocash footer' at the end</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QPushButton" name="btnDSiNANDBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>General</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Console type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="cbxConsoleType">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>The type of console to emulate</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="chkDirectBoot">
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>When loading a ROM, completely skip the regular boot process (&quot;Nintendo DS&quot; screen) to boot the ROM directly.</p><p><br/></p><p>Note: if your firmware dump isn't bootable, the ROM will be booted directly regardless of this setting.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Boot game directly</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>General</string>
|
||||
</attribute>
|
||||
<layout class="QFormLayout" name="formLayout_4">
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="cbxConsoleType">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>The type of console to emulate</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="chkDirectBoot">
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>When loading a ROM, completely skip the regular boot process (&quot;Nintendo DS&quot; screen) to boot the ROM directly.</p><p><br/></p><p>Note: if your firmware dump isn't bootable, the ROM will be booted directly regardless of this setting.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Boot game directly</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Console type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>BIOS Files</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>DS mode</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>DS firmware:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="txtFirmwarePath">
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>DS-mode firmware</p><p><br/></p><p>Possible firmwares:</p><p>* 128 KB: DS-mode firmware from a DSi or 3DS. Not bootable.</p><p>* 256 KB: regular DS firmware.</p><p>* 512 KB: iQue DS firmware.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="txtBIOS7Path">
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>DS-mode ARM7 BIOS</p><p>Size should be 16 KB</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="btnBIOS9Browse">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QPushButton" name="btnFirmwareBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>DS ARM7 BIOS:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>DS ARM9 BIOS:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="btnBIOS7Browse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="txtBIOS9Path">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>290</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>DS-mode ARM9 BIOS</p><p>Size should be 4 KB</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>DSi mode</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="btnDSiBIOS9Browse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>DSi ARM9 BIOS:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QPushButton" name="btnDSiFirmwareBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="txtDSiBIOS7Path">
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>DSi-mode ARM7 BIOS</p><p><br/></p><p>Size should be 64 KB</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="txtDSiFirmwarePath">
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>DSi-mode firmware (used for DS-mode backwards compatibility)</p><p><br/></p><p>Size should be 128 KB</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>DSi ARM7 BIOS:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>DSi firmware:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="btnDSiBIOS7Browse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="txtDSiBIOS9Path">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>DSi-mode ARM9 BIOS</p><p><br/></p><p>Size should be 64 KB</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>DSi NAND:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="txtDSiNANDPath">
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>DSi NAND dump</p><p><br/></p><p>Should have 'nocash footer' at the end</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QPushButton" name="btnDSiNANDBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_3">
|
||||
<attribute name="title">
|
||||
<string>CPU Emulation</string>
|
||||
</attribute>
|
||||
<layout class="QFormLayout" name="formLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="chkEnableJIT">
|
||||
<property name="text">
|
||||
<string>Enable JIT recompiler</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Maximum JIT block size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="spnJITMaximumBlockSize">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>32</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="chkJITBranchOptimisations">
|
||||
<property name="text">
|
||||
<string>Branch Optimisations</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="chkJITLiteralOptimisations">
|
||||
<property name="text">
|
||||
<string>Literal Optimisations</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="chkJITFastMemory">
|
||||
<property name="text">
|
||||
<string>Fast Memory</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -275,6 +368,27 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>tabWidget</tabstop>
|
||||
<tabstop>cbxConsoleType</tabstop>
|
||||
<tabstop>chkDirectBoot</tabstop>
|
||||
<tabstop>txtBIOS9Path</tabstop>
|
||||
<tabstop>txtBIOS7Path</tabstop>
|
||||
<tabstop>txtFirmwarePath</tabstop>
|
||||
<tabstop>txtDSiBIOS9Path</tabstop>
|
||||
<tabstop>txtDSiBIOS7Path</tabstop>
|
||||
<tabstop>txtDSiFirmwarePath</tabstop>
|
||||
<tabstop>txtDSiNANDPath</tabstop>
|
||||
<tabstop>btnBIOS9Browse</tabstop>
|
||||
<tabstop>btnBIOS7Browse</tabstop>
|
||||
<tabstop>btnFirmwareBrowse</tabstop>
|
||||
<tabstop>btnDSiBIOS9Browse</tabstop>
|
||||
<tabstop>btnDSiBIOS7Browse</tabstop>
|
||||
<tabstop>btnDSiFirmwareBrowse</tabstop>
|
||||
<tabstop>btnDSiNANDBrowse</tabstop>
|
||||
<tabstop>chkEnableJIT</tabstop>
|
||||
<tabstop>spnJITMaximumBlockSize</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
|
@ -284,8 +398,8 @@
|
|||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
<x>257</x>
|
||||
<y>349</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
|
@ -300,8 +414,8 @@
|
|||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
<x>325</x>
|
||||
<y>349</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
|
|
|
@ -1641,7 +1641,14 @@ void MainWindow::onStop()
|
|||
|
||||
void MainWindow::onOpenEmuSettings()
|
||||
{
|
||||
EmuSettingsDialog::openDlg(this);
|
||||
EmuSettingsDialog* dlg = EmuSettingsDialog::openDlg(this);
|
||||
connect(dlg, &EmuSettingsDialog::finished, this, &MainWindow::onEmuSettingsDialogFinished);
|
||||
}
|
||||
|
||||
void MainWindow::onEmuSettingsDialogFinished(int res)
|
||||
{
|
||||
if (RunningSomething)
|
||||
onReset();
|
||||
}
|
||||
|
||||
void MainWindow::onOpenInputConfig()
|
||||
|
|
|
@ -199,6 +199,7 @@ private slots:
|
|||
void onStop();
|
||||
|
||||
void onOpenEmuSettings();
|
||||
void onEmuSettingsDialogFinished(int res);
|
||||
void onOpenInputConfig();
|
||||
void onInputConfigFinished(int res);
|
||||
void onOpenVideoSettings();
|
||||
|
|
|
@ -1,252 +0,0 @@
|
|||
/*
|
||||
Copyright 2016-2020 Arisotura
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS 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 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libui/ui.h"
|
||||
|
||||
#include "../types.h"
|
||||
#include "PlatformConfig.h"
|
||||
|
||||
#include "DlgEmuSettings.h"
|
||||
|
||||
|
||||
void ApplyNewSettings(int type);
|
||||
|
||||
extern bool RunningSomething;
|
||||
|
||||
namespace DlgEmuSettings
|
||||
{
|
||||
|
||||
bool opened;
|
||||
uiWindow* win;
|
||||
|
||||
uiCheckbox* cbDirectBoot;
|
||||
|
||||
#ifdef JIT_ENABLED
|
||||
uiCheckbox* cbJITEnabled;
|
||||
uiEntry* enJITMaxBlockSize;
|
||||
uiCheckbox* cbJITBranchOptimisations;
|
||||
uiCheckbox* cbJITLiteralOptimisations;
|
||||
#endif
|
||||
|
||||
int OnCloseWindow(uiWindow* window, void* blarg)
|
||||
{
|
||||
opened = false;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void OnCancel(uiButton* btn, void* blarg)
|
||||
{
|
||||
uiControlDestroy(uiControl(win));
|
||||
opened = false;
|
||||
}
|
||||
|
||||
void OnOk(uiButton* btn, void* blarg)
|
||||
{
|
||||
#ifdef JIT_ENABLED
|
||||
bool restart = false;
|
||||
|
||||
bool enableJit = uiCheckboxChecked(cbJITEnabled);
|
||||
char* maxBlockSizeStr = uiEntryText(enJITMaxBlockSize);
|
||||
long blockSize = strtol(maxBlockSizeStr, NULL, 10);
|
||||
bool branchOptimisations = uiCheckboxChecked(cbJITBranchOptimisations);
|
||||
bool literalOptimisations = uiCheckboxChecked(cbJITLiteralOptimisations);
|
||||
uiFreeText(maxBlockSizeStr);
|
||||
if (blockSize < 1)
|
||||
blockSize = 1;
|
||||
if (blockSize > 32)
|
||||
blockSize = 32;
|
||||
|
||||
if (enableJit != Config::JIT_Enable || blockSize != Config::JIT_MaxBlockSize
|
||||
|| branchOptimisations != Config::JIT_BrancheOptimisations
|
||||
|| literalOptimisations != Config::JIT_LiteralOptimisations)
|
||||
{
|
||||
if (RunningSomething &&
|
||||
!uiMsgBoxConfirm(win, "Reset emulator",
|
||||
"Changing JIT settings requires a reset.\n\nDo you want to continue?"))
|
||||
return;
|
||||
|
||||
Config::JIT_Enable = enableJit;
|
||||
Config::JIT_MaxBlockSize = blockSize;
|
||||
Config::JIT_BrancheOptimisations = branchOptimisations;
|
||||
Config::JIT_LiteralOptimisations = literalOptimisations;
|
||||
|
||||
restart = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
Config::DirectBoot = uiCheckboxChecked(cbDirectBoot);
|
||||
|
||||
Config::Save();
|
||||
|
||||
uiControlDestroy(uiControl(win));
|
||||
opened = false;
|
||||
|
||||
#ifdef JIT_ENABLED
|
||||
if (restart)
|
||||
ApplyNewSettings(4);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef JIT_ENABLED
|
||||
void OnJITStateChanged(uiCheckbox* cb, void* blarg)
|
||||
{
|
||||
if (uiCheckboxChecked(cb))
|
||||
{
|
||||
uiControlEnable(uiControl(enJITMaxBlockSize));
|
||||
uiControlEnable(uiControl(cbJITBranchOptimisations));
|
||||
uiControlEnable(uiControl(cbJITLiteralOptimisations));
|
||||
}
|
||||
else
|
||||
{
|
||||
uiControlDisable(uiControl(enJITMaxBlockSize));
|
||||
uiControlDisable(uiControl(cbJITBranchOptimisations));
|
||||
uiControlDisable(uiControl(cbJITLiteralOptimisations));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void Open()
|
||||
{
|
||||
if (opened)
|
||||
{
|
||||
uiControlSetFocus(uiControl(win));
|
||||
return;
|
||||
}
|
||||
|
||||
opened = true;
|
||||
win = uiNewWindow("Emu settings - melonDS", 300, 50, 0, 0, 0);
|
||||
uiWindowSetMargined(win, 1);
|
||||
uiWindowOnClosing(win, OnCloseWindow, NULL);
|
||||
|
||||
uiBox* top = uiNewVerticalBox();
|
||||
uiWindowSetChild(win, uiControl(top));
|
||||
|
||||
{
|
||||
uiBox* in_ctrl = uiNewVerticalBox();
|
||||
uiBoxAppend(top, uiControl(in_ctrl), 0);
|
||||
|
||||
cbDirectBoot = uiNewCheckbox("Boot game directly");
|
||||
uiBoxAppend(in_ctrl, uiControl(cbDirectBoot), 0);
|
||||
}
|
||||
|
||||
#ifdef JIT_ENABLED
|
||||
{
|
||||
uiLabel* dummy = uiNewLabel("");
|
||||
uiBoxAppend(top, uiControl(dummy), 0);
|
||||
}
|
||||
|
||||
{
|
||||
uiGroup* grp = uiNewGroup("JIT");
|
||||
uiBoxAppend(top, uiControl(grp), 1);
|
||||
|
||||
uiBox* in_ctrl = uiNewVerticalBox();
|
||||
uiGroupSetChild(grp, uiControl(in_ctrl));
|
||||
|
||||
cbJITEnabled = uiNewCheckbox("Enable JIT recompiler");
|
||||
uiBoxAppend(in_ctrl, uiControl(cbJITEnabled), 0);
|
||||
|
||||
uiCheckboxOnToggled(cbJITEnabled, OnJITStateChanged, NULL);
|
||||
|
||||
{
|
||||
uiBox* row = uiNewHorizontalBox();
|
||||
uiBoxAppend(in_ctrl, uiControl(row), 0);
|
||||
|
||||
uiLabel* lbl = uiNewLabel("Maximum block size (1-32): ");
|
||||
uiBoxAppend(row, uiControl(lbl), 0);
|
||||
|
||||
enJITMaxBlockSize = uiNewEntry();
|
||||
uiBoxAppend(row, uiControl(enJITMaxBlockSize), 0);
|
||||
}
|
||||
|
||||
{
|
||||
uiBox* row = uiNewHorizontalBox();
|
||||
uiBoxAppend(in_ctrl, uiControl(row), 0);
|
||||
|
||||
uiLabel* lbl = uiNewLabel("If you experience problems with a certain game, you can try disabling these options:");
|
||||
uiBoxAppend(row, uiControl(lbl), 0);
|
||||
}
|
||||
|
||||
{
|
||||
uiBox* row = uiNewHorizontalBox();
|
||||
uiBoxAppend(in_ctrl, uiControl(row), 0);
|
||||
|
||||
cbJITBranchOptimisations = uiNewCheckbox("Branch optimisations");
|
||||
uiBoxAppend(row, uiControl(cbJITBranchOptimisations), 0);
|
||||
}
|
||||
|
||||
{
|
||||
uiBox* row = uiNewHorizontalBox();
|
||||
uiBoxAppend(in_ctrl, uiControl(row), 0);
|
||||
|
||||
cbJITLiteralOptimisations = uiNewCheckbox("Literal optimisations");
|
||||
uiBoxAppend(row, uiControl(cbJITLiteralOptimisations), 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
uiLabel* dummy = uiNewLabel("");
|
||||
uiBoxAppend(top, uiControl(dummy), 0);
|
||||
}
|
||||
|
||||
{
|
||||
uiBox* in_ctrl = uiNewHorizontalBox();
|
||||
uiBoxSetPadded(in_ctrl, 1);
|
||||
uiBoxAppend(top, uiControl(in_ctrl), 0);
|
||||
|
||||
uiLabel* dummy = uiNewLabel("");
|
||||
uiBoxAppend(in_ctrl, uiControl(dummy), 1);
|
||||
|
||||
uiButton* btncancel = uiNewButton("Cancel");
|
||||
uiButtonOnClicked(btncancel, OnCancel, NULL);
|
||||
uiBoxAppend(in_ctrl, uiControl(btncancel), 0);
|
||||
|
||||
uiButton* btnok = uiNewButton("Ok");
|
||||
uiButtonOnClicked(btnok, OnOk, NULL);
|
||||
uiBoxAppend(in_ctrl, uiControl(btnok), 0);
|
||||
}
|
||||
|
||||
uiCheckboxSetChecked(cbDirectBoot, Config::DirectBoot);
|
||||
|
||||
#ifdef JIT_ENABLED
|
||||
uiCheckboxSetChecked(cbJITEnabled, Config::JIT_Enable);
|
||||
{
|
||||
char maxBlockSizeStr[10];
|
||||
sprintf(maxBlockSizeStr, "%d", Config::JIT_MaxBlockSize);
|
||||
uiEntrySetText(enJITMaxBlockSize, maxBlockSizeStr);
|
||||
}
|
||||
OnJITStateChanged(cbJITEnabled, NULL);
|
||||
|
||||
uiCheckboxSetChecked(cbJITBranchOptimisations, Config::JIT_BrancheOptimisations);
|
||||
uiCheckboxSetChecked(cbJITLiteralOptimisations, Config::JIT_LiteralOptimisations);
|
||||
#endif
|
||||
|
||||
uiControlShow(uiControl(win));
|
||||
}
|
||||
|
||||
void Close()
|
||||
{
|
||||
if (!opened) return;
|
||||
uiControlDestroy(uiControl(win));
|
||||
opened = false;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,764 +0,0 @@
|
|||
// 6 april 2015
|
||||
|
||||
// TODO add a uiVerifyControlType() function that can be used by control implementations to verify controls
|
||||
|
||||
#ifndef __LIBUI_UI_H__
|
||||
#define __LIBUI_UI_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// this macro is generated by cmake
|
||||
#ifdef libui_EXPORTS
|
||||
#ifdef _WIN32
|
||||
#define _UI_EXTERN __declspec(dllexport) extern
|
||||
#else
|
||||
#define _UI_EXTERN __attribute__((visibility("default"))) extern
|
||||
#endif
|
||||
#else
|
||||
// TODO add __declspec(dllimport) on windows, but only if not static
|
||||
#define _UI_EXTERN extern
|
||||
#endif
|
||||
|
||||
// C++ is really really really really really really dumb about enums, so screw that and just make them anonymous
|
||||
// This has the advantage of being ABI-able should we ever need an ABI...
|
||||
#define _UI_ENUM(s) typedef unsigned int s; enum
|
||||
|
||||
// This constant is provided because M_PI is nonstandard.
|
||||
// This comes from Go's math.Pi, which in turn comes from http://oeis.org/A000796.
|
||||
#define uiPi 3.14159265358979323846264338327950288419716939937510582097494459
|
||||
|
||||
// TODO uiBool?
|
||||
|
||||
typedef struct uiInitOptions uiInitOptions;
|
||||
|
||||
struct uiInitOptions {
|
||||
size_t Size;
|
||||
};
|
||||
|
||||
_UI_EXTERN const char *uiInit(uiInitOptions *options);
|
||||
_UI_EXTERN void uiUninit(void);
|
||||
_UI_EXTERN void uiFreeInitError(const char *err);
|
||||
|
||||
_UI_EXTERN void uiMain(void);
|
||||
_UI_EXTERN void uiMainSteps(void);
|
||||
_UI_EXTERN int uiMainStep(int wait);
|
||||
_UI_EXTERN void uiQuit(void);
|
||||
|
||||
_UI_EXTERN void uiQueueMain(void (*f)(void *data), void *data);
|
||||
|
||||
_UI_EXTERN void uiOnShouldQuit(int (*f)(void *data), void *data);
|
||||
|
||||
_UI_EXTERN void uiFreeText(char *text);
|
||||
|
||||
typedef struct uiControl uiControl;
|
||||
|
||||
struct uiControl {
|
||||
uint32_t Signature;
|
||||
uint32_t OSSignature;
|
||||
uint32_t TypeSignature;
|
||||
void (*Destroy)(uiControl *);
|
||||
uintptr_t (*Handle)(uiControl *);
|
||||
uiControl *(*Parent)(uiControl *);
|
||||
void (*SetParent)(uiControl *, uiControl *);
|
||||
int (*Toplevel)(uiControl *);
|
||||
int (*Visible)(uiControl *);
|
||||
void (*Show)(uiControl *);
|
||||
void (*Hide)(uiControl *);
|
||||
int (*Enabled)(uiControl *);
|
||||
void (*Enable)(uiControl *);
|
||||
void (*Disable)(uiControl *);
|
||||
void (*SetFocus)(uiControl *);
|
||||
void (*SetMinSize)(uiControl*, int, int);
|
||||
|
||||
int MinWidth, MinHeight;
|
||||
|
||||
void* UserData;
|
||||
};
|
||||
// TOOD add argument names to all arguments
|
||||
#define uiControl(this) ((uiControl *) (this))
|
||||
_UI_EXTERN void uiControlDestroy(uiControl *);
|
||||
_UI_EXTERN uintptr_t uiControlHandle(uiControl *);
|
||||
_UI_EXTERN uiControl *uiControlParent(uiControl *);
|
||||
_UI_EXTERN void uiControlSetParent(uiControl *, uiControl *);
|
||||
_UI_EXTERN int uiControlToplevel(uiControl *);
|
||||
_UI_EXTERN int uiControlVisible(uiControl *);
|
||||
_UI_EXTERN void uiControlShow(uiControl *);
|
||||
_UI_EXTERN void uiControlHide(uiControl *);
|
||||
_UI_EXTERN int uiControlEnabled(uiControl *);
|
||||
_UI_EXTERN void uiControlEnable(uiControl *);
|
||||
_UI_EXTERN void uiControlDisable(uiControl *);
|
||||
_UI_EXTERN void uiControlSetFocus(uiControl *);
|
||||
_UI_EXTERN void uiControlSetMinSize(uiControl *, int w, int h); // -1 = no minimum
|
||||
|
||||
_UI_EXTERN uiControl *uiAllocControl(size_t n, uint32_t OSsig, uint32_t typesig, const char *typenamestr);
|
||||
_UI_EXTERN void uiFreeControl(uiControl *);
|
||||
|
||||
// TODO make sure all controls have these
|
||||
_UI_EXTERN void uiControlVerifySetParent(uiControl *, uiControl *);
|
||||
_UI_EXTERN int uiControlEnabledToUser(uiControl *);
|
||||
|
||||
_UI_EXTERN void uiUserBugCannotSetParentOnToplevel(const char *type);
|
||||
|
||||
typedef struct uiWindow uiWindow;
|
||||
#define uiWindow(this) ((uiWindow *) (this))
|
||||
_UI_EXTERN char *uiWindowTitle(uiWindow *w);
|
||||
_UI_EXTERN void uiWindowSetTitle(uiWindow *w, const char *title);
|
||||
_UI_EXTERN void uiWindowPosition(uiWindow *w, int *x, int *y);
|
||||
_UI_EXTERN void uiWindowSetPosition(uiWindow *w, int x, int y);
|
||||
_UI_EXTERN void uiWindowContentSize(uiWindow *w, int *width, int *height);
|
||||
_UI_EXTERN void uiWindowSetContentSize(uiWindow *w, int width, int height);
|
||||
_UI_EXTERN int uiWindowMinimized(uiWindow *w);
|
||||
_UI_EXTERN void uiWindowSetMinimized(uiWindow *w, int minimized);
|
||||
_UI_EXTERN int uiWindowMaximized(uiWindow *w);
|
||||
_UI_EXTERN void uiWindowSetMaximized(uiWindow *w, int maximized);
|
||||
_UI_EXTERN int uiWindowFullscreen(uiWindow *w);
|
||||
_UI_EXTERN void uiWindowSetFullscreen(uiWindow *w, int fullscreen);
|
||||
_UI_EXTERN int uiWindowBorderless(uiWindow *w);
|
||||
_UI_EXTERN void uiWindowSetBorderless(uiWindow *w, int borderless);
|
||||
_UI_EXTERN void uiWindowSetChild(uiWindow *w, uiControl *child);
|
||||
_UI_EXTERN int uiWindowMargined(uiWindow *w);
|
||||
_UI_EXTERN void uiWindowSetMargined(uiWindow *w, int margined);
|
||||
_UI_EXTERN void uiWindowSetDropTarget(uiWindow* w, int drop);
|
||||
_UI_EXTERN uiWindow *uiNewWindow(const char *title, int width, int height, int maximized, int hasMenubar, int resizable);
|
||||
|
||||
_UI_EXTERN void uiWindowOnContentSizeChanged(uiWindow *w, void (*f)(uiWindow *, void *), void *data);
|
||||
_UI_EXTERN void uiWindowOnClosing(uiWindow *w, int (*f)(uiWindow *w, void *data), void *data);
|
||||
_UI_EXTERN void uiWindowOnDropFile(uiWindow *w, void (*f)(uiWindow *w, char *file, void *data), void *data);
|
||||
_UI_EXTERN void uiWindowOnGetFocus(uiWindow *w, void (*f)(uiWindow *w, void *data), void *data);
|
||||
_UI_EXTERN void uiWindowOnLoseFocus(uiWindow *w, void (*f)(uiWindow *w, void *data), void *data);
|
||||
|
||||
typedef struct uiButton uiButton;
|
||||
#define uiButton(this) ((uiButton *) (this))
|
||||
_UI_EXTERN char *uiButtonText(uiButton *b);
|
||||
_UI_EXTERN void uiButtonSetText(uiButton *b, const char *text);
|
||||
_UI_EXTERN void uiButtonOnClicked(uiButton *b, void (*f)(uiButton *b, void *data), void *data);
|
||||
_UI_EXTERN uiButton *uiNewButton(const char *text);
|
||||
|
||||
typedef struct uiBox uiBox;
|
||||
#define uiBox(this) ((uiBox *) (this))
|
||||
_UI_EXTERN void uiBoxAppend(uiBox *b, uiControl *child, int stretchy);
|
||||
_UI_EXTERN void uiBoxDelete(uiBox *b, int index);
|
||||
_UI_EXTERN int uiBoxPadded(uiBox *b);
|
||||
_UI_EXTERN void uiBoxSetPadded(uiBox *b, int padded);
|
||||
_UI_EXTERN uiBox *uiNewHorizontalBox(void);
|
||||
_UI_EXTERN uiBox *uiNewVerticalBox(void);
|
||||
|
||||
typedef struct uiCheckbox uiCheckbox;
|
||||
#define uiCheckbox(this) ((uiCheckbox *) (this))
|
||||
_UI_EXTERN char *uiCheckboxText(uiCheckbox *c);
|
||||
_UI_EXTERN void uiCheckboxSetText(uiCheckbox *c, const char *text);
|
||||
_UI_EXTERN void uiCheckboxOnToggled(uiCheckbox *c, void (*f)(uiCheckbox *c, void *data), void *data);
|
||||
_UI_EXTERN int uiCheckboxChecked(uiCheckbox *c);
|
||||
_UI_EXTERN void uiCheckboxSetChecked(uiCheckbox *c, int checked);
|
||||
_UI_EXTERN uiCheckbox *uiNewCheckbox(const char *text);
|
||||
|
||||
typedef struct uiEntry uiEntry;
|
||||
#define uiEntry(this) ((uiEntry *) (this))
|
||||
_UI_EXTERN char *uiEntryText(uiEntry *e);
|
||||
_UI_EXTERN void uiEntrySetText(uiEntry *e, const char *text);
|
||||
_UI_EXTERN void uiEntryOnChanged(uiEntry *e, void (*f)(uiEntry *e, void *data), void *data);
|
||||
_UI_EXTERN int uiEntryReadOnly(uiEntry *e);
|
||||
_UI_EXTERN void uiEntrySetReadOnly(uiEntry *e, int readonly);
|
||||
_UI_EXTERN uiEntry *uiNewEntry(void);
|
||||
_UI_EXTERN uiEntry *uiNewPasswordEntry(void);
|
||||
_UI_EXTERN uiEntry *uiNewSearchEntry(void);
|
||||
|
||||
typedef struct uiLabel uiLabel;
|
||||
#define uiLabel(this) ((uiLabel *) (this))
|
||||
_UI_EXTERN char *uiLabelText(uiLabel *l);
|
||||
_UI_EXTERN void uiLabelSetText(uiLabel *l, const char *text);
|
||||
_UI_EXTERN uiLabel *uiNewLabel(const char *text);
|
||||
|
||||
typedef struct uiTab uiTab;
|
||||
#define uiTab(this) ((uiTab *) (this))
|
||||
_UI_EXTERN void uiTabAppend(uiTab *t, const char *name, uiControl *c);
|
||||
_UI_EXTERN void uiTabInsertAt(uiTab *t, const char *name, int before, uiControl *c);
|
||||
_UI_EXTERN void uiTabDelete(uiTab *t, int index);
|
||||
_UI_EXTERN int uiTabNumPages(uiTab *t);
|
||||
_UI_EXTERN int uiTabMargined(uiTab *t, int page);
|
||||
_UI_EXTERN void uiTabSetMargined(uiTab *t, int page, int margined);
|
||||
_UI_EXTERN uiTab *uiNewTab(void);
|
||||
|
||||
typedef struct uiGroup uiGroup;
|
||||
#define uiGroup(this) ((uiGroup *) (this))
|
||||
_UI_EXTERN char *uiGroupTitle(uiGroup *g);
|
||||
_UI_EXTERN void uiGroupSetTitle(uiGroup *g, const char *title);
|
||||
_UI_EXTERN void uiGroupSetChild(uiGroup *g, uiControl *c);
|
||||
_UI_EXTERN int uiGroupMargined(uiGroup *g);
|
||||
_UI_EXTERN void uiGroupSetMargined(uiGroup *g, int margined);
|
||||
_UI_EXTERN uiGroup *uiNewGroup(const char *title);
|
||||
|
||||
// spinbox/slider rules:
|
||||
// setting value outside of range will automatically clamp
|
||||
// initial value is minimum
|
||||
// complaint if min >= max?
|
||||
|
||||
typedef struct uiSpinbox uiSpinbox;
|
||||
#define uiSpinbox(this) ((uiSpinbox *) (this))
|
||||
_UI_EXTERN int uiSpinboxValue(uiSpinbox *s);
|
||||
_UI_EXTERN void uiSpinboxSetValue(uiSpinbox *s, int value);
|
||||
_UI_EXTERN void uiSpinboxOnChanged(uiSpinbox *s, void (*f)(uiSpinbox *s, void *data), void *data);
|
||||
_UI_EXTERN uiSpinbox *uiNewSpinbox(int min, int max);
|
||||
|
||||
typedef struct uiSlider uiSlider;
|
||||
#define uiSlider(this) ((uiSlider *) (this))
|
||||
_UI_EXTERN int uiSliderValue(uiSlider *s);
|
||||
_UI_EXTERN void uiSliderSetValue(uiSlider *s, int value);
|
||||
_UI_EXTERN void uiSliderOnChanged(uiSlider *s, void (*f)(uiSlider *s, void *data), void *data);
|
||||
_UI_EXTERN uiSlider *uiNewSlider(int min, int max);
|
||||
|
||||
typedef struct uiProgressBar uiProgressBar;
|
||||
#define uiProgressBar(this) ((uiProgressBar *) (this))
|
||||
_UI_EXTERN int uiProgressBarValue(uiProgressBar *p);
|
||||
_UI_EXTERN void uiProgressBarSetValue(uiProgressBar *p, int n);
|
||||
_UI_EXTERN uiProgressBar *uiNewProgressBar(void);
|
||||
|
||||
typedef struct uiSeparator uiSeparator;
|
||||
#define uiSeparator(this) ((uiSeparator *) (this))
|
||||
_UI_EXTERN uiSeparator *uiNewHorizontalSeparator(void);
|
||||
_UI_EXTERN uiSeparator *uiNewVerticalSeparator(void);
|
||||
|
||||
typedef struct uiCombobox uiCombobox;
|
||||
#define uiCombobox(this) ((uiCombobox *) (this))
|
||||
_UI_EXTERN void uiComboboxAppend(uiCombobox *c, const char *text);
|
||||
_UI_EXTERN int uiComboboxSelected(uiCombobox *c);
|
||||
_UI_EXTERN void uiComboboxSetSelected(uiCombobox *c, int n);
|
||||
_UI_EXTERN void uiComboboxOnSelected(uiCombobox *c, void (*f)(uiCombobox *c, void *data), void *data);
|
||||
_UI_EXTERN uiCombobox *uiNewCombobox(void);
|
||||
|
||||
typedef struct uiEditableCombobox uiEditableCombobox;
|
||||
#define uiEditableCombobox(this) ((uiEditableCombobox *) (this))
|
||||
_UI_EXTERN void uiEditableComboboxAppend(uiEditableCombobox *c, const char *text);
|
||||
_UI_EXTERN char *uiEditableComboboxText(uiEditableCombobox *c);
|
||||
_UI_EXTERN void uiEditableComboboxSetText(uiEditableCombobox *c, const char *text);
|
||||
// TODO what do we call a function that sets the currently selected item and fills the text field with it? editable comboboxes have no consistent concept of selected item
|
||||
_UI_EXTERN void uiEditableComboboxOnChanged(uiEditableCombobox *c, void (*f)(uiEditableCombobox *c, void *data), void *data);
|
||||
_UI_EXTERN uiEditableCombobox *uiNewEditableCombobox(void);
|
||||
|
||||
typedef struct uiRadioButtons uiRadioButtons;
|
||||
#define uiRadioButtons(this) ((uiRadioButtons *) (this))
|
||||
_UI_EXTERN void uiRadioButtonsAppend(uiRadioButtons *r, const char *text);
|
||||
_UI_EXTERN int uiRadioButtonsSelected(uiRadioButtons *r);
|
||||
_UI_EXTERN void uiRadioButtonsSetSelected(uiRadioButtons *r, int n);
|
||||
_UI_EXTERN void uiRadioButtonsOnSelected(uiRadioButtons *r, void (*f)(uiRadioButtons *, void *), void *data);
|
||||
_UI_EXTERN uiRadioButtons *uiNewRadioButtons(void);
|
||||
|
||||
typedef struct uiDateTimePicker uiDateTimePicker;
|
||||
#define uiDateTimePicker(this) ((uiDateTimePicker *) (this))
|
||||
_UI_EXTERN uiDateTimePicker *uiNewDateTimePicker(void);
|
||||
_UI_EXTERN uiDateTimePicker *uiNewDatePicker(void);
|
||||
_UI_EXTERN uiDateTimePicker *uiNewTimePicker(void);
|
||||
|
||||
// TODO provide a facility for entering tab stops?
|
||||
typedef struct uiMultilineEntry uiMultilineEntry;
|
||||
#define uiMultilineEntry(this) ((uiMultilineEntry *) (this))
|
||||
_UI_EXTERN char *uiMultilineEntryText(uiMultilineEntry *e);
|
||||
_UI_EXTERN void uiMultilineEntrySetText(uiMultilineEntry *e, const char *text);
|
||||
_UI_EXTERN void uiMultilineEntryAppend(uiMultilineEntry *e, const char *text);
|
||||
_UI_EXTERN void uiMultilineEntryOnChanged(uiMultilineEntry *e, void (*f)(uiMultilineEntry *e, void *data), void *data);
|
||||
_UI_EXTERN int uiMultilineEntryReadOnly(uiMultilineEntry *e);
|
||||
_UI_EXTERN void uiMultilineEntrySetReadOnly(uiMultilineEntry *e, int readonly);
|
||||
_UI_EXTERN uiMultilineEntry *uiNewMultilineEntry(void);
|
||||
_UI_EXTERN uiMultilineEntry *uiNewNonWrappingMultilineEntry(void);
|
||||
|
||||
typedef struct uiMenuItem uiMenuItem;
|
||||
#define uiMenuItem(this) ((uiMenuItem *) (this))
|
||||
_UI_EXTERN void uiMenuItemEnable(uiMenuItem *m);
|
||||
_UI_EXTERN void uiMenuItemDisable(uiMenuItem *m);
|
||||
_UI_EXTERN void uiMenuItemOnClicked(uiMenuItem *m, void (*f)(uiMenuItem *sender, uiWindow *window, void *data), void *data);
|
||||
_UI_EXTERN int uiMenuItemChecked(uiMenuItem *m);
|
||||
_UI_EXTERN void uiMenuItemSetChecked(uiMenuItem *m, int checked);
|
||||
|
||||
typedef struct uiMenu uiMenu;
|
||||
#define uiMenu(this) ((uiMenu *) (this))
|
||||
_UI_EXTERN uiMenuItem *uiMenuAppendItem(uiMenu *m, const char *name);
|
||||
_UI_EXTERN uiMenuItem *uiMenuAppendCheckItem(uiMenu *m, const char *name);
|
||||
_UI_EXTERN uiMenuItem *uiMenuAppendQuitItem(uiMenu *m);
|
||||
_UI_EXTERN uiMenuItem *uiMenuAppendPreferencesItem(uiMenu *m);
|
||||
_UI_EXTERN uiMenuItem *uiMenuAppendAboutItem(uiMenu *m);
|
||||
_UI_EXTERN uiMenuItem *uiMenuAppendSubmenu(uiMenu *m, uiMenu* child);
|
||||
_UI_EXTERN void uiMenuAppendSeparator(uiMenu *m);
|
||||
_UI_EXTERN uiMenu *uiNewMenu(const char *name);
|
||||
|
||||
_UI_EXTERN char *uiOpenFile(uiWindow *parent, const char* filter, const char* initpath);
|
||||
_UI_EXTERN char *uiSaveFile(uiWindow *parent, const char* filter, const char* initpath);
|
||||
_UI_EXTERN void uiMsgBox(uiWindow *parent, const char *title, const char *description);
|
||||
_UI_EXTERN void uiMsgBoxError(uiWindow *parent, const char *title, const char *description);
|
||||
_UI_EXTERN int uiMsgBoxConfirm(uiWindow * parent, const char *title, const char *description);
|
||||
|
||||
typedef struct uiArea uiArea;
|
||||
typedef struct uiAreaHandler uiAreaHandler;
|
||||
typedef struct uiAreaDrawParams uiAreaDrawParams;
|
||||
typedef struct uiAreaMouseEvent uiAreaMouseEvent;
|
||||
typedef struct uiAreaKeyEvent uiAreaKeyEvent;
|
||||
|
||||
typedef struct uiDrawContext uiDrawContext;
|
||||
|
||||
// TO CONSIDER: the uiAreaHandler param there seems useless
|
||||
// (might use individual callbacks instead of handler struct?)
|
||||
struct uiAreaHandler {
|
||||
void (*Draw)(uiAreaHandler *, uiArea *, uiAreaDrawParams *);
|
||||
// TODO document that resizes cause a full redraw for non-scrolling areas; implementation-defined for scrolling areas
|
||||
void (*MouseEvent)(uiAreaHandler *, uiArea *, uiAreaMouseEvent *);
|
||||
// TODO document that on first show if the mouse is already in the uiArea then one gets sent with left=0
|
||||
// TODO what about when the area is hidden and then shown again?
|
||||
void (*MouseCrossed)(uiAreaHandler *, uiArea *, int left);
|
||||
void (*DragBroken)(uiAreaHandler *, uiArea *);
|
||||
int (*KeyEvent)(uiAreaHandler *, uiArea *, uiAreaKeyEvent *);
|
||||
void (*Resize)(uiAreaHandler *, uiArea *, int, int);
|
||||
};
|
||||
|
||||
// TODO RTL layouts?
|
||||
// TODO reconcile edge and corner naming
|
||||
_UI_ENUM(uiWindowResizeEdge) {
|
||||
uiWindowResizeEdgeLeft,
|
||||
uiWindowResizeEdgeTop,
|
||||
uiWindowResizeEdgeRight,
|
||||
uiWindowResizeEdgeBottom,
|
||||
uiWindowResizeEdgeTopLeft,
|
||||
uiWindowResizeEdgeTopRight,
|
||||
uiWindowResizeEdgeBottomLeft,
|
||||
uiWindowResizeEdgeBottomRight,
|
||||
// TODO have one for keyboard resizes?
|
||||
// TODO GDK doesn't seem to have any others, including for keyboards...
|
||||
// TODO way to bring up the system menu instead?
|
||||
};
|
||||
|
||||
#define uiGLVersion(major, minor) ((major) | ((minor)<<16))
|
||||
#define uiGLVerMajor(ver) ((ver) & 0xFFFF)
|
||||
#define uiGLVerMinor(ver) ((ver) >> 16)
|
||||
|
||||
#define uiArea(this) ((uiArea *) (this))
|
||||
// TODO give a better name
|
||||
// TODO document the types of width and height
|
||||
_UI_EXTERN void uiAreaSetSize(uiArea *a, int width, int height);
|
||||
// TODO uiAreaQueueRedraw()
|
||||
_UI_EXTERN void uiAreaQueueRedrawAll(uiArea *a);
|
||||
_UI_EXTERN void uiAreaScrollTo(uiArea *a, double x, double y, double width, double height);
|
||||
// TODO document these can only be called within Mouse() handlers
|
||||
// TODO should these be allowed on scrolling areas?
|
||||
// TODO decide which mouse events should be accepted; Down is the only one guaranteed to work right now
|
||||
// TODO what happens to events after calling this up to and including the next mouse up?
|
||||
// TODO release capture?
|
||||
_UI_EXTERN void uiAreaBeginUserWindowMove(uiArea *a);
|
||||
_UI_EXTERN void uiAreaBeginUserWindowResize(uiArea *a, uiWindowResizeEdge edge);
|
||||
_UI_EXTERN void uiAreaSetBackgroundColor(uiArea *a, int r, int g, int b);
|
||||
_UI_EXTERN uiArea *uiNewArea(uiAreaHandler *ah);
|
||||
_UI_EXTERN uiArea *uiNewGLArea(uiAreaHandler *ah, const unsigned int* req_versions);
|
||||
_UI_EXTERN uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height);
|
||||
|
||||
struct uiAreaDrawParams {
|
||||
uiDrawContext *Context;
|
||||
|
||||
// TODO document that this is only defined for nonscrolling areas
|
||||
double AreaWidth;
|
||||
double AreaHeight;
|
||||
|
||||
double ClipX;
|
||||
double ClipY;
|
||||
double ClipWidth;
|
||||
double ClipHeight;
|
||||
};
|
||||
|
||||
typedef struct uiDrawPath uiDrawPath;
|
||||
typedef struct uiDrawBrush uiDrawBrush;
|
||||
typedef struct uiDrawStrokeParams uiDrawStrokeParams;
|
||||
typedef struct uiDrawMatrix uiDrawMatrix;
|
||||
|
||||
typedef struct uiDrawBrushGradientStop uiDrawBrushGradientStop;
|
||||
|
||||
typedef struct uiDrawBitmap uiDrawBitmap;
|
||||
|
||||
_UI_ENUM(uiDrawBrushType) {
|
||||
uiDrawBrushTypeSolid,
|
||||
uiDrawBrushTypeLinearGradient,
|
||||
uiDrawBrushTypeRadialGradient,
|
||||
uiDrawBrushTypeImage,
|
||||
};
|
||||
|
||||
_UI_ENUM(uiDrawLineCap) {
|
||||
uiDrawLineCapFlat,
|
||||
uiDrawLineCapRound,
|
||||
uiDrawLineCapSquare,
|
||||
};
|
||||
|
||||
_UI_ENUM(uiDrawLineJoin) {
|
||||
uiDrawLineJoinMiter,
|
||||
uiDrawLineJoinRound,
|
||||
uiDrawLineJoinBevel,
|
||||
};
|
||||
|
||||
// this is the default for botoh cairo and Direct2D (in the latter case, from the C++ helper functions)
|
||||
// Core Graphics doesn't explicitly specify a default, but NSBezierPath allows you to choose one, and this is the initial value
|
||||
// so we're good to use it too!
|
||||
#define uiDrawDefaultMiterLimit 10.0
|
||||
|
||||
_UI_ENUM(uiDrawFillMode) {
|
||||
uiDrawFillModeWinding,
|
||||
uiDrawFillModeAlternate,
|
||||
};
|
||||
|
||||
struct uiDrawMatrix {
|
||||
double M11;
|
||||
double M12;
|
||||
double M21;
|
||||
double M22;
|
||||
double M31;
|
||||
double M32;
|
||||
};
|
||||
|
||||
struct uiDrawBrush {
|
||||
uiDrawBrushType Type;
|
||||
|
||||
// solid brushes
|
||||
double R;
|
||||
double G;
|
||||
double B;
|
||||
double A;
|
||||
|
||||
// gradient brushes
|
||||
double X0; // linear: start X, radial: start X
|
||||
double Y0; // linear: start Y, radial: start Y
|
||||
double X1; // linear: end X, radial: outer circle center X
|
||||
double Y1; // linear: end Y, radial: outer circle center Y
|
||||
double OuterRadius; // radial gradients only
|
||||
uiDrawBrushGradientStop *Stops;
|
||||
size_t NumStops;
|
||||
// TODO extend mode
|
||||
// cairo: none, repeat, reflect, pad; no individual control
|
||||
// Direct2D: repeat, reflect, pad; no individual control
|
||||
// Core Graphics: none, pad; before and after individually
|
||||
// TODO cairo documentation is inconsistent about pad
|
||||
|
||||
// TODO images
|
||||
|
||||
// TODO transforms
|
||||
};
|
||||
|
||||
struct uiDrawBrushGradientStop {
|
||||
double Pos;
|
||||
double R;
|
||||
double G;
|
||||
double B;
|
||||
double A;
|
||||
};
|
||||
|
||||
struct uiDrawStrokeParams {
|
||||
uiDrawLineCap Cap;
|
||||
uiDrawLineJoin Join;
|
||||
// TODO what if this is 0? on windows there will be a crash with dashing
|
||||
double Thickness;
|
||||
double MiterLimit;
|
||||
double *Dashes;
|
||||
// TOOD what if this is 1 on Direct2D?
|
||||
// TODO what if a dash is 0 on Cairo or Quartz?
|
||||
size_t NumDashes;
|
||||
double DashPhase;
|
||||
};
|
||||
|
||||
struct uiRect {
|
||||
int X;
|
||||
int Y;
|
||||
int Width;
|
||||
int Height;
|
||||
};
|
||||
|
||||
typedef struct uiRect uiRect;
|
||||
|
||||
_UI_EXTERN uiDrawPath *uiDrawNewPath(uiDrawFillMode fillMode);
|
||||
_UI_EXTERN void uiDrawFreePath(uiDrawPath *p);
|
||||
|
||||
_UI_EXTERN void uiDrawPathNewFigure(uiDrawPath *p, double x, double y);
|
||||
_UI_EXTERN void uiDrawPathNewFigureWithArc(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative);
|
||||
_UI_EXTERN void uiDrawPathLineTo(uiDrawPath *p, double x, double y);
|
||||
// notes: angles are both relative to 0 and go counterclockwise
|
||||
// TODO is the initial line segment on cairo and OS X a proper join?
|
||||
// TODO what if sweep < 0?
|
||||
_UI_EXTERN void uiDrawPathArcTo(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative);
|
||||
_UI_EXTERN void uiDrawPathBezierTo(uiDrawPath *p, double c1x, double c1y, double c2x, double c2y, double endX, double endY);
|
||||
// TODO quadratic bezier
|
||||
_UI_EXTERN void uiDrawPathCloseFigure(uiDrawPath *p);
|
||||
|
||||
// TODO effect of these when a figure is already started
|
||||
_UI_EXTERN void uiDrawPathAddRectangle(uiDrawPath *p, double x, double y, double width, double height);
|
||||
|
||||
_UI_EXTERN void uiDrawPathEnd(uiDrawPath *p);
|
||||
|
||||
_UI_EXTERN void uiDrawStroke(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b, uiDrawStrokeParams *p);
|
||||
_UI_EXTERN void uiDrawFill(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b);
|
||||
|
||||
// TODO primitives:
|
||||
// - rounded rectangles
|
||||
// - elliptical arcs
|
||||
// - quadratic bezier curves
|
||||
|
||||
_UI_EXTERN void uiDrawMatrixSetIdentity(uiDrawMatrix *m);
|
||||
_UI_EXTERN void uiDrawMatrixTranslate(uiDrawMatrix *m, double x, double y);
|
||||
_UI_EXTERN void uiDrawMatrixScale(uiDrawMatrix *m, double xCenter, double yCenter, double x, double y);
|
||||
_UI_EXTERN void uiDrawMatrixRotate(uiDrawMatrix *m, double x, double y, double amount);
|
||||
_UI_EXTERN void uiDrawMatrixSkew(uiDrawMatrix *m, double x, double y, double xamount, double yamount);
|
||||
_UI_EXTERN void uiDrawMatrixMultiply(uiDrawMatrix *dest, uiDrawMatrix *src);
|
||||
_UI_EXTERN int uiDrawMatrixInvertible(uiDrawMatrix *m);
|
||||
_UI_EXTERN int uiDrawMatrixInvert(uiDrawMatrix *m);
|
||||
_UI_EXTERN void uiDrawMatrixTransformPoint(uiDrawMatrix *m, double *x, double *y);
|
||||
_UI_EXTERN void uiDrawMatrixTransformSize(uiDrawMatrix *m, double *x, double *y);
|
||||
|
||||
_UI_EXTERN void uiDrawTransform(uiDrawContext *c, uiDrawMatrix *m);
|
||||
|
||||
// TODO add a uiDrawPathStrokeToFill() or something like that
|
||||
_UI_EXTERN void uiDrawClip(uiDrawContext *c, uiDrawPath *path);
|
||||
|
||||
_UI_EXTERN void uiDrawSave(uiDrawContext *c);
|
||||
_UI_EXTERN void uiDrawRestore(uiDrawContext *c);
|
||||
|
||||
// bitmap API
|
||||
_UI_EXTERN uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height, int alpha);
|
||||
_UI_EXTERN void uiDrawBitmapUpdate(uiDrawBitmap* bmp, const void* data);
|
||||
_UI_EXTERN void uiDrawBitmapDraw(uiDrawContext* c, uiDrawBitmap* bmp, uiRect* srcrect, uiRect* dstrect, int filter);
|
||||
_UI_EXTERN void uiDrawFreeBitmap(uiDrawBitmap* bmp);
|
||||
|
||||
// TODO manage the use of Text, Font, and TextFont, and of the uiDrawText prefix in general
|
||||
|
||||
///// TODO reconsider this
|
||||
typedef struct uiDrawFontFamilies uiDrawFontFamilies;
|
||||
|
||||
_UI_EXTERN uiDrawFontFamilies *uiDrawListFontFamilies(void);
|
||||
_UI_EXTERN int uiDrawFontFamiliesNumFamilies(uiDrawFontFamilies *ff);
|
||||
_UI_EXTERN char *uiDrawFontFamiliesFamily(uiDrawFontFamilies *ff, int n);
|
||||
_UI_EXTERN void uiDrawFreeFontFamilies(uiDrawFontFamilies *ff);
|
||||
///// END TODO
|
||||
|
||||
typedef struct uiDrawTextLayout uiDrawTextLayout;
|
||||
typedef struct uiDrawTextFont uiDrawTextFont;
|
||||
typedef struct uiDrawTextFontDescriptor uiDrawTextFontDescriptor;
|
||||
typedef struct uiDrawTextFontMetrics uiDrawTextFontMetrics;
|
||||
|
||||
_UI_ENUM(uiDrawTextWeight) {
|
||||
uiDrawTextWeightThin,
|
||||
uiDrawTextWeightUltraLight,
|
||||
uiDrawTextWeightLight,
|
||||
uiDrawTextWeightBook,
|
||||
uiDrawTextWeightNormal,
|
||||
uiDrawTextWeightMedium,
|
||||
uiDrawTextWeightSemiBold,
|
||||
uiDrawTextWeightBold,
|
||||
uiDrawTextWeightUltraBold,
|
||||
uiDrawTextWeightHeavy,
|
||||
uiDrawTextWeightUltraHeavy,
|
||||
};
|
||||
|
||||
_UI_ENUM(uiDrawTextItalic) {
|
||||
uiDrawTextItalicNormal,
|
||||
uiDrawTextItalicOblique,
|
||||
uiDrawTextItalicItalic,
|
||||
};
|
||||
|
||||
_UI_ENUM(uiDrawTextStretch) {
|
||||
uiDrawTextStretchUltraCondensed,
|
||||
uiDrawTextStretchExtraCondensed,
|
||||
uiDrawTextStretchCondensed,
|
||||
uiDrawTextStretchSemiCondensed,
|
||||
uiDrawTextStretchNormal,
|
||||
uiDrawTextStretchSemiExpanded,
|
||||
uiDrawTextStretchExpanded,
|
||||
uiDrawTextStretchExtraExpanded,
|
||||
uiDrawTextStretchUltraExpanded,
|
||||
};
|
||||
|
||||
struct uiDrawTextFontDescriptor {
|
||||
const char *Family;
|
||||
double Size;
|
||||
uiDrawTextWeight Weight;
|
||||
uiDrawTextItalic Italic;
|
||||
uiDrawTextStretch Stretch;
|
||||
};
|
||||
|
||||
struct uiDrawTextFontMetrics {
|
||||
double Ascent;
|
||||
double Descent;
|
||||
double Leading;
|
||||
// TODO do these two mean the same across all platforms?
|
||||
double UnderlinePos;
|
||||
double UnderlineThickness;
|
||||
};
|
||||
|
||||
_UI_EXTERN uiDrawTextFont *uiDrawLoadClosestFont(const uiDrawTextFontDescriptor *desc);
|
||||
_UI_EXTERN void uiDrawFreeTextFont(uiDrawTextFont *font);
|
||||
_UI_EXTERN uintptr_t uiDrawTextFontHandle(uiDrawTextFont *font);
|
||||
_UI_EXTERN void uiDrawTextFontDescribe(uiDrawTextFont *font, uiDrawTextFontDescriptor *desc);
|
||||
// TODO make copy with given attributes methods?
|
||||
// TODO yuck this name
|
||||
_UI_EXTERN void uiDrawTextFontGetMetrics(uiDrawTextFont *font, uiDrawTextFontMetrics *metrics);
|
||||
|
||||
// TODO initial line spacing? and what about leading?
|
||||
_UI_EXTERN uiDrawTextLayout *uiDrawNewTextLayout(const char *text, uiDrawTextFont *defaultFont, double width);
|
||||
_UI_EXTERN void uiDrawFreeTextLayout(uiDrawTextLayout *layout);
|
||||
// TODO get width
|
||||
_UI_EXTERN void uiDrawTextLayoutSetWidth(uiDrawTextLayout *layout, double width);
|
||||
_UI_EXTERN void uiDrawTextLayoutExtents(uiDrawTextLayout *layout, double *width, double *height);
|
||||
|
||||
// and the attributes that you can set on a text layout
|
||||
_UI_EXTERN void uiDrawTextLayoutSetColor(uiDrawTextLayout *layout, int startChar, int endChar, double r, double g, double b, double a);
|
||||
|
||||
_UI_EXTERN void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout);
|
||||
|
||||
|
||||
// OpenGL support
|
||||
|
||||
typedef struct uiGLContext uiGLContext;
|
||||
|
||||
_UI_EXTERN uiGLContext *uiAreaGetGLContext(uiArea* a);
|
||||
_UI_EXTERN void uiGLMakeContextCurrent(uiGLContext* ctx);
|
||||
_UI_EXTERN void uiGLBegin(uiGLContext* ctx);
|
||||
_UI_EXTERN void uiGLEnd(uiGLContext* ctx);
|
||||
_UI_EXTERN unsigned int uiGLGetVersion(uiGLContext* ctx);
|
||||
_UI_EXTERN void *uiGLGetProcAddress(const char* proc);
|
||||
_UI_EXTERN int uiGLGetFramebuffer(uiGLContext* ctx);
|
||||
_UI_EXTERN float uiGLGetFramebufferScale(uiGLContext* ctx);
|
||||
_UI_EXTERN void uiGLSwapBuffers(uiGLContext* ctx);
|
||||
_UI_EXTERN void uiGLSetVSync(int sync);
|
||||
|
||||
|
||||
_UI_ENUM(uiModifiers) {
|
||||
uiModifierCtrl = 1 << 0,
|
||||
uiModifierAlt = 1 << 1,
|
||||
uiModifierShift = 1 << 2,
|
||||
uiModifierSuper = 1 << 3,
|
||||
};
|
||||
|
||||
// TODO document drag captures
|
||||
struct uiAreaMouseEvent {
|
||||
// TODO document what these mean for scrolling areas
|
||||
double X;
|
||||
double Y;
|
||||
|
||||
// TODO see draw above
|
||||
double AreaWidth;
|
||||
double AreaHeight;
|
||||
|
||||
int Down;
|
||||
int Up;
|
||||
|
||||
int Count;
|
||||
|
||||
uiModifiers Modifiers;
|
||||
|
||||
uint64_t Held1To64;
|
||||
};
|
||||
|
||||
_UI_ENUM(uiExtKey) {
|
||||
uiExtKeyEscape = 1,
|
||||
uiExtKeyInsert, // equivalent to "Help" on Apple keyboards
|
||||
uiExtKeyDelete,
|
||||
uiExtKeyHome,
|
||||
uiExtKeyEnd,
|
||||
uiExtKeyPageUp,
|
||||
uiExtKeyPageDown,
|
||||
uiExtKeyUp,
|
||||
uiExtKeyDown,
|
||||
uiExtKeyLeft,
|
||||
uiExtKeyRight,
|
||||
uiExtKeyF1, // F1..F12 are guaranteed to be consecutive
|
||||
uiExtKeyF2,
|
||||
uiExtKeyF3,
|
||||
uiExtKeyF4,
|
||||
uiExtKeyF5,
|
||||
uiExtKeyF6,
|
||||
uiExtKeyF7,
|
||||
uiExtKeyF8,
|
||||
uiExtKeyF9,
|
||||
uiExtKeyF10,
|
||||
uiExtKeyF11,
|
||||
uiExtKeyF12,
|
||||
uiExtKeyN0, // numpad keys; independent of Num Lock state
|
||||
uiExtKeyN1, // N0..N9 are guaranteed to be consecutive
|
||||
uiExtKeyN2,
|
||||
uiExtKeyN3,
|
||||
uiExtKeyN4,
|
||||
uiExtKeyN5,
|
||||
uiExtKeyN6,
|
||||
uiExtKeyN7,
|
||||
uiExtKeyN8,
|
||||
uiExtKeyN9,
|
||||
uiExtKeyNDot,
|
||||
uiExtKeyNEnter,
|
||||
uiExtKeyNAdd,
|
||||
uiExtKeyNSubtract,
|
||||
uiExtKeyNMultiply,
|
||||
uiExtKeyNDivide,
|
||||
};
|
||||
|
||||
struct uiAreaKeyEvent {
|
||||
char Key;
|
||||
uiExtKey ExtKey;
|
||||
uiModifiers Modifier;
|
||||
|
||||
uiModifiers Modifiers;
|
||||
|
||||
// additional things
|
||||
int Scancode; // bit0-7: scancode, bit8: ext flag
|
||||
|
||||
int Up;
|
||||
int Repeat;
|
||||
};
|
||||
|
||||
typedef struct uiFontButton uiFontButton;
|
||||
#define uiFontButton(this) ((uiFontButton *) (this))
|
||||
// TODO document this returns a new font
|
||||
_UI_EXTERN uiDrawTextFont *uiFontButtonFont(uiFontButton *b);
|
||||
// TOOD SetFont, mechanics
|
||||
_UI_EXTERN void uiFontButtonOnChanged(uiFontButton *b, void (*f)(uiFontButton *, void *), void *data);
|
||||
_UI_EXTERN uiFontButton *uiNewFontButton(void);
|
||||
|
||||
typedef struct uiColorButton uiColorButton;
|
||||
#define uiColorButton(this) ((uiColorButton *) (this))
|
||||
_UI_EXTERN void uiColorButtonColor(uiColorButton *b, double *r, double *g, double *bl, double *a);
|
||||
_UI_EXTERN void uiColorButtonSetColor(uiColorButton *b, double r, double g, double bl, double a);
|
||||
_UI_EXTERN void uiColorButtonOnChanged(uiColorButton *b, void (*f)(uiColorButton *, void *), void *data);
|
||||
_UI_EXTERN uiColorButton *uiNewColorButton(void);
|
||||
|
||||
typedef struct uiForm uiForm;
|
||||
#define uiForm(this) ((uiForm *) (this))
|
||||
_UI_EXTERN void uiFormAppend(uiForm *f, const char *label, uiControl *c, int stretchy);
|
||||
_UI_EXTERN void uiFormDelete(uiForm *f, int index);
|
||||
_UI_EXTERN int uiFormPadded(uiForm *f);
|
||||
_UI_EXTERN void uiFormSetPadded(uiForm *f, int padded);
|
||||
_UI_EXTERN uiForm *uiNewForm(void);
|
||||
|
||||
_UI_ENUM(uiAlign) {
|
||||
uiAlignFill,
|
||||
uiAlignStart,
|
||||
uiAlignCenter,
|
||||
uiAlignEnd,
|
||||
};
|
||||
|
||||
_UI_ENUM(uiAt) {
|
||||
uiAtLeading,
|
||||
uiAtTop,
|
||||
uiAtTrailing,
|
||||
uiAtBottom,
|
||||
};
|
||||
|
||||
typedef struct uiGrid uiGrid;
|
||||
#define uiGrid(this) ((uiGrid *) (this))
|
||||
_UI_EXTERN void uiGridAppend(uiGrid *g, uiControl *c, int left, int top, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign);
|
||||
_UI_EXTERN void uiGridInsertAt(uiGrid *g, uiControl *c, uiControl *existing, uiAt at, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign);
|
||||
_UI_EXTERN int uiGridPadded(uiGrid *g);
|
||||
_UI_EXTERN void uiGridSetPadded(uiGrid *g, int padded);
|
||||
_UI_EXTERN uiGrid *uiNewGrid(void);
|
||||
|
||||
|
||||
// misc.
|
||||
|
||||
_UI_EXTERN char* uiKeyName(int scancode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,126 +0,0 @@
|
|||
// 26 june 2015
|
||||
#include "uipriv_unix.h"
|
||||
|
||||
// LONGTERM figure out why, and describe, that this is the desired behavior
|
||||
// LONGTERM also point out that font and color buttons also work like this
|
||||
|
||||
#define windowWindow(w) ((w)?(GTK_WINDOW(uiControlHandle(uiControl(w)))):NULL)
|
||||
|
||||
static char *filedialog(GtkWindow *parent, GtkFileChooserAction mode, const gchar *confirm, const char* filter, const char* initpath)
|
||||
{
|
||||
GtkWidget *fcd;
|
||||
GtkFileChooser *fc;
|
||||
gint response;
|
||||
char *filename;
|
||||
|
||||
fcd = gtk_file_chooser_dialog_new(NULL, parent, mode,
|
||||
"_Cancel", GTK_RESPONSE_CANCEL,
|
||||
confirm, GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
fc = GTK_FILE_CHOOSER(fcd);
|
||||
|
||||
// filters
|
||||
{
|
||||
gchar _filter[256];
|
||||
gchar* fp = &_filter[0]; int s = 0;
|
||||
gchar* fname;
|
||||
for (int i = 0; i < 255; i++)
|
||||
{
|
||||
if (filter[i] == '|' || filter[i] == '\0')
|
||||
{
|
||||
_filter[i] = '\0';
|
||||
if (s & 1)
|
||||
{
|
||||
GtkFileFilter* filter = gtk_file_filter_new();
|
||||
gtk_file_filter_set_name(filter, fname);
|
||||
|
||||
for (gchar* j = fp; ; j++)
|
||||
{
|
||||
if (*j == ';')
|
||||
{
|
||||
*j = '\0';
|
||||
gtk_file_filter_add_pattern(filter, fp);
|
||||
fp = j+1;
|
||||
}
|
||||
else if (*j == '\0')
|
||||
{
|
||||
gtk_file_filter_add_pattern(filter, fp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gtk_file_chooser_add_filter(fc, filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
fname = fp;
|
||||
}
|
||||
fp = &_filter[i+1];
|
||||
s++;
|
||||
if (s >= 8) break;
|
||||
if (filter[i] == '\0') break;
|
||||
}
|
||||
else
|
||||
_filter[i] = filter[i];
|
||||
}
|
||||
}
|
||||
|
||||
gtk_file_chooser_set_local_only(fc, FALSE);
|
||||
gtk_file_chooser_set_select_multiple(fc, FALSE);
|
||||
gtk_file_chooser_set_show_hidden(fc, TRUE);
|
||||
gtk_file_chooser_set_do_overwrite_confirmation(fc, TRUE);
|
||||
gtk_file_chooser_set_create_folders(fc, TRUE);
|
||||
if (initpath && strlen(initpath)>0)
|
||||
gtk_file_chooser_set_current_folder(fc, initpath);
|
||||
|
||||
response = gtk_dialog_run(GTK_DIALOG(fcd));
|
||||
if (response != GTK_RESPONSE_ACCEPT) {
|
||||
gtk_widget_destroy(fcd);
|
||||
return NULL;
|
||||
}
|
||||
filename = uiUnixStrdupText(gtk_file_chooser_get_filename(fc));
|
||||
gtk_widget_destroy(fcd);
|
||||
return filename;
|
||||
}
|
||||
|
||||
char *uiOpenFile(uiWindow *parent, const char* filter, const char* initpath)
|
||||
{
|
||||
return filedialog(windowWindow(parent), GTK_FILE_CHOOSER_ACTION_OPEN, "_Open", filter, initpath);
|
||||
}
|
||||
|
||||
char *uiSaveFile(uiWindow *parent, const char* filter, const char* initpath)
|
||||
{
|
||||
return filedialog(windowWindow(parent), GTK_FILE_CHOOSER_ACTION_SAVE, "_Save", filter, initpath);
|
||||
}
|
||||
|
||||
static int msgbox(GtkWindow *parent, const char *title, const char *description, GtkMessageType type, GtkButtonsType buttons)
|
||||
{
|
||||
GtkWidget *md;
|
||||
|
||||
md = gtk_message_dialog_new(parent, GTK_DIALOG_MODAL,
|
||||
type, buttons,
|
||||
"%s", title);
|
||||
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(md), "%s", description);
|
||||
int result = gtk_dialog_run(GTK_DIALOG(md));
|
||||
gtk_widget_destroy(md);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void uiMsgBox(uiWindow *parent, const char *title, const char *description)
|
||||
{
|
||||
msgbox(windowWindow(parent), title, description, GTK_MESSAGE_OTHER, GTK_BUTTONS_OK);
|
||||
}
|
||||
|
||||
void uiMsgBoxError(uiWindow *parent, const char *title, const char *description)
|
||||
{
|
||||
msgbox(windowWindow(parent), title, description, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK);
|
||||
}
|
||||
|
||||
int uiMsgBoxConfirm(uiWindow * parent, const char *title, const char *description)
|
||||
{
|
||||
int result =
|
||||
msgbox(windowWindow(parent), title, description, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL);
|
||||
|
||||
return result == GTK_RESPONSE_OK;
|
||||
}
|
|
@ -1,180 +0,0 @@
|
|||
// 22 may 2015
|
||||
#include "uipriv_windows.hpp"
|
||||
|
||||
// TODO document all this is what we want
|
||||
// TODO do the same for font and color buttons
|
||||
|
||||
// notes:
|
||||
// - FOS_SUPPORTSTREAMABLEITEMS doesn't seem to be supported on windows vista, or at least not with the flags we use
|
||||
// - even with FOS_NOVALIDATE the dialogs will reject invalid filenames (at least on Vista, anyway)
|
||||
// - lack of FOS_NOREADONLYRETURN doesn't seem to matter on Windows 7
|
||||
|
||||
// TODO
|
||||
// - http://blogs.msdn.com/b/wpfsdk/archive/2006/10/26/uncommon-dialogs--font-chooser-and-color-picker-dialogs.aspx
|
||||
// - when a dialog is active, tab navigation in other windows stops working
|
||||
// - when adding uiOpenFolder(), use IFileDialog as well - https://msdn.microsoft.com/en-us/library/windows/desktop/bb762115%28v=vs.85%29.aspx
|
||||
|
||||
#define windowHWND(w) (w ? (HWND) uiControlHandle(uiControl(w)) : NULL)
|
||||
|
||||
char *commonItemDialog(HWND parent, REFCLSID clsid, REFIID iid, const char* filter, const char* initpath, FILEOPENDIALOGOPTIONS optsadd)
|
||||
{
|
||||
IFileDialog *d = NULL;
|
||||
FILEOPENDIALOGOPTIONS opts;
|
||||
IShellItem *result = NULL;
|
||||
WCHAR *wname = NULL;
|
||||
char *name = NULL;
|
||||
HRESULT hr;
|
||||
|
||||
hr = CoCreateInstance(clsid,
|
||||
NULL, CLSCTX_INPROC_SERVER,
|
||||
iid, (LPVOID *) (&d));
|
||||
if (hr != S_OK) {
|
||||
logHRESULT(L"error creating common item dialog", hr);
|
||||
// always return NULL on error
|
||||
goto out;
|
||||
}
|
||||
hr = d->GetOptions(&opts);
|
||||
if (hr != S_OK) {
|
||||
logHRESULT(L"error getting current options", hr);
|
||||
goto out;
|
||||
}
|
||||
opts |= optsadd;
|
||||
// the other platforms don't check read-only; we won't either
|
||||
opts &= ~FOS_NOREADONLYRETURN;
|
||||
hr = d->SetOptions(opts);
|
||||
if (hr != S_OK) {
|
||||
logHRESULT(L"error setting options", hr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
// filters
|
||||
{
|
||||
COMDLG_FILTERSPEC filterspec[8];
|
||||
wchar_t _filter[256];
|
||||
wchar_t* fp = &_filter[0]; int s = 0;
|
||||
wchar_t* fname;
|
||||
for (int i = 0; i < 255; i++)
|
||||
{
|
||||
if (filter[i] == '|' || filter[i] == '\0')
|
||||
{
|
||||
_filter[i] = '\0';
|
||||
if (s & 1)
|
||||
{
|
||||
filterspec[s>>1].pszName = fname;
|
||||
filterspec[s>>1].pszSpec = fp;
|
||||
}
|
||||
else
|
||||
{
|
||||
fname = fp;
|
||||
}
|
||||
fp = &_filter[i+1];
|
||||
s++;
|
||||
if (s >= 8) break;
|
||||
if (filter[i] == '\0') break;
|
||||
}
|
||||
else
|
||||
_filter[i] = filter[i];
|
||||
}
|
||||
d->SetFileTypes(s>>1, filterspec);
|
||||
}
|
||||
|
||||
hr = d->Show(parent);
|
||||
if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED))
|
||||
// cancelled; return NULL like we have ready
|
||||
goto out;
|
||||
if (hr != S_OK) {
|
||||
logHRESULT(L"error showing dialog", hr);
|
||||
goto out;
|
||||
}
|
||||
hr = d->GetResult(&result);
|
||||
if (hr != S_OK) {
|
||||
logHRESULT(L"error getting dialog result", hr);
|
||||
goto out;
|
||||
}
|
||||
hr = result->GetDisplayName(SIGDN_FILESYSPATH, &wname);
|
||||
if (hr != S_OK) {
|
||||
logHRESULT(L"error getting filename", hr);
|
||||
goto out;
|
||||
}
|
||||
name = toUTF8(wname);
|
||||
|
||||
out:
|
||||
if (wname != NULL)
|
||||
CoTaskMemFree(wname);
|
||||
if (result != NULL)
|
||||
result->Release();
|
||||
if (d != NULL)
|
||||
d->Release();
|
||||
return name;
|
||||
}
|
||||
|
||||
char *uiOpenFile(uiWindow *parent, const char* filter, const char* initpath)
|
||||
{
|
||||
char *res;
|
||||
|
||||
disableAllWindowsExcept(parent);
|
||||
res = commonItemDialog(windowHWND(parent),
|
||||
CLSID_FileOpenDialog, IID_IFileOpenDialog,
|
||||
filter, initpath,
|
||||
FOS_NOCHANGEDIR | FOS_FORCEFILESYSTEM | FOS_NOVALIDATE | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_SHAREAWARE | FOS_NOTESTFILECREATE | FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE);
|
||||
enableAllWindowsExcept(parent);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *uiSaveFile(uiWindow *parent, const char* filter, const char* initpath)
|
||||
{
|
||||
char *res;
|
||||
|
||||
disableAllWindowsExcept(parent);
|
||||
res = commonItemDialog(windowHWND(parent),
|
||||
CLSID_FileSaveDialog, IID_IFileSaveDialog,
|
||||
filter, initpath,
|
||||
FOS_OVERWRITEPROMPT | FOS_NOCHANGEDIR | FOS_FORCEFILESYSTEM | FOS_NOVALIDATE | FOS_SHAREAWARE | FOS_NOTESTFILECREATE | FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE);
|
||||
enableAllWindowsExcept(parent);
|
||||
return res;
|
||||
}
|
||||
|
||||
// TODO switch to TaskDialogIndirect()?
|
||||
|
||||
static int msgbox(HWND parent, const char *title, const char *description, TASKDIALOG_COMMON_BUTTON_FLAGS buttons, PCWSTR icon)
|
||||
{
|
||||
WCHAR *wtitle, *wdescription;
|
||||
HRESULT hr;
|
||||
|
||||
wtitle = toUTF16(title);
|
||||
wdescription = toUTF16(description);
|
||||
|
||||
int result;
|
||||
hr = TaskDialog(parent, NULL, NULL, wtitle, wdescription, buttons, icon, &result);
|
||||
if (hr != S_OK)
|
||||
logHRESULT(L"error showing task dialog", hr);
|
||||
|
||||
uiFree(wdescription);
|
||||
uiFree(wtitle);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void uiMsgBox(uiWindow *parent, const char *title, const char *description)
|
||||
{
|
||||
disableAllWindowsExcept(parent);
|
||||
msgbox(windowHWND(parent), title, description, TDCBF_OK_BUTTON, NULL);
|
||||
enableAllWindowsExcept(parent);
|
||||
}
|
||||
|
||||
void uiMsgBoxError(uiWindow *parent, const char *title, const char *description)
|
||||
{
|
||||
disableAllWindowsExcept(parent);
|
||||
msgbox(windowHWND(parent), title, description, TDCBF_OK_BUTTON, TD_ERROR_ICON);
|
||||
enableAllWindowsExcept(parent);
|
||||
}
|
||||
|
||||
int uiMsgBoxConfirm(uiWindow * parent, const char *title, const char *description)
|
||||
{
|
||||
disableAllWindowsExcept(parent);
|
||||
int result =
|
||||
msgbox(windowHWND(parent), title, description, TDCBF_OK_BUTTON | TDCBF_CANCEL_BUTTON, TD_WARNING_ICON);
|
||||
enableAllWindowsExcept(parent);
|
||||
|
||||
return result == IDOK;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue