Cores/Nds/ARMInterpreter_Branch.cs
namespace Emulotl.Nds;

public static partial class ARMInterpreter
{
	public static void A_B( ARM cpu )
	{
		int offset = (int)(cpu.CurInstr << 8) >> 6;
		cpu.JumpTo( cpu.R[15] + (uint)offset );
	}

	public static void A_BL( ARM cpu )
	{
		int offset = (int)(cpu.CurInstr << 8) >> 6;
		cpu.R[14] = cpu.R[15] - 4;
		cpu.JumpTo( cpu.R[15] + (uint)offset );
	}

	public static void A_BLX_IMM( ARM cpu )
	{
		int offset = (int)(cpu.CurInstr << 8) >> 6;
		if ( (cpu.CurInstr & 0x01000000) != 0 ) offset += 2;
		cpu.R[14] = cpu.R[15] - 4;
		cpu.JumpTo( cpu.R[15] + (uint)offset + 1 );
	}

	public static void A_BX( ARM cpu )
	{
		cpu.JumpTo( cpu.R[cpu.CurInstr & 0xF] );
	}

	public static void A_BLX_REG( ARM cpu )
	{
		uint lr = cpu.R[15] - 4;
		cpu.JumpTo( cpu.R[cpu.CurInstr & 0xF] );
		cpu.R[14] = lr;
	}

	public static void T_BCOND( ARM cpu )
	{
		if ( cpu.CheckCondition( (cpu.CurInstr >> 8) & 0xF ) )
		{
			int offset = (int)(cpu.CurInstr << 24) >> 23;
			cpu.JumpTo( cpu.R[15] + (uint)offset + 1 );
		}
		else
		{
			cpu.AddCycles_C();
		}
	}

	public static void T_BX( ARM cpu )
	{
		cpu.JumpTo( cpu.R[(cpu.CurInstr >> 3) & 0xF] );
	}

	public static void T_BLX_REG( ARM cpu )
	{
		if ( cpu.Num == 1 )
		{
			Platform.Log( LogLevel.Warn, "!! THUMB BLX_REG ON ARM7" );
			return;
		}

		uint lr = cpu.R[15] - 1;
		cpu.JumpTo( cpu.R[(cpu.CurInstr >> 3) & 0xF] );
		cpu.R[14] = lr;
	}

	public static void T_B( ARM cpu )
	{
		int offset = (int)((cpu.CurInstr & 0x7FF) << 21) >> 20;
		cpu.JumpTo( cpu.R[15] + (uint)offset + 1 );
	}

	public static void T_BL_LONG_1( ARM cpu )
	{
		int offset = (int)((cpu.CurInstr & 0x7FF) << 21) >> 9;
		cpu.R[14] = cpu.R[15] + (uint)offset;
		cpu.AddCycles_C();
	}

	public static void T_BL_LONG_2( ARM cpu )
	{
		uint offset = (cpu.CurInstr & 0x7FF) << 1;
		uint pc = cpu.R[14] + offset;

		if ( cpu.Num == 1 || (cpu.CurInstr & (1 << 12)) != 0 )
		{
			pc |= 1;
		}
		else
		{
			if ( (cpu.CurInstr & 1) != 0 )
			{
				T_UNK( cpu );
				return;
			}

			pc &= ~1u;
		}

		cpu.R[14] = (cpu.R[15] - 2) | 1;
		cpu.JumpTo( pc );
	}

	private static void BuildBranchTable()
	{
		for ( int i = 0; i < 256; i++ )
		{
			ARMInstrTable[0xA00 | i] = A_B;
			ARMInstrTable[0xB00 | i] = A_BL;
		}

		ARMInstrTable[0x121] = A_BX;
		ARMInstrTable[0x123] = A_BLX_REG;
	}
}