reconcile DSi and JIT, fastmem for x64 and Windows

This commit is contained in:
RSDuck 2020-06-30 23:50:41 +02:00
parent ea6d03581b
commit c5381d2911
29 changed files with 1691 additions and 5492 deletions

View File

@ -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

View File

@ -147,7 +147,7 @@ public:
NDS::MemRegion CodeMem;
#ifdef JIT_ENABLED
u32 FastBlockLookupStart = 0, FastBlockLookupSize = 0;
u32 FastBlockLookupStart, FastBlockLookupSize;
u64* FastBlockLookup;
#endif

View File

@ -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(&region[(addressRanges[j] & 0xFFFF000) / 512]))
ARMJIT_Memory::SetCodeProtection(addressRanges[j] >> 28, addressRanges[j] & 0xFFFFFFF, true);
if (!PageContainsCode(&region[(addressRanges[j] & 0x7FFF000) / 512]))
ARMJIT_Memory::SetCodeProtection(addressRanges[j] >> 27, addressRanges[j] & 0x7FFFFFF, true);
AddressRange* range = &region[(addressRanges[j] & 0xFFFFFFF) / 512];
AddressRange* range = &region[(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 = &region[(localAddr & 0xFFFFFFF) / 512];
AddressRange* region = CodeMemRegions[localAddr >> 27];
AddressRange* range = &region[(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(&region[(localAddr & 0xFFFF000) / 512]))
&& !PageContainsCode(&region[(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;
}

View File

@ -16,6 +16,8 @@ void DeInit();
void Reset();
void CheckAndInvalidateITCM();
void InvalidateByAddr(u32 pseudoPhysical);
template <u32 num, int region>

View File

@ -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)
{

View File

@ -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);
}

View File

@ -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:

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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])
{

View File

@ -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)

View File

@ -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}

View File

@ -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

View File

@ -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;

View File

@ -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();

View File

@ -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;
}

View File

@ -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;

View File

@ -165,6 +165,8 @@ extern u16 ARM7BIOSProt;
extern u8* MainRAM;
extern u32 MainRAMMask;
const u32 MainRAMMaxSize = 0x1000000;
const u32 SharedWRAMSize = 0x8000;
extern u8* SharedWRAM;

View File

@ -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);
}

View File

@ -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();

View File

@ -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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DS-mode ARM9 BIOS&lt;/p&gt;&lt;p&gt;Size should be 4 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DS-mode ARM7 BIOS&lt;/p&gt;&lt;p&gt;Size should be 16 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DS-mode firmware&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Possible firmwares:&lt;/p&gt;&lt;p&gt;* 128 KB: DS-mode firmware from a DSi or 3DS. Not bootable.&lt;/p&gt;&lt;p&gt;* 256 KB: regular DS firmware.&lt;/p&gt;&lt;p&gt;* 512 KB: iQue DS firmware.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DSi-mode ARM7 BIOS&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Size should be 64 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="txtDSiFirmwarePath">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DSi-mode firmware (used for DS-mode backwards compatibility)&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Size should be 128 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DSi-mode ARM9 BIOS&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Size should be 64 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DSi NAND dump&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Should have 'nocash footer' at the end&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The type of console to emulate&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="chkDirectBoot">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When loading a ROM, completely skip the regular boot process (&amp;quot;Nintendo DS&amp;quot; screen) to boot the ROM directly.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Note: if your firmware dump isn't bootable, the ROM will be booted directly regardless of this setting.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The type of console to emulate&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="chkDirectBoot">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When loading a ROM, completely skip the regular boot process (&amp;quot;Nintendo DS&amp;quot; screen) to boot the ROM directly.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Note: if your firmware dump isn't bootable, the ROM will be booted directly regardless of this setting.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DS-mode firmware&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Possible firmwares:&lt;/p&gt;&lt;p&gt;* 128 KB: DS-mode firmware from a DSi or 3DS. Not bootable.&lt;/p&gt;&lt;p&gt;* 256 KB: regular DS firmware.&lt;/p&gt;&lt;p&gt;* 512 KB: iQue DS firmware.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="txtBIOS7Path">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DS-mode ARM7 BIOS&lt;/p&gt;&lt;p&gt;Size should be 16 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DS-mode ARM9 BIOS&lt;/p&gt;&lt;p&gt;Size should be 4 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DSi-mode ARM7 BIOS&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Size should be 64 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="txtDSiFirmwarePath">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DSi-mode firmware (used for DS-mode backwards compatibility)&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Size should be 128 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DSi-mode ARM9 BIOS&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Size should be 64 KB&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DSi NAND dump&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Should have 'nocash footer' at the end&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>

View File

@ -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()

View File

@ -199,6 +199,7 @@ private slots:
void onStop();
void onOpenEmuSettings();
void onEmuSettingsDialogFinished(int res);
void onOpenInputConfig();
void onInputConfigFinished(int res);
void onOpenVideoSettings();

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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