Cores/Nds/ARM.cs
namespace Emulotl.Nds;
public abstract class ARM
{
public static uint ROR( uint x, uint n )
{
return (x >> (int)(n & 0x1F)) | (x << (int)((32 - n) & 0x1F));
}
public static readonly uint[] ConditionTable =
[
0xF0F0,
0x0F0F,
0xCCCC,
0x3333,
0xFF00,
0x00FF,
0xAAAA,
0x5555,
0x0C0C,
0xF3F3,
0xAA55,
0x55AA,
0x0A05,
0xF5FA,
0xFFFF,
0x0000,
];
public readonly NDS NDS;
public uint Num;
public int Cycles;
public uint StopExecution;
public byte Halted
{
get => (byte)(StopExecution & 0xFF);
set => StopExecution = (StopExecution & 0xFFFFFF00) | value;
}
public byte IRQ
{
get => (byte)((StopExecution >> 8) & 0xFF);
set => StopExecution = (StopExecution & 0xFFFF00FF) | ((uint)value << 8);
}
public byte IdleLoop
{
get => (byte)((StopExecution >> 16) & 0xFF);
set => StopExecution = (StopExecution & 0xFF00FFFF) | ((uint)value << 16);
}
public uint CodeRegion;
public int CodeCycles;
public uint DataRegion;
public int DataCycles;
public uint[] R = new uint[16];
public uint CPSR;
public uint[] R_FIQ = new uint[8];
public uint[] R_SVC = new uint[3];
public uint[] R_ABT = new uint[3];
public uint[] R_IRQ = new uint[3];
public uint[] R_UND = new uint[3];
public uint CurInstr;
public uint[] NextInstr = new uint[2];
public uint ExceptionBase;
public MemRegion CodeMem;
protected ARM( uint num, NDS nds )
{
Num = num;
NDS = nds;
}
public virtual void Reset()
{
Cycles = 0;
Halted = 0;
IRQ = 0;
for ( int i = 0; i < 16; i++ )
R[i] = 0;
CPSR = 0x000000D3;
for ( int i = 0; i < 7; i++ )
R_FIQ[i] = 0;
for ( int i = 0; i < 2; i++ )
{
R_SVC[i] = 0;
R_ABT[i] = 0;
R_IRQ[i] = 0;
R_UND[i] = 0;
}
R_FIQ[7] = 0x00000010;
R_SVC[2] = 0x00000010;
R_ABT[2] = 0x00000010;
R_IRQ[2] = 0x00000010;
R_UND[2] = 0x00000010;
ExceptionBase = Num != 0 ? 0x00000000 : 0xFFFF0000;
CodeMem.Mem = null;
JumpTo( ExceptionBase );
}
public abstract void FillPipeline();
public abstract void JumpTo( uint addr, bool restorecpsr = false );
public void RestoreCPSR()
{
uint oldcpsr = CPSR;
switch ( CPSR & 0x1F )
{
case 0x11: CPSR = R_FIQ[7]; break;
case 0x12: CPSR = R_IRQ[2]; break;
case 0x13: CPSR = R_SVC[2]; break;
case 0x14:
case 0x15:
case 0x16:
case 0x17: CPSR = R_ABT[2]; break;
case 0x18:
case 0x19:
case 0x1A:
case 0x1B: CPSR = R_UND[2]; break;
default:
Platform.Log( LogLevel.Warn, $"!! restore CPSR bad mode {CPSR & 0x1F:X2}" );
break;
}
CPSR |= 0x00000010;
UpdateMode( oldcpsr, CPSR );
}
public void Halt( uint halt )
{
if ( halt == 2 && Halted == 1 )
return;
Halted = (byte)halt;
}
public bool CheckCondition( uint code )
{
if ( code == 0xE )
return true;
return (ConditionTable[code] & (1 << (int)(CPSR >> 28))) != 0;
}
public void SetC( bool c )
{
if ( c ) CPSR |= 0x20000000;
else CPSR &= ~0x20000000u;
}
public void SetNZ( bool n, bool z )
{
CPSR &= ~0xC0000000u;
if ( n ) CPSR |= 0x80000000;
if ( z ) CPSR |= 0x40000000;
}
public void SetNZCV( bool n, bool z, bool c, bool v )
{
CPSR &= ~0xF0000000u;
if ( n ) CPSR |= 0x80000000;
if ( z ) CPSR |= 0x40000000;
if ( c ) CPSR |= 0x20000000;
if ( v ) CPSR |= 0x10000000;
}
public bool ModeIs( uint mode )
{
uint cm = CPSR & 0x1F;
mode &= 0x1F;
if ( mode == cm ) return true;
if ( mode == 0x17 ) return cm >= 0x14 && cm <= 0x17;
if ( mode == 0x1B ) return cm >= 0x18 && cm <= 0x1B;
return false;
}
public void UpdateMode( uint oldmode, uint newmode, bool phony = false )
{
if ( (oldmode & 0x1F) == (newmode & 0x1F) )
return;
switch ( oldmode & 0x1F )
{
case 0x11:
Swap( ref R[8], ref R_FIQ[0] );
Swap( ref R[9], ref R_FIQ[1] );
Swap( ref R[10], ref R_FIQ[2] );
Swap( ref R[11], ref R_FIQ[3] );
Swap( ref R[12], ref R_FIQ[4] );
Swap( ref R[13], ref R_FIQ[5] );
Swap( ref R[14], ref R_FIQ[6] );
break;
case 0x12:
Swap( ref R[13], ref R_IRQ[0] );
Swap( ref R[14], ref R_IRQ[1] );
break;
case 0x13:
Swap( ref R[13], ref R_SVC[0] );
Swap( ref R[14], ref R_SVC[1] );
break;
case 0x17:
Swap( ref R[13], ref R_ABT[0] );
Swap( ref R[14], ref R_ABT[1] );
break;
case 0x1B:
Swap( ref R[13], ref R_UND[0] );
Swap( ref R[14], ref R_UND[1] );
break;
}
switch ( newmode & 0x1F )
{
case 0x11:
Swap( ref R[8], ref R_FIQ[0] );
Swap( ref R[9], ref R_FIQ[1] );
Swap( ref R[10], ref R_FIQ[2] );
Swap( ref R[11], ref R_FIQ[3] );
Swap( ref R[12], ref R_FIQ[4] );
Swap( ref R[13], ref R_FIQ[5] );
Swap( ref R[14], ref R_FIQ[6] );
break;
case 0x12:
Swap( ref R[13], ref R_IRQ[0] );
Swap( ref R[14], ref R_IRQ[1] );
break;
case 0x13:
Swap( ref R[13], ref R_SVC[0] );
Swap( ref R[14], ref R_SVC[1] );
break;
case 0x17:
Swap( ref R[13], ref R_ABT[0] );
Swap( ref R[14], ref R_ABT[1] );
break;
case 0x1B:
Swap( ref R[13], ref R_UND[0] );
Swap( ref R[14], ref R_UND[1] );
break;
}
if ( !phony && Num == 0 )
{
ARMv5 cpu = (ARMv5)this;
cpu.PU_Map = (newmode & 0x1F) == 0x10 ? cpu.PU_UserMap : cpu.PU_PrivMap;
}
}
public void TriggerIRQ()
{
if ( (CPSR & 0x80) != 0 )
return;
uint oldcpsr = CPSR;
CPSR &= ~0xFFu;
CPSR |= 0xD2;
UpdateMode( oldcpsr, CPSR );
R_IRQ[2] = oldcpsr;
R[14] = R[15] + ((oldcpsr & 0x20) != 0 ? 2u : 0u);
JumpTo( ExceptionBase + 0x18 );
}
public uint CodeMemBase = 0xFFFFFFFF;
public void SetupCodeMem( uint addr )
{
if ( Num == 0 )
((ARMv5)this).GetCodeMemRegion( addr, ref CodeMem );
else
NDS.GetARM7CodeMem( addr, ref CodeMem );
CodeMemBase = addr & 0xFF800000;
}
public void NocashPrint( uint addr ) { }
public abstract void DataRead8( uint addr, ref uint val );
public abstract void DataRead16( uint addr, ref uint val );
public abstract void DataRead32( uint addr, ref uint val );
public abstract void DataRead32S( uint addr, ref uint val );
public abstract void DataWrite8( uint addr, byte val );
public abstract void DataWrite16( uint addr, ushort val );
public abstract void DataWrite32( uint addr, uint val );
public abstract void DataWrite32S( uint addr, uint val );
public abstract void AddCycles_C();
public abstract void AddCycles_CI( int numI );
public abstract void AddCycles_CDI();
public abstract void AddCycles_CD();
protected abstract byte BusRead8( uint addr );
protected abstract ushort BusRead16( uint addr );
protected abstract uint BusRead32( uint addr );
protected abstract void BusWrite8( uint addr, byte val );
protected abstract void BusWrite16( uint addr, ushort val );
protected abstract void BusWrite32( uint addr, uint val );
private static void Swap( ref uint a, ref uint b )
{
(a, b) = (b, a);
}
}