1
0
Fork 0
mirror of https://github.com/melonDS-emu/melonDS.git synced 2025-03-06 21:00:31 +01:00
This commit is contained in:
Jakly 2025-02-21 11:53:02 +01:00 committed by GitHub
commit 06b3d88097
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 7672 additions and 1732 deletions

File diff suppressed because it is too large Load diff

961
src/ARM.h

File diff suppressed because it is too large Load diff

View file

@ -36,6 +36,8 @@ namespace melonDS::ARMInterpreter
void A_UNK(ARM* cpu)
{
if (cpu->CheckInterlock) return;
cpu->AddCycles_C();
Log(LogLevel::Warn, "undefined ARM%d instruction %08X @ %08X\n", cpu->Num?7:9, cpu->CurInstr, cpu->R[15]-8);
#ifdef GDBSTUB_ENABLED
cpu->GdbStub.Enter(cpu->GdbStub.IsConnected(), Gdb::TgtStatus::FaultInsn, cpu->R[15]-8);
@ -49,11 +51,14 @@ void A_UNK(ARM* cpu)
cpu->R_UND[2] = oldcpsr;
cpu->R[14] = cpu->R[15] - 4;
cpu->JumpTo(cpu->ExceptionBase + 0x04);
}
void T_UNK(ARM* cpu)
{
if (cpu->CheckInterlock) return;
cpu->AddCycles_C();
Log(LogLevel::Warn, "undefined THUMB%d instruction %04X @ %08X\n", cpu->Num?7:9, cpu->CurInstr, cpu->R[15]-4);
#ifdef GDBSTUB_ENABLED
cpu->GdbStub.Enter(cpu->GdbStub.IsConnected(), Gdb::TgtStatus::FaultInsn, cpu->R[15]-4);
@ -66,13 +71,27 @@ void T_UNK(ARM* cpu)
cpu->R_UND[2] = oldcpsr;
cpu->R[14] = cpu->R[15] - 2;
cpu->JumpTo(cpu->ExceptionBase + 0x04);
}
void A_BKPT(ARM* cpu)
{
if (cpu->CheckInterlock) return;
if (cpu->Num == 1) return A_UNK(cpu); // checkme
Log(LogLevel::Warn, "BKPT: "); // combine with the prefetch abort warning message
((ARMv5*)cpu)->PrefetchAbort();
}
void A_MSR_IMM(ARM* cpu)
{
if (cpu->CheckInterlock) return;
if ((cpu->Num != 1) && (cpu->CurInstr & ((0x7<<16)|(1<<22)))) cpu->AddCycles_CI(2); // arm9 cpsr_sxc & spsr
else cpu->AddCycles_C();
u32* psr;
if (cpu->CurInstr & (1<<22))
{
@ -90,7 +109,6 @@ void A_MSR_IMM(ARM* cpu)
case 0x1A:
case 0x1B: psr = &cpu->R_UND[2]; break;
default:
cpu->AddCycles_C();
return;
}
}
@ -101,12 +119,9 @@ void A_MSR_IMM(ARM* cpu)
u32 mask = 0;
if (cpu->CurInstr & (1<<16)) mask |= 0x000000FF;
if (cpu->CurInstr & (1<<17)) mask |= 0x0000FF00;
if (cpu->CurInstr & (1<<18)) mask |= 0x00FF0000;
if (cpu->CurInstr & (1<<19)) mask |= 0xFF000000;
if (!(cpu->CurInstr & (1<<22)))
mask &= 0xFFFFFFDF;
//if (cpu->CurInstr & (1<<17)) mask |= 0x0000FF00; // unused by arm 7 & 9
//if (cpu->CurInstr & (1<<18)) mask |= 0x00FF0000; // unused by arm 7 & 9
if (cpu->CurInstr & (1<<19)) mask |= ((cpu->Num==1) ? 0xF0000000 : 0xF8000000);
if ((cpu->CPSR & 0x1F) == 0x10) mask &= 0xFFFFFF00;
@ -121,11 +136,29 @@ void A_MSR_IMM(ARM* cpu)
if (!(cpu->CurInstr & (1<<22)))
cpu->UpdateMode(oldpsr, cpu->CPSR);
cpu->AddCycles_C();
if (cpu->CPSR & 0x20) [[unlikely]]
{
if (cpu->Num == 0)
{
cpu->R[15] += 2; // pc should actually increment by 4 one more time after switching to thumb mode without a pipeline flush, this gets the same effect.
((ARMv5*)cpu)->StartExec = &ARMv5::StartExecTHUMB;
if (cpu->MRTrack.Type == MainRAMType::Null) ((ARMv5*)cpu)->FuncQueue[0] = ((ARMv5*)cpu)->StartExec;
}
else
{
Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: MSR REG T bit change on ARM7\n");
cpu->CPSR &= ~0x20; // keep it from crashing the emulator at least
}
}
}
void A_MSR_REG(ARM* cpu)
{
if (cpu->CheckInterlock) return ((ARMv5*)cpu)->HandleInterlocksExecute<false>(cpu->CurInstr & 0xF);
if ((cpu->Num != 1) && (cpu->CurInstr & ((0x7<<16)|(1<<22)))) cpu->AddCycles_CI(2); // arm9 cpsr_sxc & spsr
else cpu->AddCycles_C();
u32* psr;
if (cpu->CurInstr & (1<<22))
{
@ -143,7 +176,6 @@ void A_MSR_REG(ARM* cpu)
case 0x1A:
case 0x1B: psr = &cpu->R_UND[2]; break;
default:
cpu->AddCycles_C();
return;
}
}
@ -154,12 +186,9 @@ void A_MSR_REG(ARM* cpu)
u32 mask = 0;
if (cpu->CurInstr & (1<<16)) mask |= 0x000000FF;
if (cpu->CurInstr & (1<<17)) mask |= 0x0000FF00;
if (cpu->CurInstr & (1<<18)) mask |= 0x00FF0000;
if (cpu->CurInstr & (1<<19)) mask |= 0xFF000000;
if (!(cpu->CurInstr & (1<<22)))
mask &= 0xFFFFFFDF;
//if (cpu->CurInstr & (1<<17)) mask |= 0x0000FF00; // unused by arm 7 & 9
//if (cpu->CurInstr & (1<<18)) mask |= 0x00FF0000; // unused by arm 7 & 9
if (cpu->CurInstr & (1<<19)) mask |= ((cpu->Num==1) ? 0xF0000000 : 0xF8000000);
if ((cpu->CPSR & 0x1F) == 0x10) mask &= 0xFFFFFF00;
@ -174,11 +203,25 @@ void A_MSR_REG(ARM* cpu)
if (!(cpu->CurInstr & (1<<22)))
cpu->UpdateMode(oldpsr, cpu->CPSR);
cpu->AddCycles_C();
if (cpu->CPSR & 0x20) [[unlikely]]
{
if (cpu->Num == 0)
{
cpu->R[15] += 2; // pc should actually increment by 4 one more time after switching to thumb mode without a pipeline flush, this gets the same effect.
((ARMv5*)cpu)->StartExec = &ARMv5::StartExecTHUMB;
if (cpu->MRTrack.Type == MainRAMType::Null) ((ARMv5*)cpu)->FuncQueue[0] = ((ARMv5*)cpu)->StartExec;
}
else
{
Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: MSR REG T bit change on ARM7\n");
cpu->CPSR &= ~0x20; // keep it from crashing the emulator at least
}
}
}
void A_MRS(ARM* cpu)
{
if (cpu->CheckInterlock) return;
u32 psr;
if (cpu->CurInstr & (1<<22))
{
@ -201,8 +244,19 @@ void A_MRS(ARM* cpu)
else
psr = cpu->CPSR;
cpu->R[(cpu->CurInstr>>12) & 0xF] = psr;
cpu->AddCycles_C();
if (cpu->Num != 1) // arm9
{
cpu->AddCycles_CI(2); // 1 X
((ARMv5*)cpu)->AddCycles_MW(2); // 2 M
}
else cpu->AddCycles_C(); // arm7
if (((cpu->CurInstr>>12) & 0xF) == 15)
{
if (cpu->Num == 1) // doesn't seem to jump on the arm9? checkme
cpu->JumpTo(psr & ~0x1); // checkme: this shouldn't be able to switch to thumb?
}
else cpu->R[(cpu->CurInstr>>12) & 0xF] = psr;
}
@ -211,15 +265,19 @@ void A_MCR(ARM* cpu)
if ((cpu->CPSR & 0x1F) == 0x10)
return A_UNK(cpu);
if (cpu->CheckInterlock) return ((ARMv5*)cpu)->HandleInterlocksExecute<false>((cpu->CurInstr>>12)&0xF);
u32 cp = (cpu->CurInstr >> 8) & 0xF;
//u32 op = (cpu->CurInstr >> 21) & 0x7;
u32 op = (cpu->CurInstr >> 21) & 0x7;
u32 cn = (cpu->CurInstr >> 16) & 0xF;
u32 cm = cpu->CurInstr & 0xF;
u32 cpinfo = (cpu->CurInstr >> 5) & 0x7;
u32 val = cpu->R[(cpu->CurInstr>>12)&0xF];
if (((cpu->CurInstr>>12) & 0xF) == 15) val += 4;
if (cpu->Num==0 && cp==15)
{
((ARMv5*)cpu)->CP15Write((cn<<8)|(cm<<4)|cpinfo, cpu->R[(cpu->CurInstr>>12)&0xF]);
((ARMv5*)cpu)->CP15Write((cn<<8)|(cm<<4)|cpinfo|(op<<12), val);
}
else if (cpu->Num==1 && cp==14)
{
@ -227,11 +285,12 @@ void A_MCR(ARM* cpu)
}
else
{
Log(LogLevel::Warn, "bad MCR opcode p%d,%d,%d,%d on ARM%d\n", cp, cn, cm, cpinfo, cpu->Num?7:9);
Log(LogLevel::Warn, "bad MCR opcode p%d, %d, reg, c%d, c%d, %d on ARM%d\n", cp, op, cn, cm, cpinfo, cpu->Num?7:9);
return A_UNK(cpu); // TODO: check what kind of exception it really is
}
cpu->AddCycles_CI(1 + 1); // TODO: checkme
if (cpu->Num==0) cpu->AddCycles_CI(5); // checkme
else /* ARM7 */ cpu->AddCycles_CI(1 + 1); // TODO: checkme
}
void A_MRC(ARM* cpu)
@ -239,15 +298,24 @@ void A_MRC(ARM* cpu)
if ((cpu->CPSR & 0x1F) == 0x10)
return A_UNK(cpu);
if (cpu->CheckInterlock) return ((ARMv5*)cpu)->HandleInterlocksExecute<false>((cpu->CurInstr>>12)&0xF);
u32 cp = (cpu->CurInstr >> 8) & 0xF;
//u32 op = (cpu->CurInstr >> 21) & 0x7;
u32 op = (cpu->CurInstr >> 21) & 0x7;
u32 cn = (cpu->CurInstr >> 16) & 0xF;
u32 cm = cpu->CurInstr & 0xF;
u32 cpinfo = (cpu->CurInstr >> 5) & 0x7;
u32 rd = (cpu->CurInstr>>12) & 0xF;
if (cpu->Num==0 && cp==15)
{
cpu->R[(cpu->CurInstr>>12)&0xF] = ((ARMv5*)cpu)->CP15Read((cn<<8)|(cm<<4)|cpinfo);
if (rd != 15) cpu->R[rd] = ((ARMv5*)cpu)->CP15Read((cn<<8)|(cm<<4)|cpinfo|(op<<12));
else
{
// r15 updates the top 4 bits of the cpsr, done to "allow for conditional branching based on coprocessor status"
u32 flags = ((ARMv5*)cpu)->CP15Read((cn<<8)|(cm<<4)|cpinfo|(op<<12)) & 0xF0000000;
cpu->CPSR = (cpu->CPSR & ~0xF0000000) | flags;
}
}
else if (cpu->Num==1 && cp==14)
{
@ -255,17 +323,25 @@ void A_MRC(ARM* cpu)
}
else
{
Log(LogLevel::Warn, "bad MRC opcode p%d,%d,%d,%d on ARM%d\n", cp, cn, cm, cpinfo, cpu->Num?7:9);
Log(LogLevel::Warn, "bad MRC opcode p%d, %d, reg, c%d, c%d, %d on ARM%d\n", cp, op, cn, cm, cpinfo, cpu->Num?7:9);
return A_UNK(cpu); // TODO: check what kind of exception it really is
}
cpu->AddCycles_CI(2 + 1); // TODO: checkme
if (cpu->Num != 1)
{
cpu->AddCycles_CI(2); // 1 Execute cycle
((ARMv5*)cpu)->AddCycles_MW(2); // 2 Memory cycles
((ARMv5*)cpu)->SetupInterlock((cpu->CurInstr >> 12) & 0xF);
}
else cpu->AddCycles_CI(2 + 1); // TODO: checkme
}
void A_SVC(ARM* cpu)
void A_SVC(ARM* cpu) // A_SWI
{
if (cpu->CheckInterlock) return;
cpu->AddCycles_C();
u32 oldcpsr = cpu->CPSR;
cpu->CPSR &= ~0xBF;
cpu->CPSR |= 0x93;
@ -273,11 +349,14 @@ void A_SVC(ARM* cpu)
cpu->R_SVC[2] = oldcpsr;
cpu->R[14] = cpu->R[15] - 4;
cpu->JumpTo(cpu->ExceptionBase + 0x08);
}
void T_SVC(ARM* cpu)
void T_SVC(ARM* cpu) // T_SWI
{
if (cpu->CheckInterlock) return;
cpu->AddCycles_C();
u32 oldcpsr = cpu->CPSR;
cpu->CPSR &= ~0xBF;
cpu->CPSR |= 0x93;
@ -285,6 +364,7 @@ void T_SVC(ARM* cpu)
cpu->R_SVC[2] = oldcpsr;
cpu->R[14] = cpu->R[15] - 2;
cpu->JumpTo(cpu->ExceptionBase + 0x08);
}

View file

@ -36,6 +36,7 @@ void A_MRS(ARM* cpu);
void A_MCR(ARM* cpu);
void A_MRC(ARM* cpu);
void A_SVC(ARM* cpu);
void A_BKPT(ARM* cpu);
void T_SVC(ARM* cpu);

File diff suppressed because it is too large Load diff

View file

@ -27,12 +27,16 @@ using Platform::LogLevel;
void A_B(ARM* cpu)
{
if (cpu->CheckInterlock) return;
cpu->AddCycles_C();
s32 offset = (s32)(cpu->CurInstr << 8) >> 6;
cpu->JumpTo(cpu->R[15] + offset);
}
void A_BL(ARM* cpu)
{
if (cpu->CheckInterlock) return;
cpu->AddCycles_C();
s32 offset = (s32)(cpu->CurInstr << 8) >> 6;
cpu->R[14] = cpu->R[15] - 4;
cpu->JumpTo(cpu->R[15] + offset);
@ -40,6 +44,8 @@ void A_BL(ARM* cpu)
void A_BLX_IMM(ARM* cpu)
{
if (cpu->CheckInterlock) return;
cpu->AddCycles_C();
s32 offset = (s32)(cpu->CurInstr << 8) >> 6;
if (cpu->CurInstr & 0x01000000) offset += 2;
cpu->R[14] = cpu->R[15] - 4;
@ -48,11 +54,15 @@ void A_BLX_IMM(ARM* cpu)
void A_BX(ARM* cpu)
{
if (cpu->CheckInterlock) return ((ARMv5*)cpu)->HandleInterlocksExecute<false>(cpu->CurInstr&0xF);
cpu->AddCycles_C();
cpu->JumpTo(cpu->R[cpu->CurInstr & 0xF]);
}
void A_BLX_REG(ARM* cpu)
{
if (cpu->CheckInterlock) return ((ARMv5*)cpu)->HandleInterlocksExecute<false>(cpu->CurInstr&0xF);
cpu->AddCycles_C();
u32 lr = cpu->R[15] - 4;
cpu->JumpTo(cpu->R[cpu->CurInstr & 0xF]);
cpu->R[14] = lr;
@ -62,22 +72,26 @@ void A_BLX_REG(ARM* cpu)
void T_BCOND(ARM* cpu)
{
if (cpu->CheckInterlock) return;
cpu->AddCycles_C();
if (cpu->CheckCondition((cpu->CurInstr >> 8) & 0xF))
{
s32 offset = (s32)(cpu->CurInstr << 24) >> 23;
cpu->JumpTo(cpu->R[15] + offset + 1);
}
else
cpu->AddCycles_C();
}
void T_BX(ARM* cpu)
{
if (cpu->CheckInterlock) return ((ARMv5*)cpu)->HandleInterlocksExecute<false>((cpu->CurInstr >> 3) & 0xF);
cpu->AddCycles_C();
cpu->JumpTo(cpu->R[(cpu->CurInstr >> 3) & 0xF]);
}
void T_BLX_REG(ARM* cpu)
{
if (cpu->CheckInterlock) return ((ARMv5*)cpu)->HandleInterlocksExecute<false>((cpu->CurInstr >> 3) & 0xF);
cpu->AddCycles_C();
if (cpu->Num==1)
{
Log(LogLevel::Warn, "!! THUMB BLX_REG ON ARM7\n");
@ -91,12 +105,15 @@ void T_BLX_REG(ARM* cpu)
void T_B(ARM* cpu)
{
if (cpu->CheckInterlock) return;
cpu->AddCycles_C();
s32 offset = (s32)((cpu->CurInstr & 0x7FF) << 21) >> 20;
cpu->JumpTo(cpu->R[15] + offset + 1);
}
void T_BL_LONG_1(ARM* cpu)
{
if (cpu->CheckInterlock) return;
s32 offset = (s32)((cpu->CurInstr & 0x7FF) << 21) >> 9;
cpu->R[14] = cpu->R[15] + offset;
cpu->AddCycles_C();
@ -104,6 +121,12 @@ void T_BL_LONG_1(ARM* cpu)
void T_BL_LONG_2(ARM* cpu)
{
if ((cpu->CurInstr & 0x1801) == 0x0801) // "BLX" with bit 0 set is an undefined instruction.
return T_UNK(cpu); // TODO: Check ARM7 for exceptions
if (cpu->CheckInterlock) return;
cpu->AddCycles_C();
s32 offset = (cpu->CurInstr & 0x7FF) << 1;
u32 pc = cpu->R[14] + offset;
cpu->R[14] = (cpu->R[15] - 2) | 1;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,136 @@
#ifndef ARMINTERPRETER_MULTIPLYSUPERLLE_H
#define ARMINTERPRETER_MULTIPLYSUPERLLE_H
#include "types.h"
using namespace melonDS;
/*
Copyright (c) 2024 zaydlang
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
// code taken from: (also features a few alternative implementations that could maybe be worth looking at?)
// https://github.com/calc84maniac/multiplication-algorithm/blob/master/impl_opt.h
// based on research that can be found here: https://bmchtech.github.io/post/multiply/
// the code in this file is dedicated to handling the calculation of the carry flag for multiplication (S variant) instructions on the ARM7TDMI.
// Takes a multiplier between -0x01000000 and 0x00FFFFFF, cycles between 0 and 2
static inline bool booths_multiplication32_opt(u32 multiplicand, u32 multiplier, u32 accumulator) {
// Set the low bit of the multiplicand to cause negation to invert the upper bits, this bit can't propagate to bit 31
multiplicand |= 1;
// Optimized first iteration
u32 booth = (s32)(multiplier << 31) >> 31;
u32 carry = booth * multiplicand;
// Pre-populate accumulator for output
u32 output = accumulator;
u32 sum = output + carry;
int shift = 29;
do {
for (int i = 0; i < 4; i++, shift -= 2) {
// Get next booth factor (-2 to 2, shifted left by 30-shift)
u32 next_booth = (s32)(multiplier << shift) >> shift;
u32 factor = next_booth - booth;
booth = next_booth;
// Get scaled value of booth addend
u32 addend = multiplicand * factor;
// Combine the addend with the CSA
// Not performing any masking seems to work because the lower carries can't propagate to bit 31
output ^= carry ^ addend;
sum += addend;
carry = sum - output;
}
} while (booth != multiplier);
return carry >> 31;
}
// Takes a multiplicand shifted right by 6 and a multiplier shifted right by 26 (zero or sign extended)
static inline bool booths_multiplication64_opt(u32 multiplicand, u32 multiplier, u32 accum_hi) {
// Skipping the first 14 iterations seems to work because the lower carries can't propagate to bit 63
// This means only magic bits 62-61 are needed (which requires decoding 3 booth chunks),
// and only the last two booth iterations are needed
// Set the low bit of the multiplicand to cause negation to invert the upper bits
multiplicand |= 1;
// Pre-populate magic bit 61 for carry
u32 carry = ~accum_hi & UINT32_C(0x20000000);
// Pre-populate magic bits 63-60 for output (with carry magic pre-added in)
u32 output = accum_hi - UINT32_C(0x08000000);
// Get factors from the top 3 booth chunks
u32 booth0 = (s32)(multiplier << 27) >> 27;
u32 booth1 = (s32)(multiplier << 29) >> 29;
u32 booth2 = (s32)(multiplier << 31) >> 31;
u32 factor0 = multiplier - booth0;
u32 factor1 = booth0 - booth1;
u32 factor2 = booth1 - booth2;
// Get scaled value of the 3rd top booth addend
u32 addend = multiplicand * factor2;
// Finalize bits 61-60 of output magic using its sign
output -= addend & UINT32_C(0x10000000);
// Get scaled value of the 2nd top booth addend
addend = multiplicand * factor1;
// Finalize bits 63-62 of output magic using its sign
output -= addend & UINT32_C(0x40000000);
// Get the carry from the CSA in bit 61 and propagate it to bit 62, which is not processed in this iteration
u32 sum = output + (addend & UINT32_C(0x20000000));
// Subtract out the carry magic to get the actual output magic
output -= carry;
// Get scaled value of the 1st top booth addend
addend = multiplicand * factor0;
// Add to bit 62 and propagate the carry
sum += addend & UINT32_C(0x40000000);
// Cancel out the output magic bit 63 to get the carry bit 63
return (sum ^ output) >> 31;
}
// also for MLAS and MUL (thumb ver.)
inline bool MULSCarry(s32 rm, s32 rs, u32 rn, bool lastcycle)
{
if (lastcycle)
return (rs >> 30) == -2;
else
return booths_multiplication32_opt(rm, rs, rn);
}
// also for UMLALS
inline bool UMULLSCarry(u64 rd, u32 rm, u32 rs, bool lastcycle)
{
if (lastcycle)
return booths_multiplication64_opt(rm >> 6, rs >> 26, rd >> 32);
else
return booths_multiplication32_opt(rm, rs, rd & 0xFFFFFFFF);
}
// also for SMLALS
inline bool SMULLSCarry(u64 rd, s32 rm, s32 rs, bool lastcycle)
{
if (lastcycle)
return booths_multiplication64_opt(rm >> 6, rs >> 26, rd >> 32);
else
return booths_multiplication32_opt(rm, rs, rd & 0xFFFFFFFF);
}
#endif

View file

@ -51,10 +51,10 @@ namespace melonDS
using Platform::Log;
using Platform::LogLevel;
static_assert(offsetof(ARM, CPSR) == ARM_CPSR_offset, "");
/*static_assert(offsetof(ARM, CPSR) == ARM_CPSR_offset, "");
static_assert(offsetof(ARM, Cycles) == ARM_Cycles_offset, "");
static_assert(offsetof(ARM, StopExecution) == ARM_StopExecution_offset, "");
*/
#define JIT_DEBUGPRINT(msg, ...)
//#define JIT_DEBUGPRINT(msg, ...) Platform::Log(Platform::LogLevel::Debug, msg, ## __VA_ARGS__)
@ -586,7 +586,7 @@ void ARMJIT::CompileBlock(ARM* cpu) noexcept
u32 numWriteAddrs = 0, writeAddrsTranslated = 0;
cpu->FillPipeline();
u32 nextInstr[2] = {cpu->NextInstr[0], cpu->NextInstr[1]};
u32 nextInstr[2] = {(u32)cpu->NextInstr[0], (u32)cpu->NextInstr[1]};
u32 nextInstrAddr[2] = {blockAddr, r15};
JIT_DEBUGPRINT("start block %x %08x (%x)\n", blockAddr, cpu->CPSR, localAddr);
@ -644,17 +644,17 @@ void ARMJIT::CompileBlock(ARM* cpu) noexcept
}
else
{
nextInstr[1] = cpuv5->CodeRead32(r15, false);
//nextInstr[1] = cpuv5->CodeRead32(r15, false);
instrs[i].CodeCycles = cpu->CodeCycles;
}
}
else
{
ARMv4* cpuv4 = (ARMv4*)cpu;
if (thumb)
nextInstr[1] = cpuv4->CodeRead16(r15);
else
nextInstr[1] = cpuv4->CodeRead32(r15);
if (thumb);
//nextInstr[1] = cpuv4->CodeRead16(r15);
else;
// nextInstr[1] = cpuv4->CodeRead32(r15);
instrs[i].CodeCycles = cpu->CodeCycles;
}
instrs[i].Info = ARMInstrInfo::Decode(thumb, cpu->Num, instrs[i].Instr, LiteralOptimizations);
@ -722,7 +722,7 @@ void ARMJIT::CompileBlock(ARM* cpu) noexcept
addressRanges[numAddressRanges++] = translatedAddrRounded;
addressMasks[j] |= 1 << ((translatedAddr & 0x1FF) / 16);
JIT_DEBUGPRINT("literal loading %08x %08x %08x %08x\n", literalAddr, translatedAddr, addressMasks[j], addressRanges[j]);
cpu->DataRead32(literalAddr, &literalValues[numLiterals]);
//cpu->DataRead32(literalAddr, &literalValues[numLiterals]);
literalLoadAddrs[numLiterals++] = translatedAddr;
}
}

View file

@ -83,14 +83,14 @@ void Compiler::Comp_JumpTo(u32 addr, bool forceNonConstantCycles)
// doesn't matter if we put garbage in the MSbs there
if (addr & 0x2)
{
cpu9->CodeRead32(addr-2, true);
//cpu9->CodeRead32(addr-2, true);
cycles += cpu9->CodeCycles;
cpu9->CodeRead32(addr+2, false);
//cpu9->CodeRead32(addr+2, false);
cycles += CurCPU->CodeCycles;
}
else
{
cpu9->CodeRead32(addr, true);
//cpu9->CodeRead32(addr, true);
cycles += cpu9->CodeCycles;
}
}
@ -99,9 +99,9 @@ void Compiler::Comp_JumpTo(u32 addr, bool forceNonConstantCycles)
addr &= ~0x3;
newPC = addr+4;
cpu9->CodeRead32(addr, true);
//cpu9->CodeRead32(addr, true);
cycles += cpu9->CodeCycles;
cpu9->CodeRead32(addr+4, false);
//cpu9->CodeRead32(addr+4, false);
cycles += cpu9->CodeCycles;
}

View file

@ -79,18 +79,18 @@ bool Compiler::Comp_MemLoadLiteral(int size, bool signExtend, int rd, u32 addr)
CurCPU->R[15] = R15;
if (size == 32)
{
CurCPU->DataRead32(addr & ~0x3, &val);
//CurCPU->DataRead32(addr & ~0x3, &val);
val = melonDS::ROR(val, (addr & 0x3) << 3);
}
else if (size == 16)
{
CurCPU->DataRead16(addr & ~0x1, &val);
//CurCPU->DataRead16(addr & ~0x1, &val);
if (signExtend)
val = ((s32)val << 16) >> 16;
}
else
{
CurCPU->DataRead8(addr, &val);
// CurCPU->DataRead8(addr, &val);
if (signExtend)
val = ((s32)val << 24) >> 24;
}

View file

@ -72,14 +72,14 @@ void Compiler::Comp_JumpTo(u32 addr, bool forceNonConstantCycles)
// doesn't matter if we put garbage in the MSbs there
if (addr & 0x2)
{
cpu9->CodeRead32(addr-2, true);
//cpu9->CodeRead32(addr-2, true);
cycles += cpu9->CodeCycles;
cpu9->CodeRead32(addr+2, false);
//cpu9->CodeRead32(addr+2, false);
cycles += CurCPU->CodeCycles;
}
else
{
cpu9->CodeRead32(addr, true);
//cpu9->CodeRead32(addr, true);
cycles += cpu9->CodeCycles;
}
}
@ -88,9 +88,9 @@ void Compiler::Comp_JumpTo(u32 addr, bool forceNonConstantCycles)
addr &= ~0x3;
newPC = addr+4;
cpu9->CodeRead32(addr, true);
//cpu9->CodeRead32(addr, true);
cycles += cpu9->CodeCycles;
cpu9->CodeRead32(addr+4, false);
//cpu9->CodeRead32(addr+4, false);
cycles += cpu9->CodeCycles;
}

View file

@ -85,18 +85,18 @@ bool Compiler::Comp_MemLoadLiteral(int size, bool signExtend, int rd, u32 addr)
CurCPU->R[15] = R15;
if (size == 32)
{
CurCPU->DataRead32(addr & ~0x3, &val);
//CurCPU->DataRead32(addr & ~0x3, &val);
val = melonDS::ROR(val, (addr & 0x3) << 3);
}
else if (size == 16)
{
CurCPU->DataRead16(addr & ~0x1, &val);
//CurCPU->DataRead16(addr & ~0x1, &val);
if (signExtend)
val = ((s32)val << 16) >> 16;
}
else
{
CurCPU->DataRead8(addr, &val);
//CurCPU->DataRead8(addr, &val);
if (signExtend)
val = ((s32)val << 24) >> 24;
}

View file

@ -194,6 +194,7 @@ const u32 A_BX = A_BranchAlways | A_Read0 | ak(ak_BX);
const u32 A_BLX_REG = A_BranchAlways | A_Link | A_Read0 | ak(ak_BLX_REG);
const u32 A_UNK = A_BranchAlways | A_Link | ak(ak_UNK);
const u32 A_BKPT = A_BranchAlways | A_Link | ak(ak_UNK);
const u32 A_MSR_IMM = ak(ak_MSR_IMM);
const u32 A_MSR_REG = A_Read0 | ak(ak_MSR_REG);
const u32 A_MRS = A_Write12 | ak(ak_MRS);

View file

@ -130,7 +130,7 @@ INSTRFUNC_PROTO(ARMInstrTable[4096]) =
// 0001 0010 0000
A_MSR_REG, A_BX, A_UNK, A_BLX_REG,
A_UNK, A_QSUB, A_UNK, A_UNK,
A_UNK, A_QSUB, A_UNK, A_BKPT,
A_SMLAWy, A_UNK, A_SMULWy, A_STRH_REG,
A_SMLAWy, A_LDRD_REG, A_SMULWy, A_STRD_REG,

File diff suppressed because it is too large Load diff

170
src/CP15_Constants.h Normal file
View file

@ -0,0 +1,170 @@
/*
Copyright 2016-2023 melonDS team
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/.
*/
#ifndef MELONDS_CP15CONSTANTS_H
#define MELONDS_CP15CONSTANTS_H
#include "types.h"
namespace melonDS
{
/* ICACHE Layout constants */
constexpr u32 ICACHE_SIZE_LOG2 = 13;
constexpr u32 ICACHE_SIZE = 1 << ICACHE_SIZE_LOG2;
constexpr u32 ICACHE_SETS_LOG2 = 2;
constexpr u32 ICACHE_SETS = 1 << ICACHE_SETS_LOG2;
constexpr u32 ICACHE_LINELENGTH_ENCODED = 2;
constexpr u32 ICACHE_LINELENGTH_LOG2 = ICACHE_LINELENGTH_ENCODED + 3;
constexpr u32 ICACHE_LINELENGTH = 8 * (1 << ICACHE_LINELENGTH_ENCODED);
constexpr u32 ICACHE_LINESPERSET = ICACHE_SIZE / (ICACHE_SETS * ICACHE_LINELENGTH);
/* DCACHE Layout constants */
constexpr u32 DCACHE_SIZE_LOG2 = 12;
constexpr u32 DCACHE_SIZE = 1 << DCACHE_SIZE_LOG2;
constexpr u32 DCACHE_SETS_LOG2 = 2;
constexpr u32 DCACHE_SETS = 1 << DCACHE_SETS_LOG2;
constexpr u32 DCACHE_LINELENGTH_ENCODED = 2;
constexpr u32 DCACHE_LINELENGTH_LOG2 = DCACHE_LINELENGTH_ENCODED + 3;
constexpr u32 DCACHE_LINELENGTH = 8 * (1 << DCACHE_LINELENGTH_ENCODED);
constexpr u32 DCACHE_LINESPERSET = DCACHE_SIZE / (DCACHE_SETS * DCACHE_LINELENGTH);
/* CP15 Cache Data TAGs */
constexpr u32 CACHE_FLAG_VALID = (1 << 4);
constexpr u32 CACHE_FLAG_DIRTY_LOWERHALF = (1 << 2);
constexpr u32 CACHE_FLAG_DIRTY_UPPERHALF = (1 << 3);
constexpr u32 CACHE_FLAG_DIRTY_MASK = (3 << 2);
constexpr u32 CACHE_FLAG_SET_MASK = (3 << 0);
constexpr u32 CACHE_FLAG_MASK = 0x1F;
/* CP15 Cache Type Register */
constexpr u32 CACHE_TR_LOCKDOWN_TYPE_B = (7 << 25);
constexpr u32 CACHE_TR_NONUNIFIED = (1 << 24);
/* CP15 I/DCache LockDown registers */
constexpr u32 CACHE_LOCKUP_L = (1 << 31);
/* CP15 Main ID register */
constexpr u32 CP15_MAINID_IMPLEMENTOR_ARM = (0x41 << 24);
constexpr u32 CP15_MAINID_IMPLEMENTOR_DEC = (0x44 << 24);
constexpr u32 CP15_MAINID_IMPLEMENTOR_MOTOROLA = (0x4D << 24);
constexpr u32 CP15_MAINID_IMPLEMENTOR_MARVELL = (0x56 << 24);
constexpr u32 CP15_MAINID_IMPLEMENTOR_INTEL = (0x69 << 24);
constexpr u32 CP15_MAINID_VARIANT_0 = (0 << 20);
constexpr u32 CP15_MAINID_ARCH_v4 = (1 << 16);
constexpr u32 CP15_MAINID_ARCH_v4T = (2 << 16);
constexpr u32 CP15_MAINID_ARCH_v5 = (3 << 16);
constexpr u32 CP15_MAINID_ARCH_v5T = (4 << 16);
constexpr u32 CP15_MAINID_ARCH_v5TE = (5 << 16);
constexpr u32 CP15_MAINID_ARCH_v5TEJ = (6 << 16);
constexpr u32 CP15_MAINID_ARCH_v6 = (7 << 16);
constexpr u32 CP15_MAINID_IMPLEMENTATION_946 = (0x946 << 4);
constexpr u32 CP15_MAINID_REVISION_0 = (0 << 0);
constexpr u32 CP15_MAINID_REVISION_1 = (1 << 0);
/* CP15 TCM Size Register */
constexpr u32 CP15_TCMSIZE_DTCM_16KB = (5 << 18);
constexpr u32 CP15_TCMSIZE_ITCM_32KB = (6 << 6);
/* CP15 Cache and Write Buffer Conrol Register */
constexpr u32 CP15_CACHE_CR_ROUNDROBIN = (1 << 14);
constexpr u32 CP15_CACHE_CR_ICACHEENABLE = (1 << 12);
constexpr u32 CP15_CACHE_CR_DCACHEENABLE = (1 << 2);
constexpr u32 CP15_CACHE_CR_WRITEBUFFERENABLE = (1 << 3);
/* CP15 TCM Control Register */
constexpr u32 CP15_TCM_CR_DTCM_ENABLE = (1 << 16);
constexpr u32 CP15_TCM_CR_ITCM_ENABLE = (1 << 18);
constexpr u32 CP15_TCM_CR_DTCM_LOADMODE = (1 << 17); // TODO
constexpr u32 CP15_TCM_CR_ITCM_LOADMODE = (1 << 19); // TODO
/* CP15 DTCM Settings Register */
constexpr u32 CP15_DTCM_SIZE_BASE = 0x200;
constexpr u32 CP15_DTCM_SIZE_MASK = 0x3E;
constexpr u32 CP15_DTCM_SIZE_POS = 1;
constexpr u32 CP15_DTCM_SIZE_MIN = 0b00011;
constexpr u32 CP15_DTCM_SIZE_MAX = 0b10111;
constexpr u32 CP15_DTCM_BASE_MASK = 0xFFFFF000;
/* CP15 ITCM Settings Register */
constexpr u32 CP15_ITCM_SIZE_BASE = 0x200;
constexpr u32 CP15_ITCM_SIZE_MASK = 0x3E;
constexpr u32 CP15_ITCM_SIZE_POS = 1;
constexpr u32 CP15_ITCM_SIZE_MIN = 0b00011;
constexpr u32 CP15_ITCM_SIZE_MAX = 0b10111;
constexpr u32 CP15_ITCM_BASE_MASK = 0x00000000;
/* CP15 Control Register */
constexpr u32 CP15_CR_MPUENABLE = (1 << 0);
constexpr u32 CP15_CR_BIGENDIAN = (1 << 7);
constexpr u32 CP15_CR_HIGHEXCEPTIONBASE = (1 << 13);
constexpr u32 CP15_CR_DISABLE_THUMBBIT = (1 << 15);
constexpr u32 CP15_CR_CHANGEABLE_MASK = CP15_CR_MPUENABLE | CP15_CR_BIGENDIAN | CP15_CACHE_CR_DCACHEENABLE
| CP15_CACHE_CR_ICACHEENABLE | CP15_CR_HIGHEXCEPTIONBASE
| CP15_TCM_CR_DTCM_ENABLE | CP15_TCM_CR_ITCM_ENABLE
| CP15_TCM_CR_DTCM_LOADMODE | CP15_TCM_CR_ITCM_LOADMODE
| CP15_CACHE_CR_ROUNDROBIN | CP15_CR_DISABLE_THUMBBIT;
/* Note: ARM946E-S Technical reference manual, Chapter 6.5.2 "You cannot directly enable or disable the write buffer"
CP15_CACHE_CR_WRITEBUFFERENABLE is always set on the cp15
*/
/* CP15 Internal Exception base value */
constexpr u32 CP15_EXCEPTIONBASE_HIGH = 0xFFFF0000;
constexpr u32 CP15_EXCEPTIONBASE_LOW = 0x00000000;
/* CP15 BIST Test State register */
constexpr u32 CP15_BIST_TR_DISABLE_ICACHE_STREAMING = (1 << 11);
constexpr u32 CP15_BIST_TR_DISABLE_DCACHE_STREAMING = (1 << 12);
constexpr u32 CP15_BIST_TR_DISABLE_ICACHE_LINEFILL = (1 << 9);
constexpr u32 CP15_BIST_TR_DISABLE_DCACHE_LINEFILL = (1 << 10);
/* CP15 Region Base and Size Register */
constexpr u32 CP15_REGION_COUNT = 8;
constexpr u32 CP15_REGION_ENABLE = (1 << 0);
constexpr u32 CP15_REGION_SIZE_MASK = (0x1F << 1);
constexpr u32 CP15_REGION_BASE_GRANULARITY_LOG2 = 12;
constexpr u32 CP15_REGION_BASE_GRANULARITY = (1 << CP15_REGION_BASE_GRANULARITY_LOG2);
constexpr u32 CP15_REGION_BASE_MASK = ~(CP15_REGION_BASE_GRANULARITY_LOG2-1);
/* CP15 Region access mask registers */
constexpr u32 CP15_REGIONACCESS_BITS_PER_REGION = 4;
constexpr u32 CP15_REGIONACCESS_REGIONMASK = (1 << CP15_REGIONACCESS_BITS_PER_REGION) - 1;
/* Flags in the melonDS internal PU_PrivMap and PU_UserMap */
constexpr u32 CP15_MAP_NOACCESS = 0x00;
constexpr u32 CP15_MAP_READABLE = 0x01;
constexpr u32 CP15_MAP_WRITEABLE = 0x02;
constexpr u32 CP15_MAP_EXECUTABLE = 0x04;
constexpr u32 CP15_MAP_DCACHEABLE = 0x10;
constexpr u32 CP15_MAP_BUFFERABLE = 0x20;
constexpr u32 CP15_MAP_ICACHEABLE = 0x40;
constexpr u32 CP15_MAP_ENTRYSIZE_LOG2 = CP15_REGION_BASE_GRANULARITY_LOG2;
constexpr u32 CP15_MAP_ENTRYSIZE = (1 << CP15_MAP_ENTRYSIZE_LOG2);
constexpr u32 CP15_MAP_ENTRYCOUNT = 1 << (32 - CP15_MAP_ENTRYSIZE_LOG2);
/* Internal Timing Constants */
constexpr u32 BUSCYCLES_N16 = 0;
constexpr u32 BUSCYCLES_S16 = 1;
constexpr u32 BUSCYCLES_N32 = 2;
constexpr u32 BUSCYCLES_S32 = 3;
constexpr u32 BUSCYCLES_MAP_GRANULARITY_LOG2 = CP15_REGION_BASE_GRANULARITY_LOG2;
}
#endif // MELONDS_CP15CONSTANTS_H

View file

@ -21,6 +21,7 @@
#include "DSi.h"
#include "DMA.h"
#include "GPU.h"
#include "ARM.h"
#include "GPU3D.h"
#include "DMA_Timings.h"
#include "Platform.h"
@ -80,6 +81,7 @@ void DMA::Reset()
Running = false;
Executing = false;
InProgress = false;
DMAQueued = false;
MRAMBurstCount = 0;
MRAMBurstTable = DMATiming::MRAMDummy;
}
@ -108,6 +110,7 @@ void DMA::DoSavestate(Savestate* file)
file->Var32(&MRAMBurstCount);
file->Bool32(&Executing);
file->Bool32(&Stall);
file->Bool32(&DMAQueued);
file->VarArray(MRAMBurstTable.data(), sizeof(MRAMBurstTable));
}
@ -137,14 +140,17 @@ void DMA::WriteCnt(u32 val)
case 0x01000000: SrcAddrInc = 0; break;
case 0x01800000: SrcAddrInc = 1; break;
}
u32 oldstartmode = StartMode;
if (CPU == 0)
StartMode = (Cnt >> 27) & 0x7;
else
StartMode = ((Cnt >> 28) & 0x3) | 0x10;
if ((StartMode & 0x7) == 0)
Start();
{
NDS.DMAsQueued[NDS.DMAQueuePtr++] = (CPU*4)+Num;
if (!(NDS.SchedListMask & (1<<Event_DMA))) NDS.ScheduleEvent(Event_DMA, false, 1, 0, 0);
}
else if (StartMode == 0x07)
NDS.GPU.GPU3D.CheckFIFODMA();
@ -155,7 +161,22 @@ void DMA::WriteCnt(u32 val)
void DMA::Start()
{
if (Running) return;
if (Running)
{
if (CPU ? StartMode == 0x12 : StartMode == 0x05)
{
DMAQueued = true;
}
else
{
DMAQueued = false;
}
return;
}
else
{
DMAQueued = false;
}
if (!InProgress)
{
@ -187,16 +208,27 @@ void DMA::Start()
// TODO eventually: not stop if we're running code in ITCM
Running = 2;
Running = 3;
// safety measure
MRAMBurstTable = DMATiming::MRAMDummy;
InProgress = true;
NDS.StopCPU(CPU, 1<<Num);
if (CPU == 0)
{
u64 ts = NDS.SysTimestamp << NDS.ARM9ClockShift;
if (NDS.DMA9Timestamp < ts) NDS.DMA9Timestamp = ts;
}
if (Num == 0) NDS.DMAs[(CPU*4)+1].ResetBurst();
if (Num <= 1) NDS.DMAs[(CPU*4)+2].ResetBurst();
if (Num <= 2) NDS.DMAs[(CPU*4)+3].ResetBurst();
}
u32 DMA::UnitTimings9_16(bool burststart)
u32 DMA::UnitTimings9_16(int burststart)
{
u32 src_id = CurSrcAddr >> 14;
u32 dst_id = CurDstAddr >> 14;
@ -209,80 +241,24 @@ u32 DMA::UnitTimings9_16(bool burststart)
src_s = NDS.ARM9MemTimings[src_id][5];
dst_n = NDS.ARM9MemTimings[dst_id][4];
dst_s = NDS.ARM9MemTimings[dst_id][5];
if (src_rgn == Mem9_MainRAM)
if (src_rgn & dst_rgn)
{
if (dst_rgn == Mem9_MainRAM)
return 16;
if (SrcAddrInc > 0)
{
if (burststart || MRAMBurstTable[MRAMBurstCount] == 0)
{
MRAMBurstCount = 0;
if (dst_rgn == Mem9_GBAROM)
{
if (dst_s == 4)
MRAMBurstTable = DMATiming::MRAMRead16Bursts[1];
else
MRAMBurstTable = DMATiming::MRAMRead16Bursts[2];
}
else
MRAMBurstTable = DMATiming::MRAMRead16Bursts[0];
}
u32 ret = MRAMBurstTable[MRAMBurstCount++];
return ret;
}
if (burststart != 1)
return src_n + dst_n + (src_n == 1 || burststart <= 0);
else
{
// TODO: not quite right for GBA slot
return (((CurSrcAddr & 0x1F) == 0x1E) ? 7 : 8) +
(burststart ? dst_n : dst_s);
}
}
else if (dst_rgn == Mem9_MainRAM)
{
if (DstAddrInc > 0)
{
if (burststart || MRAMBurstTable[MRAMBurstCount] == 0)
{
MRAMBurstCount = 0;
if (src_rgn == Mem9_GBAROM)
{
if (src_s == 4)
MRAMBurstTable = DMATiming::MRAMWrite16Bursts[1];
else
MRAMBurstTable = DMATiming::MRAMWrite16Bursts[2];
}
else
MRAMBurstTable = DMATiming::MRAMWrite16Bursts[0];
}
u32 ret = MRAMBurstTable[MRAMBurstCount++];
return ret;
}
else
{
return (burststart ? src_n : src_s) + 7;
}
}
else if (src_rgn & dst_rgn)
{
return src_n + dst_n + 1;
return src_n + dst_n + (src_n != 1);
}
else
{
if (burststart)
return src_n + dst_n;
if (burststart == 2)
return src_n + dst_n + (src_n == 1);
else
return src_s + dst_s;
}
}
u32 DMA::UnitTimings9_32(bool burststart)
u32 DMA::UnitTimings9_32(int burststart)
{
u32 src_id = CurSrcAddr >> 14;
u32 dst_id = CurDstAddr >> 14;
@ -296,77 +272,17 @@ u32 DMA::UnitTimings9_32(bool burststart)
dst_n = NDS.ARM9MemTimings[dst_id][6];
dst_s = NDS.ARM9MemTimings[dst_id][7];
if (src_rgn == Mem9_MainRAM)
if (src_rgn & dst_rgn)
{
if (dst_rgn == Mem9_MainRAM)
return 18;
if (SrcAddrInc > 0)
{
if (burststart || MRAMBurstTable[MRAMBurstCount] == 0)
{
MRAMBurstCount = 0;
if (dst_rgn == Mem9_GBAROM)
{
if (dst_s == 8)
MRAMBurstTable = DMATiming::MRAMRead32Bursts[2];
else
MRAMBurstTable = DMATiming::MRAMRead32Bursts[3];
}
else if (dst_n == 2)
MRAMBurstTable = DMATiming::MRAMRead32Bursts[0];
else
MRAMBurstTable = DMATiming::MRAMRead32Bursts[1];
}
u32 ret = MRAMBurstTable[MRAMBurstCount++];
return ret;
}
if (burststart != 1)
return src_n + dst_n + (src_n == 1 || burststart <= 0);
else
{
// TODO: not quite right for GBA slot
return (((CurSrcAddr & 0x1F) == 0x1C) ? (dst_n==2 ? 7:8) : 9) +
(burststart ? dst_n : dst_s);
}
}
else if (dst_rgn == Mem9_MainRAM)
{
if (DstAddrInc > 0)
{
if (burststart || MRAMBurstTable[MRAMBurstCount] == 0)
{
MRAMBurstCount = 0;
if (src_rgn == Mem9_GBAROM)
{
if (src_s == 8)
MRAMBurstTable = DMATiming::MRAMWrite32Bursts[2];
else
MRAMBurstTable = DMATiming::MRAMWrite32Bursts[3];
}
else if (src_n == 2)
MRAMBurstTable = DMATiming::MRAMWrite32Bursts[0];
else
MRAMBurstTable = DMATiming::MRAMWrite32Bursts[1];
}
u32 ret = MRAMBurstTable[MRAMBurstCount++];
return ret;
}
else
{
return (burststart ? src_n : src_s) + 8;
}
}
else if (src_rgn & dst_rgn)
{
return src_n + dst_n + 1;
return src_n + dst_n + (src_n != 1);
}
else
{
if (burststart)
return src_n + dst_n;
if (burststart == 2)
return src_n + dst_n + (src_n == 1);
else
return src_s + dst_s;
}
@ -374,7 +290,7 @@ u32 DMA::UnitTimings9_32(bool burststart)
// TODO: the ARM7 ones don't take into account that the two wifi regions have different timings
u32 DMA::UnitTimings7_16(bool burststart)
u32 DMA::UnitTimings7_16(int burststart)
{
u32 src_id = CurSrcAddr >> 15;
u32 dst_id = CurDstAddr >> 15;
@ -388,79 +304,23 @@ u32 DMA::UnitTimings7_16(bool burststart)
dst_n = NDS.ARM7MemTimings[dst_id][0];
dst_s = NDS.ARM7MemTimings[dst_id][1];
if (src_rgn == Mem7_MainRAM)
if (src_rgn & dst_rgn)
{
if (dst_rgn == Mem7_MainRAM)
return 16;
if (SrcAddrInc > 0)
{
if (burststart || MRAMBurstTable[MRAMBurstCount] == 0)
{
MRAMBurstCount = 0;
if (dst_rgn == Mem7_GBAROM || dst_rgn == Mem7_Wifi0 || dst_rgn == Mem7_Wifi1)
{
if (dst_s == 4)
MRAMBurstTable = DMATiming::MRAMRead16Bursts[1];
else
MRAMBurstTable = DMATiming::MRAMRead16Bursts[2];
}
else
MRAMBurstTable = DMATiming::MRAMRead16Bursts[0];
}
u32 ret = MRAMBurstTable[MRAMBurstCount++];
return ret;
}
if (burststart != 1)
return src_n + dst_n + (src_n == 1 || burststart <= 0);
else
{
// TODO: not quite right for GBA slot
return (((CurSrcAddr & 0x1F) == 0x1E) ? 7 : 8) +
(burststart ? dst_n : dst_s);
}
}
else if (dst_rgn == Mem7_MainRAM)
{
if (DstAddrInc > 0)
{
if (burststart || MRAMBurstTable[MRAMBurstCount] == 0)
{
MRAMBurstCount = 0;
if (src_rgn == Mem7_GBAROM || src_rgn == Mem7_Wifi0 || src_rgn == Mem7_Wifi1)
{
if (src_s == 4)
MRAMBurstTable = DMATiming::MRAMWrite16Bursts[1];
else
MRAMBurstTable = DMATiming::MRAMWrite16Bursts[2];
}
else
MRAMBurstTable = DMATiming::MRAMWrite16Bursts[0];
}
u32 ret = MRAMBurstTable[MRAMBurstCount++];
return ret;
}
else
{
return (burststart ? src_n : src_s) + 7;
}
}
else if (src_rgn & dst_rgn)
{
return src_n + dst_n + 1;
return src_n + dst_n + (src_n != 1);
}
else
{
if (burststart)
return src_n + dst_n;
if (burststart == 2)
return src_n + dst_n + (src_n == 1);
else
return src_s + dst_s;
}
}
u32 DMA::UnitTimings7_32(bool burststart)
u32 DMA::UnitTimings7_32(int burststart)
{
u32 src_id = CurSrcAddr >> 15;
u32 dst_id = CurDstAddr >> 15;
@ -474,77 +334,17 @@ u32 DMA::UnitTimings7_32(bool burststart)
dst_n = NDS.ARM7MemTimings[dst_id][2];
dst_s = NDS.ARM7MemTimings[dst_id][3];
if (src_rgn == Mem7_MainRAM)
if (src_rgn & dst_rgn)
{
if (dst_rgn == Mem7_MainRAM)
return 18;
if (SrcAddrInc > 0)
{
if (burststart || MRAMBurstTable[MRAMBurstCount] == 0)
{
MRAMBurstCount = 0;
if (dst_rgn == Mem7_GBAROM || dst_rgn == Mem7_Wifi0 || dst_rgn == Mem7_Wifi1)
{
if (dst_s == 8)
MRAMBurstTable = DMATiming::MRAMRead32Bursts[2];
else
MRAMBurstTable = DMATiming::MRAMRead32Bursts[3];
}
else if (dst_n == 2)
MRAMBurstTable = DMATiming::MRAMRead32Bursts[0];
else
MRAMBurstTable = DMATiming::MRAMRead32Bursts[1];
}
u32 ret = MRAMBurstTable[MRAMBurstCount++];
return ret;
}
if (burststart != 1)
return src_n + dst_n + (src_n == 1 || burststart <= 0);
else
{
// TODO: not quite right for GBA slot
return (((CurSrcAddr & 0x1F) == 0x1C) ? (dst_n==2 ? 7:8) : 9) +
(burststart ? dst_n : dst_s);
}
}
else if (dst_rgn == Mem7_MainRAM)
{
if (DstAddrInc > 0)
{
if (burststart || MRAMBurstTable[MRAMBurstCount] == 0)
{
MRAMBurstCount = 0;
if (src_rgn == Mem7_GBAROM || src_rgn == Mem7_Wifi0 || src_rgn == Mem7_Wifi1)
{
if (src_s == 8)
MRAMBurstTable = DMATiming::MRAMWrite32Bursts[2];
else
MRAMBurstTable = DMATiming::MRAMWrite32Bursts[3];
}
else if (src_n == 2)
MRAMBurstTable = DMATiming::MRAMWrite32Bursts[0];
else
MRAMBurstTable = DMATiming::MRAMWrite32Bursts[1];
}
u32 ret = MRAMBurstTable[MRAMBurstCount++];
return ret;
}
else
{
return (burststart ? src_n : src_s) + 8;
}
}
else if (src_rgn & dst_rgn)
{
return src_n + dst_n + 1;
return src_n + dst_n + (src_n != 1);
}
else
{
if (burststart)
return src_n + dst_n;
if (burststart == 2)
return src_n + dst_n + (src_n == 1);
else
return src_s + dst_s;
}
@ -552,20 +352,30 @@ u32 DMA::UnitTimings7_32(bool burststart)
void DMA::Run9()
{
if (NDS.ARM9Timestamp >= NDS.ARM9Target) return;
//NDS.DMA9Timestamp = std::max(NDS.DMA9Timestamp, NDS.SysTimestamp << NDS.ARM9ClockShift);
//NDS.DMA9Timestamp = (NDS.DMA9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1);
if (NDS.DMA9Timestamp >= NDS.ARM9Target) return;
Executing = true;
// add NS penalty for first accesses in burst
bool burststart = (Running == 2);
Running = 1;
int burststart = Running-1;
if (!(Cnt & (1<<26)))
{
while (IterCount > 0 && !Stall)
{
NDS.ARM9Timestamp += (UnitTimings9_16(burststart) << NDS.ARM9ClockShift);
burststart = false;
u32 rgn = NDS.ARM9Regions[CurSrcAddr>>14] | NDS.ARM9Regions[CurDstAddr>>14];
if (rgn & Mem9_MainRAM)
{
NDS.ARM9.MRTrack.Type = MainRAMType::DMA16;
NDS.ARM9.MRTrack.Var = Num;
return;
}
NDS.DMA9Timestamp += (UnitTimings9_16(burststart) << NDS.ARM9ClockShift);
burststart -= 1;
NDS.ARM9Write16(CurDstAddr, NDS.ARM9Read16(CurSrcAddr));
@ -574,15 +384,23 @@ void DMA::Run9()
IterCount--;
RemCount--;
if (NDS.ARM9Timestamp >= NDS.ARM9Target) break;
if (NDS.DMA9Timestamp >= NDS.ARM9Target) break;
}
}
else
{
while (IterCount > 0 && !Stall)
{
NDS.ARM9Timestamp += (UnitTimings9_32(burststart) << NDS.ARM9ClockShift);
burststart = false;
u32 rgn = NDS.ARM9Regions[CurSrcAddr>>14] | NDS.ARM9Regions[CurDstAddr>>14];
if (rgn & Mem9_MainRAM)
{
NDS.ARM9.MRTrack.Type = MainRAMType::DMA32;
NDS.ARM9.MRTrack.Var = Num;
return;
}
NDS.DMA9Timestamp += (UnitTimings9_32(burststart) << NDS.ARM9ClockShift);
burststart -= 1;
NDS.ARM9Write32(CurDstAddr, NDS.ARM9Read32(CurSrcAddr));
@ -591,10 +409,15 @@ void DMA::Run9()
IterCount--;
RemCount--;
if (NDS.ARM9Timestamp >= NDS.ARM9Target) break;
if (NDS.DMA9Timestamp >= NDS.ARM9Target) break;
}
}
NDS.DMA9Timestamp -= 1;
if (burststart <= 0) Running = 1;
else Running = 2;
Executing = false;
Stall = false;
@ -621,6 +444,8 @@ void DMA::Run9()
Running = 0;
InProgress = false;
NDS.ResumeCPU(0, 1<<Num);
if (DMAQueued) Start();
}
void DMA::Run7()
@ -630,13 +455,20 @@ void DMA::Run7()
Executing = true;
// add NS penalty for first accesses in burst
bool burststart = (Running == 2);
Running = 1;
int burststart = Running - 1;
if (!(Cnt & (1<<26)))
{
while (IterCount > 0 && !Stall)
{
u32 rgn = NDS.ARM7Regions[CurSrcAddr>>15] | NDS.ARM7Regions[CurDstAddr>>15];
if (rgn & Mem7_MainRAM)
{
NDS.ARM7.MRTrack.Type = MainRAMType::DMA16;
NDS.ARM7.MRTrack.Var = Num+4;
return;
}
NDS.ARM7Timestamp += UnitTimings7_16(burststart);
burststart = false;
@ -654,6 +486,14 @@ void DMA::Run7()
{
while (IterCount > 0 && !Stall)
{
u32 rgn = NDS.ARM7Regions[CurSrcAddr>>15] | NDS.ARM7Regions[CurDstAddr>>15];
if (rgn & Mem7_MainRAM)
{
NDS.ARM7.MRTrack.Type = MainRAMType::DMA32;
NDS.ARM7.MRTrack.Var = Num+4;
return;
}
NDS.ARM7Timestamp += UnitTimings7_32(burststart);
burststart = false;
@ -668,6 +508,9 @@ void DMA::Run7()
}
}
if (burststart <= 0) Running = 1;
else Running = 2;
Executing = false;
Stall = false;
@ -691,6 +534,8 @@ void DMA::Run7()
Running = 0;
InProgress = false;
NDS.ResumeCPU(1, 1<<Num);
if (DMAQueued) Start();
}
void DMA::Run()

View file

@ -40,10 +40,10 @@ public:
void WriteCnt(u32 val);
void Start();
u32 UnitTimings9_16(bool burststart);
u32 UnitTimings9_32(bool burststart);
u32 UnitTimings7_16(bool burststart);
u32 UnitTimings7_32(bool burststart);
u32 UnitTimings9_16(int burststart);
u32 UnitTimings9_32(int burststart);
u32 UnitTimings7_16(int burststart);
u32 UnitTimings7_32(int burststart);
void Run();
void Run9();
@ -73,30 +73,34 @@ public:
if (Executing) Stall = true;
}
void ResetBurst()
{
if (Running > 0) Running = 3;
}
u32 SrcAddr {};
u32 DstAddr {};
u32 Cnt {};
private:
melonDS::NDS& NDS;
u32 CPU {};
u32 Num {};
u32 StartMode {};
u32 CurSrcAddr {};
u32 CurDstAddr {};
u32 RemCount {};
u32 IterCount {};
s32 SrcAddrInc {};
s32 DstAddrInc {};
u32 CountMask {};
u32 Running {};
bool InProgress {};
u32 Num {};
u32 StartMode {};
bool Executing {};
bool Stall {};
private:
melonDS::NDS& NDS;
u32 CPU {};
bool DMAQueued;
u32 CountMask {};
bool IsGXFIFODMA {};
u32 MRAMBurstCount {};

View file

@ -48,7 +48,7 @@ extern const std::array<u8, 256> MRAMDummy = {0};
extern const std::array<u8, 256> MRAMRead16Bursts[] =
{
// main RAM to regular 16bit or 32bit bus (similar)
{7, 3, 2, 2, 2, 2, 2, 2, 2, 2,
{6, 3, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@ -60,7 +60,7 @@ extern const std::array<u8, 256> MRAMRead16Bursts[] =
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2,
7, 3, 2, 2, 2, 2, 2, 2, 2, 2,
6, 3, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@ -72,7 +72,7 @@ extern const std::array<u8, 256> MRAMRead16Bursts[] =
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2,
7, 3,
6, 3,
0},
// main RAM to GBA/wifi, seq=4
{8, 6, 5, 5, 5, 5, 5, 5, 5, 5,
@ -181,7 +181,7 @@ extern const std::array<u8, 256> MRAMRead32Bursts[] =
extern const std::array<u8, 256> MRAMWrite16Bursts[] =
{
// regular 16bit or 32bit bus to main RAM (similar)
{8, 2, 2, 2, 2, 2, 2, 2, 2, 2,
{5, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@ -212,7 +212,7 @@ extern const std::array<u8, 256> MRAMWrite16Bursts[] =
extern const std::array<u8, 256> MRAMWrite32Bursts[4] =
{
// regular 16bit bus to main RAM
{9, 4, 4, 4, 4, 4, 4, 4, 4, 4,
{6, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
@ -220,7 +220,7 @@ extern const std::array<u8, 256> MRAMWrite32Bursts[4] =
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
0},
// regular 32bit bus to main RAM
{9, 3, 3, 3, 3, 3, 3, 3, 3, 3,
{6, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,

View file

@ -129,6 +129,9 @@ void DSi::Reset()
//ARM9.CP15Write(0x911, 0x00000020);
//ARM9.CP15Write(0x100, ARM9.CP15Read(0x100) | 0x00050000);
NDS::Reset();
ExMemCnt[0] = 0xEC8C; // checkme: bit 10 should be explicitly set?
ExMemCnt[1] = 0xEC8C;
// The SOUNDBIAS register does nothing on DSi
SPU.SetApplyBias(false);
@ -160,6 +163,7 @@ void DSi::Reset()
SCFG_Clock9 = 0x0187; // CHECKME
SCFG_Clock7 = 0x0187;
SCFG_EXT[0] = 0x8307F100;
SetVRAMTimings(true);
SCFG_EXT[1] = 0x93FFFB06;
SCFG_MC = 0x0010 | (~((u32)(NDSCartSlot.GetCart() != nullptr))&1);//0x0011;
SCFG_RST = 0;
@ -233,6 +237,7 @@ void DSi::DoSavestateExtra(Savestate* file)
Set_SCFG_Clock9(SCFG_Clock9);
Set_SCFG_MC(SCFG_MC);
DSP.SetRstLine(SCFG_RST & 0x0001);
SetVRAMTimings(SCFG_EXT[0] & (1<<13));
MBK[0][8] = 0;
MBK[1][8] = 0;
@ -711,6 +716,7 @@ void DSi::SoftReset()
SCFG_Clock9 = 0x0187; // CHECKME
SCFG_Clock7 = 0x0187;
SCFG_EXT[0] = 0x8307F100;
SetVRAMTimings(true);
SCFG_EXT[1] = 0x93FFFB06;
SCFG_MC = 0x0010;//0x0011;
// TODO: is this actually reset?
@ -1273,7 +1279,22 @@ void DSi::ApplyNewRAMSize(u32 size)
void DSi::Set_SCFG_Clock9(u16 val)
{
ARM9Timestamp >>= ARM9ClockShift;
DMA9Timestamp >>= ARM9ClockShift;
ARM9Target >>= ARM9ClockShift;
for (int i = 0; i < 7; i++)
{
ARM9.ICacheStreamTimes[i] >>= ARM9ClockShift;
ARM9.DCacheStreamTimes[i] >>= ARM9ClockShift;
}
ARM9.TimestampMemory >>= ARM9ClockShift;
ARM9.ITCMTimestamp >>= ARM9ClockShift;
ARM9.IRQTimestamp >>= ARM9ClockShift;
ARM9.WBTimestamp >>= ARM9ClockShift;
ARM9.WBDelay >>= ARM9ClockShift;
ARM9.WBReleaseTS >>= ARM9ClockShift;
ARM9.WBInitialTS >>= ARM9ClockShift;
ARM9.ILCurrTime >>= ARM9ClockShift;
ARM9.ILPrevTime >>= ARM9ClockShift;
Log(LogLevel::Debug, "CLOCK9=%04X\n", val);
SCFG_Clock9 = val & 0x0187;
@ -1282,8 +1303,24 @@ void DSi::Set_SCFG_Clock9(u16 val)
else ARM9ClockShift = 1;
ARM9Timestamp <<= ARM9ClockShift;
DMA9Timestamp <<= ARM9ClockShift;
ARM9Target <<= ARM9ClockShift;
ARM9.UpdateRegionTimings(0x00000, 0x100000);
for (int i = 0; i < 7; i++)
{
ARM9.ICacheStreamTimes[i] <<= ARM9ClockShift;
ARM9.DCacheStreamTimes[i] <<= ARM9ClockShift;
}
ARM9.TimestampMemory <<= ARM9ClockShift;
ARM9.ITCMTimestamp <<= ARM9ClockShift;
ARM9.IRQTimestamp <<= ARM9ClockShift;
ARM9.WBTimestamp <<= ARM9ClockShift;
ARM9.WBDelay <<= ARM9ClockShift;
ARM9.WBReleaseTS <<= ARM9ClockShift;
ARM9.WBInitialTS <<= ARM9ClockShift;
ARM9.ILCurrTime <<= ARM9ClockShift;
ARM9.ILPrevTime <<= ARM9ClockShift;
ARM9.UpdateRegionTimings(0x00000, 0x40000);
}
void DSi::Set_SCFG_MC(u32 val)
@ -1301,6 +1338,20 @@ void DSi::Set_SCFG_MC(u32 val)
}
}
void DSi::SetVRAMTimings(bool extrabuswidth)
{
if (extrabuswidth) // 32 bit bus; arm9 can do 8 bit writes
{
SetARM9RegionTimings(0x06000, 0x07000, Mem9_VRAM, 32, 1, 1);
SetARM7RegionTimings(0x06000, 0x07000, Mem7_VRAM, 32, 1, 1);
}
else // 16 bit bus; arm9 cannot do 8 bit writes
{
SetARM9RegionTimings(0x06000, 0x07000, Mem9_VRAM, 16, 1, 1);
SetARM7RegionTimings(0x06000, 0x07000, Mem7_VRAM, 16, 1, 1);
}
}
u8 DSi::ARM9Read8(u32 addr)
{
@ -1723,7 +1774,7 @@ void DSi::ARM9Write32(u32 addr, u32 val)
return NDS::ARM9Write32(addr, val);
}
bool DSi::ARM9GetMemRegion(u32 addr, bool write, MemRegion* region)
bool DSi::ARM9GetMemRegion(const u32 addr, const bool write, MemRegion* region)
{
assert(ConsoleType == 1);
switch (addr & 0xFF000000)
@ -2539,12 +2590,19 @@ void DSi::ARM9IOWrite32(u32 addr, u32 val)
u32 oldram = (SCFG_EXT[0] >> 14) & 0x3;
u32 newram = (val >> 14) & 0x3;
u32 oldvram = (SCFG_EXT[0] & (1<<13));
u32 newvram = (val & (1<<13));
SCFG_EXT[0] &= ~0x8007F19F;
SCFG_EXT[0] |= (val & 0x8007F19F);
SCFG_EXT[1] &= ~0x0000F080;
SCFG_EXT[1] |= (val & 0x0000F080);
Log(LogLevel::Debug, "SCFG_EXT = %08X / %08X (val9 %08X)\n", SCFG_EXT[0], SCFG_EXT[1], val);
/*switch ((SCFG_EXT[0] >> 14) & 0x3)
if (oldvram != newvram)
SetVRAMTimings(newvram);
switch ((SCFG_EXT[0] >> 14) & 0x3)
{
case 0:
case 1:
@ -2557,7 +2615,7 @@ void DSi::ARM9IOWrite32(u32 addr, u32 val)
NDS::MainRAMMask = 0xFFFFFF;
printf("RAM: 16MB\n");
break;
}*/
}
// HAX!!
// a change to the RAM size setting is supposed to apply immediately (it does so on hardware)
// however, doing so will cause DS-mode app startup to break, because the change happens while the ARM7
@ -3069,6 +3127,7 @@ void DSi::ARM7IOWrite32(u32 addr, u32 val)
SCFG_EXT[0] |= (val & 0x03000000);
SCFG_EXT[1] &= ~0x93FF0F07;
SCFG_EXT[1] |= (val & 0x93FF0F07);
if (!(val & (1<<24))) { ExMemCnt[0] &= ~(1<<10); ExMemCnt[1] &= ~(1<<10); } // bit 10 of exmemcnt is cleared when disabling second card slot access
Log(LogLevel::Debug, "SCFG_EXT = %08X / %08X (val7 %08X)\n", SCFG_EXT[0], SCFG_EXT[1], val);
return;
case 0x04004010:

View file

@ -96,6 +96,7 @@ public:
void MapNWRAM_B(u32 num, u8 val);
void MapNWRAM_C(u32 num, u8 val);
void MapNWRAMRange(u32 cpu, u32 num, u32 val);
void SetVRAMTimings(bool extrabuswidth);
u8 ARM9Read8(u32 addr) override;
u16 ARM9Read16(u32 addr) override;
@ -104,7 +105,7 @@ public:
void ARM9Write16(u32 addr, u16 val) override;
void ARM9Write32(u32 addr, u32 val) override;
bool ARM9GetMemRegion(u32 addr, bool write, MemRegion* region) override;
bool ARM9GetMemRegion(const u32 addr, const bool write, MemRegion* region) override;
u8 ARM7Read8(u32 addr) override;
u16 ARM7Read16(u32 addr) override;

View file

@ -2378,13 +2378,13 @@ void GPU3D::Run() noexcept
if (!GeometryEnabled || FlushRequest ||
(CmdPIPE.IsEmpty() && !(GXStat & (1<<27))))
{
Timestamp = NDS.ARM9Timestamp >> NDS.ARM9ClockShift;
Timestamp = std::max(NDS.ARM9Timestamp, NDS.DMA9Timestamp) >> NDS.ARM9ClockShift;
return;
}
s32 cycles = (NDS.ARM9Timestamp >> NDS.ARM9ClockShift) - Timestamp;
s32 cycles = (std::max(NDS.ARM9Timestamp, NDS.DMA9Timestamp) >> NDS.ARM9ClockShift) - Timestamp;
CycleCount -= cycles;
Timestamp = NDS.ARM9Timestamp >> NDS.ARM9ClockShift;
Timestamp = std::max(NDS.ARM9Timestamp, NDS.DMA9Timestamp) >> NDS.ARM9ClockShift;
if (CycleCount <= 0)
{
@ -2417,7 +2417,7 @@ void GPU3D::CheckFIFOIRQ() noexcept
case 2: irq = CmdFIFO.IsEmpty(); break;
}
if (irq) NDS.SetIRQ(0, IRQ_GXFIFO);
if (irq) NDS.SetIRQ(0, IRQ_GXFIFO, CycleCount);
else NDS.ClearIRQ(0, IRQ_GXFIFO);
}

File diff suppressed because it is too large Load diff

View file

@ -64,6 +64,7 @@ enum
Event_SPITransfer,
Event_Div,
Event_Sqrt,
Event_DMA,
// DSi
Event_DSi_SDMMCTransfer,
@ -196,6 +197,8 @@ enum
Mem9_VRAM = 0x00000100,
Mem9_GBAROM = 0x00020000,
Mem9_GBARAM = 0x00040000,
Mem9_DCache = 0x40000000,
Mem9_Null = 0x80000000,
Mem7_BIOS = 0x00000001,
Mem7_MainRAM = 0x00000002,
@ -241,7 +244,8 @@ public: // TODO: Encapsulate the rest of these members
int ConsoleType;
int CurCPU;
u32 SchedListMask;
SchedEvent SchedList[Event_MAX] {};
u8 ARM9MemTimings[0x40000][8];
u32 ARM9Regions[0x40000];
@ -253,8 +257,11 @@ public: // TODO: Encapsulate the rest of these members
bool LagFrameFlag;
// no need to worry about those overflowing, they can keep going for atleast 4350 years
u64 ARM9Timestamp, ARM9Target;
u64 ARM9Timestamp, DMA9Timestamp, ARM9Target;
u64 ARM7Timestamp, ARM7Target;
u64 MainRAMTimestamp, MainRAMBurstStart;
u64 A9ContentionTS; bool ConTSLock;
u64 SysTimestamp;
u32 ARM9ClockShift;
u32 IME[2];
@ -272,11 +279,18 @@ public: // TODO: Encapsulate the rest of these members
alignas(u32) u8 ROMSeed0[2*8];
alignas(u32) u8 ROMSeed1[2*8];
u32 DMAReadHold[2];
u8 DMAsQueued[8];
u8 DMAQueuePtr;
bool MainRAMBork; // if a main ram read burst starts in the last 6 bytes of a 32 byte block, and then crosses the 32 byte boundary, the burst forcibly restarts
bool MainRAMLastAccess; // 0 == ARM9 | 1 == ARM7
bool DMALastWasMainRAM;
protected:
// These BIOS arrays should be declared *before* the component objects (JIT, SPI, etc.)
// so that they're initialized before the component objects' constructors run.
std::array<u8, ARM9BIOSSize> ARM9BIOS;
std::array<u8, ARM7BIOSSize> ARM7BIOS;
alignas(u32) std::array<u8, ARM9BIOSSize> ARM9BIOS;
alignas(u32) std::array<u8, ARM7BIOSSize> ARM7BIOS;
bool ARM9BIOSNative;
bool ARM7BIOSNative;
public: // TODO: Encapsulate the rest of these members
@ -311,6 +325,11 @@ public: // TODO: Encapsulate the rest of these members
GBACart::GBACartSlot GBACartSlot;
melonDS::GPU GPU;
melonDS::AREngine AREngine;
DMA DMAs[8];
#ifdef JIT_ENABLED
bool IsJITEnabled(){return EnableJIT;};
#endif
const u32 ARM7WRAMSize = 0x10000;
u8* ARM7WRAM;
@ -390,6 +409,10 @@ public: // TODO: Encapsulate the rest of these members
std::unique_ptr<GBACart::CartCommon> EjectGBACart() { return GBACartSlot.EjectCart(); }
void MainRAMHandleARM9();
void MainRAMHandleARM7();
bool MainRAMHandle();
u32 RunFrame();
bool IsRunning() const noexcept { return Running; }
@ -409,6 +432,7 @@ public: // TODO: Encapsulate the rest of these members
void UnregisterEventFuncs(u32 id);
void ScheduleEvent(u32 id, bool periodic, s32 delay, u32 funcid, u32 param);
void CancelEvent(u32 id);
void RunEventManual(u32 id);
void debug(u32 p);
@ -416,8 +440,8 @@ public: // TODO: Encapsulate the rest of these members
void MapSharedWRAM(u8 val);
void UpdateIRQ(u32 cpu);
void SetIRQ(u32 cpu, u32 irq);
void UpdateIRQ(u32 cpu, s32 delay = 0);
void SetIRQ(u32 cpu, u32 irq, s32 delay = 0);
void ClearIRQ(u32 cpu, u32 irq);
void SetIRQ2(u32 irq);
void ClearIRQ2(u32 irq);
@ -447,7 +471,7 @@ public: // TODO: Encapsulate the rest of these members
virtual void ARM9Write16(u32 addr, u16 val);
virtual void ARM9Write32(u32 addr, u32 val);
virtual bool ARM9GetMemRegion(u32 addr, bool write, MemRegion* region);
virtual bool ARM9GetMemRegion(const u32 addr, const bool write, MemRegion* region);
virtual u8 ARM7Read8(u32 addr);
virtual u16 ARM7Read16(u32 addr);
@ -488,8 +512,6 @@ public: // TODO: Encapsulate the rest of these members
private:
void InitTimings();
u32 SchedListMask;
u64 SysTimestamp;
u8 WRAMCnt;
u8 PostFlag9;
u8 PostFlag7;
@ -497,7 +519,6 @@ private:
u16 WifiWaitCnt;
u8 TimerCheckMask[2];
u64 TimerTimestamp[2];
DMA DMAs[8];
u32 DMA9Fill[4];
u16 IPCSync9, IPCSync7;
u16 IPCFIFOCnt9, IPCFIFOCnt7;
@ -525,6 +546,7 @@ private:
void HandleTimerOverflow(u32 tid);
u16 TimerGetCounter(u32 timer);
void TimerStart(u32 id, u16 cnt);
void QueueDMAs(u32 param);
void StartDiv();
void DivDone(u32 param);
void SqrtDone(u32 param);

View file

@ -1485,6 +1485,7 @@ void NDSCartSlot::DoSavestate(Savestate* file) noexcept
file->Var32(&TransferLen);
file->Var32(&TransferDir);
file->VarArray(TransferCmd.data(), sizeof(TransferCmd));
file->Var64(&ROMTransferTime);
// cart inserted/len/ROM/etc should be already populated
// savestate should be loaded after the right game is loaded
@ -1799,6 +1800,7 @@ void NDSCartSlot::ResetCart() noexcept
TransferDir = 0;
memset(TransferCmd.data(), 0, sizeof(TransferCmd));
TransferCmd[0] = 0xFF;
ROMTransferTime = -1;
if (Cart) Cart->Reset();
}
@ -1835,6 +1837,12 @@ void NDSCartSlot::ROMPrepareData(u32 param) noexcept
NDS.CheckDMAs(0, 0x05);
}
u32 NDSCartSlot::GetROMCnt() noexcept
{
NDS.RunEventManual(Event_ROMTransfer);
return ROMCnt;
}
void NDSCartSlot::WriteROMCnt(u32 val) noexcept
{
u32 xferstart = (val & ~ROMCnt) & (1<<31);
@ -1902,13 +1910,13 @@ void NDSCartSlot::WriteROMCnt(u32 val) noexcept
// ROM transfer timings
// the bus is parallel with 8 bits
// thus a command would take 8 cycles to be transferred
// and it would take 4 cycles to receive a word of data
// thus a command would take 8 cycles to be transferred (...actually it's 10?? checkme: does this apply to every command?)
// and it would take 4 cycles to receive a word of data (...or 3? does it overlap a cycle somewhere?)
// TODO: advance read position if bit28 is set
// TODO: during a write transfer, bit23 is set immediately when beginning the transfer(?)
u32 xfercycle = (ROMCnt & (1<<27)) ? 8 : 5;
u32 cmddelay = 8;
u32 cmddelay = 10;
// delays are only applied when the WR bit is cleared
// CHECKME: do the delays apply at the end (instead of start) when WR is set?
@ -1919,9 +1927,17 @@ void NDSCartSlot::WriteROMCnt(u32 val) noexcept
}
if (datasize == 0)
NDS.ScheduleEvent(Event_ROMTransfer, false, xfercycle*cmddelay, ROMTransfer_End, 0);
NDS.ScheduleEvent(Event_ROMTransfer, false, xfercycle*cmddelay+4, ROMTransfer_End, 0);
else
NDS.ScheduleEvent(Event_ROMTransfer, false, xfercycle*(cmddelay+4), ROMTransfer_PrepareData, 0);
{
NDS.ScheduleEvent(Event_ROMTransfer, false, xfercycle*(cmddelay+3)+3, ROMTransfer_PrepareData, 0);
u64 curts;
if (NDS.ExMemCnt[0] & (1<<11)) curts = NDS.ARM7Timestamp;
else curts = (std::max(NDS.ARM9Timestamp, NDS.DMA9Timestamp)) >> NDS.ARM9ClockShift;
ROMTransferTime = (xfercycle*(cmddelay+8)) + curts + 3;
}
}
void NDSCartSlot::AdvanceROMTransfer() noexcept
@ -1931,14 +1947,21 @@ void NDSCartSlot::AdvanceROMTransfer() noexcept
if (TransferPos < TransferLen)
{
u32 xfercycle = (ROMCnt & (1<<27)) ? 8 : 5;
u32 extdelay = (ROMCnt & (1<<27)) ? 7 : 5; // why is this only 7...?
u32 delay = 4;
if (!(ROMCnt & (1<<30)))
{
if (!(TransferPos & 0x1FF))
if (!((TransferPos+4) & 0x1FF))
delay += ((ROMCnt >> 16) & 0x3F);
}
u64 curts;
if (NDS.ExMemCnt[0] & (1<<11)) curts = NDS.ARM7Timestamp;
else curts = (std::max(NDS.ARM9Timestamp, NDS.DMA9Timestamp)) >> NDS.ARM9ClockShift;
NDS.ScheduleEvent(Event_ROMTransfer, false, ROMTransferTime-curts, ROMTransfer_PrepareData, 0);
NDS.ScheduleEvent(Event_ROMTransfer, false, xfercycle*delay, ROMTransfer_PrepareData, 0);
ROMTransferTime = (xfercycle*delay) + std::max(curts+extdelay, ROMTransferTime);
}
else
ROMEndTransfer(0);
@ -1947,6 +1970,8 @@ void NDSCartSlot::AdvanceROMTransfer() noexcept
u32 NDSCartSlot::ReadROMData() noexcept
{
if (ROMCnt & (1<<30)) return 0;
NDS.RunEventManual(Event_ROMTransfer);
if (ROMCnt & (1<<23))
{
@ -1959,6 +1984,8 @@ u32 NDSCartSlot::ReadROMData() noexcept
void NDSCartSlot::WriteROMData(u32 val) noexcept
{
if (!(ROMCnt & (1<<30))) return;
NDS.RunEventManual(Event_ROMTransfer);
ROMData = val;

View file

@ -414,9 +414,11 @@ public:
[[nodiscard]] u8 GetROMCommand(u8 index) const noexcept { return ROMCommand[index]; }
void SetROMCommand(u8 index, u8 val) noexcept { ROMCommand[index] = val; }
[[nodiscard]] u32 GetROMCnt() const noexcept { return ROMCnt; }
[[nodiscard]] u32 GetROMCnt() noexcept;
[[nodiscard]] u16 GetSPICnt() const noexcept { return SPICnt; }
void SetSPICnt(u16 val) noexcept { SPICnt = val; }
private:
friend class CartCommon;
melonDS::NDS& NDS;
@ -441,6 +443,7 @@ private:
u64 Key2_X = 0;
u64 Key2_Y = 0;
u64 ROMTransferTime;
void Key1_Encrypt(u32* data) const noexcept;
void Key1_Decrypt(u32* data) const noexcept;

View file

@ -24,7 +24,7 @@
#include <stdio.h>
#include "types.h"
#define SAVESTATE_MAJOR 12
#define SAVESTATE_MAJOR 13
#define SAVESTATE_MINOR 1
namespace melonDS