diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj
index 2b4d5347b7..f65074ddd4 100644
--- a/BizHawk.Emulation/BizHawk.Emulation.csproj
+++ b/BizHawk.Emulation/BizHawk.Emulation.csproj
@@ -231,6 +231,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/Arm7Processor.cs b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/Arm7Processor.cs
new file mode 100644
index 0000000000..6b9c83c499
--- /dev/null
+++ b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/Arm7Processor.cs
@@ -0,0 +1,501 @@
+namespace GarboDev
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Text;
+
+ public class Arm7Processor
+ {
+ private Memory memory = null;
+ private FastArmCore armCore = null;
+ private ThumbCore thumbCore = null;
+ private Dictionary breakpoints = null;
+
+ private int cycles = 0;
+ private int timerCycles = 0;
+ private int soundCycles = 0;
+
+ // CPU mode definitions
+ public const uint USR = 0x10;
+ public const uint FIQ = 0x11;
+ public const uint IRQ = 0x12;
+ public const uint SVC = 0x13;
+ public const uint ABT = 0x17;
+ public const uint UND = 0x1B;
+ public const uint SYS = 0x1F;
+
+ // CPSR bit definitions
+ public const int N_BIT = 31;
+ public const int Z_BIT = 30;
+ public const int C_BIT = 29;
+ public const int V_BIT = 28;
+ public const int I_BIT = 7;
+ public const int F_BIT = 6;
+ public const int T_BIT = 5;
+
+ public const uint N_MASK = (uint)(1U << N_BIT);
+ public const uint Z_MASK = (uint)(1U << Z_BIT);
+ public const uint C_MASK = (uint)(1U << C_BIT);
+ public const uint V_MASK = (uint)(1U << V_BIT);
+ public const uint I_MASK = (uint)(1U << I_BIT);
+ public const uint F_MASK = (uint)(1U << F_BIT);
+ public const uint T_MASK = (uint)(1U << T_BIT);
+
+ // Standard registers
+ private uint[] registers = new uint[16];
+ private uint cpsr = 0;
+
+ // Banked registers
+ private uint[] bankedFIQ = new uint[7];
+ private uint[] bankedIRQ = new uint[2];
+ private uint[] bankedSVC = new uint[2];
+ private uint[] bankedABT = new uint[2];
+ private uint[] bankedUND = new uint[2];
+
+ // Saved CPSR's
+ private uint spsrFIQ = 0;
+ private uint spsrIRQ = 0;
+ private uint spsrSVC = 0;
+ private uint spsrABT = 0;
+ private uint spsrUND = 0;
+
+ private ushort keyState;
+
+ private bool breakpointHit = false;
+ private bool cpuHalted = false;
+
+ public ushort KeyState
+ {
+ set { this.keyState = value; }
+ }
+
+ public int Cycles
+ {
+ get { return this.cycles; }
+ set { this.cycles = value; }
+ }
+
+ public bool ArmState
+ {
+ get { return (this.cpsr & Arm7Processor.T_MASK) != Arm7Processor.T_MASK; }
+ }
+
+ public uint[] Registers
+ {
+ get { return this.registers; }
+ }
+
+ public uint CPSR
+ {
+ get { return this.cpsr; }
+ set { this.cpsr = value; }
+ }
+
+ public bool SPSRExists
+ {
+ get
+ {
+ switch (this.cpsr & 0x1F)
+ {
+ case USR:
+ case SYS:
+ return false;
+ case FIQ:
+ case SVC:
+ case ABT:
+ case IRQ:
+ case UND:
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+
+ public uint SPSR
+ {
+ get
+ {
+ switch (this.cpsr & 0x1F)
+ {
+ case USR:
+ case SYS:
+ return 0xFFFFFFFF;
+ case FIQ:
+ return this.spsrFIQ;
+ case SVC:
+ return this.spsrSVC;
+ case ABT:
+ return this.spsrABT;
+ case IRQ:
+ return this.spsrIRQ;
+ case UND:
+ return this.spsrUND;
+ default:
+ throw new Exception("Unhandled CPSR state...");
+ }
+ }
+ set
+ {
+ switch (this.cpsr & 0x1F)
+ {
+ case USR:
+ case SYS:
+ break;
+ case FIQ:
+ this.spsrFIQ = value;
+ break;
+ case SVC:
+ this.spsrSVC = value;
+ break;
+ case ABT:
+ this.spsrABT = value;
+ break;
+ case IRQ:
+ this.spsrIRQ = value;
+ break;
+ case UND:
+ this.spsrUND = value;
+ break;
+ default:
+ throw new Exception("Unhandled CPSR state...");
+ }
+ }
+ }
+
+ public Dictionary Breakpoints
+ {
+ get
+ {
+ return this.breakpoints;
+ }
+ }
+
+ public bool BreakpointHit
+ {
+ get { return this.breakpointHit; }
+ set { this.breakpointHit = value; }
+ }
+
+ public Arm7Processor(Memory memory)
+ {
+ this.memory = memory;
+ this.memory.Processor = this;
+ this.armCore = new FastArmCore(this, this.memory);
+ this.thumbCore = new ThumbCore(this, this.memory);
+ this.breakpoints = new Dictionary();
+ this.breakpointHit = false;
+ }
+
+ private void SwapRegsHelper(uint[] swapRegs)
+ {
+ for (int i = 14; i > 14 - swapRegs.Length; i--)
+ {
+ uint tmp = this.registers[i];
+ this.registers[i] = swapRegs[swapRegs.Length - (14 - i) - 1];
+ swapRegs[swapRegs.Length - (14 - i) - 1] = tmp;
+ }
+ }
+
+ private void SwapRegisters(uint bank)
+ {
+ switch (bank & 0x1F)
+ {
+ case FIQ:
+ this.SwapRegsHelper(this.bankedFIQ);
+ break;
+ case SVC:
+ this.SwapRegsHelper(this.bankedSVC);
+ break;
+ case ABT:
+ this.SwapRegsHelper(this.bankedABT);
+ break;
+ case IRQ:
+ this.SwapRegsHelper(this.bankedIRQ);
+ break;
+ case UND:
+ this.SwapRegsHelper(this.bankedUND);
+ break;
+ }
+ }
+
+ public void WriteCpsr(uint newCpsr)
+ {
+ if ((newCpsr & 0x1F) != (this.cpsr & 0x1F))
+ {
+ // Swap out the old registers
+ this.SwapRegisters(this.cpsr);
+ // Swap in the new registers
+ this.SwapRegisters(newCpsr);
+ }
+
+ this.cpsr = newCpsr;
+ }
+
+ public void EnterException(uint mode, uint vector, bool interruptsDisabled, bool fiqDisabled)
+ {
+ uint oldCpsr = this.cpsr;
+
+ if ((oldCpsr & Arm7Processor.T_MASK) != 0)
+ {
+ registers[15] += 2U;
+ }
+
+ // Clear T bit, and set mode
+ uint newCpsr = (oldCpsr & ~0x3FU) | mode;
+ if (interruptsDisabled) newCpsr |= 1 << 7;
+ if (fiqDisabled) newCpsr |= 1 << 6;
+ this.WriteCpsr(newCpsr);
+
+ this.SPSR = oldCpsr;
+ registers[14] = registers[15];
+ registers[15] = vector;
+
+ this.ReloadQueue();
+ }
+
+ public void RequestIrq(int irq)
+ {
+ ushort iflag = Memory.ReadU16(this.memory.IORam, Memory.IF);
+ iflag |= (ushort)(1 << irq);
+ Memory.WriteU16(this.memory.IORam, Memory.IF, iflag);
+ }
+
+ public void FireIrq()
+ {
+ ushort ime = Memory.ReadU16(this.memory.IORam, Memory.IME);
+ ushort ie = Memory.ReadU16(this.memory.IORam, Memory.IE);
+ ushort iflag = Memory.ReadU16(this.memory.IORam, Memory.IF);
+
+ if ((ie & (iflag)) != 0 && (ime & 1) != 0 && (this.cpsr & (1 << 7)) == 0)
+ {
+ // Off to the irq exception vector
+ this.EnterException(Arm7Processor.IRQ, 0x18, true, false);
+ }
+ }
+
+ public void Reset(bool skipBios)
+ {
+ this.breakpointHit = false;
+ this.cpuHalted = false;
+
+ // Default to ARM state
+ this.cycles = 0;
+ this.timerCycles = 0;
+ this.soundCycles = 0;
+
+ this.bankedSVC[0] = 0x03007FE0;
+ this.bankedIRQ[0] = 0x03007FA0;
+
+ this.cpsr = SYS;
+ this.spsrSVC = this.cpsr;
+ for (int i = 0; i < 15; i++) this.registers[i] = 0;
+
+ if (skipBios)
+ {
+ this.registers[15] = 0x8000000;
+ }
+ else
+ {
+ this.registers[15] = 0;
+ }
+
+ this.armCore.BeginExecution();
+ }
+
+ public void Halt()
+ {
+ this.cpuHalted = true;
+ this.cycles = 0;
+ }
+
+ public void Step()
+ {
+ this.breakpointHit = false;
+
+ if ((this.cpsr & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbCore.Step();
+ }
+ else
+ {
+ this.armCore.Step();
+ }
+
+ this.UpdateTimers();
+ }
+
+ public void ReloadQueue()
+ {
+ if ((this.cpsr & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbCore.BeginExecution();
+ }
+ else
+ {
+ this.armCore.BeginExecution();
+ }
+ }
+
+ private void UpdateTimer(int timer, int cycles, bool countUp)
+ {
+ ushort control = Memory.ReadU16(this.memory.IORam, Memory.TM0CNT + (uint)(timer * 4));
+
+ // Make sure timer is enabled, or count up is disabled
+ if ((control & (1 << 7)) == 0) return;
+ if (!countUp && (control & (1 << 2)) != 0) return;
+
+ if (!countUp)
+ {
+ switch (control & 3)
+ {
+ case 0: cycles *= 1 << 10; break;
+ case 1: cycles *= 1 << 4; break;
+ case 2: cycles *= 1 << 2; break;
+ // Don't need to do anything for case 3
+ }
+ }
+
+ this.memory.TimerCnt[timer] += (uint)cycles;
+ uint timerCnt = this.memory.TimerCnt[timer] >> 10;
+
+ if (timerCnt > 0xffff)
+ {
+ ushort soundCntX = Memory.ReadU16(this.memory.IORam, Memory.SOUNDCNT_X);
+ if ((soundCntX & (1 << 7)) != 0)
+ {
+ ushort soundCntH = Memory.ReadU16(this.memory.IORam, Memory.SOUNDCNT_H);
+ if (timer == ((soundCntH >> 10) & 1))
+ {
+ // FIFO A overflow
+ this.memory.SoundManager.DequeueA();
+ if (this.memory.SoundManager.QueueSizeA < 16)
+ {
+ this.memory.FifoDma(1);
+ // TODO
+ if (this.memory.SoundManager.QueueSizeA < 16)
+ {
+ }
+ }
+ }
+ if (timer == ((soundCntH >> 14) & 1))
+ {
+ // FIFO B overflow
+ this.memory.SoundManager.DequeueB();
+ if (this.memory.SoundManager.QueueSizeB < 16)
+ {
+ this.memory.FifoDma(2);
+ }
+ }
+ }
+
+ // Overflow, attempt to fire IRQ
+ if ((control & (1 << 6)) != 0)
+ {
+ this.RequestIrq(3 + timer);
+ }
+
+ if (timer < 3)
+ {
+ ushort control2 = Memory.ReadU16(this.memory.IORam, Memory.TM0CNT + (uint)((timer + 1) * 4));
+ if ((control2 & (1 << 2)) != 0)
+ {
+ // Count-up
+ this.UpdateTimer(timer + 1, (int)((timerCnt >> 16) << 10), true);
+ }
+ }
+
+ // Reset the original value
+ uint count = Memory.ReadU16(this.memory.IORam, Memory.TM0D + (uint)(timer * 4));
+ this.memory.TimerCnt[timer] = count << 10;
+ }
+ }
+
+ public void UpdateTimers()
+ {
+ int cycles = this.timerCycles - this.cycles;
+
+ for (int i = 0; i < 4; i++)
+ {
+ this.UpdateTimer(i, cycles, false);
+ }
+
+ this.timerCycles = this.cycles;
+ }
+
+ public void UpdateKeyState()
+ {
+ ushort KEYCNT = this.memory.ReadU16Debug(Memory.REG_BASE + Memory.KEYCNT);
+
+ if ((KEYCNT & (1 << 14)) != 0)
+ {
+ if ((KEYCNT & (1 << 15)) != 0)
+ {
+ KEYCNT &= 0x3FF;
+ if (((~this.keyState) & KEYCNT) == KEYCNT)
+ this.RequestIrq(12);
+ }
+ else
+ {
+ KEYCNT &= 0x3FF;
+ if (((~this.keyState) & KEYCNT) != 0)
+ this.RequestIrq(12);
+ }
+ }
+
+ this.memory.KeyState = this.keyState;
+ }
+
+ public void UpdateSound()
+ {
+ this.memory.SoundManager.Mix(this.soundCycles);
+ this.soundCycles = 0;
+ }
+
+ public void Execute(int cycles)
+ {
+ this.cycles += cycles;
+ this.timerCycles += cycles;
+ this.soundCycles += cycles;
+ this.breakpointHit = false;
+
+ if (this.cpuHalted)
+ {
+ ushort ie = Memory.ReadU16(this.memory.IORam, Memory.IE);
+ ushort iflag = Memory.ReadU16(this.memory.IORam, Memory.IF);
+
+ if ((ie & iflag) != 0)
+ {
+ this.cpuHalted = false;
+ }
+ else
+ {
+ this.cycles = 0;
+ this.UpdateTimers();
+ this.UpdateSound();
+ return;
+ }
+ }
+
+ while (this.cycles > 0)
+ {
+ if ((this.cpsr & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbCore.Execute();
+ }
+ else
+ {
+ this.armCore.Execute();
+ }
+
+ this.UpdateTimers();
+ this.UpdateSound();
+
+ if (this.breakpointHit)
+ {
+ break;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/ArmCore.cs b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/ArmCore.cs
new file mode 100644
index 0000000000..5eda1e7a5d
--- /dev/null
+++ b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/ArmCore.cs
@@ -0,0 +1,1273 @@
+//#define ARM_DEBUG
+
+namespace GarboDev
+{
+ using System;
+
+ public class ArmCore
+ {
+ private const uint COND_EQ = 0; // Z set
+ private const uint COND_NE = 1; // Z clear
+ private const uint COND_CS = 2; // C set
+ private const uint COND_CC = 3; // C clear
+ private const uint COND_MI = 4; // N set
+ private const uint COND_PL = 5; // N clear
+ private const uint COND_VS = 6; // V set
+ private const uint COND_VC = 7; // V clear
+ private const uint COND_HI = 8; // C set and Z clear
+ private const uint COND_LS = 9; // C clear or Z set
+ private const uint COND_GE = 10; // N equals V
+ private const uint COND_LT = 11; // N not equal to V
+ private const uint COND_GT = 12; // Z clear AND (N equals V)
+ private const uint COND_LE = 13; // Z set OR (N not equal to V)
+ private const uint COND_AL = 14; // Always
+ private const uint COND_NV = 15; // Never execute
+
+ private const uint OP_AND = 0x0;
+ private const uint OP_EOR = 0x1;
+ private const uint OP_SUB = 0x2;
+ private const uint OP_RSB = 0x3;
+ private const uint OP_ADD = 0x4;
+ private const uint OP_ADC = 0x5;
+ private const uint OP_SBC = 0x6;
+ private const uint OP_RSC = 0x7;
+ private const uint OP_TST = 0x8;
+ private const uint OP_TEQ = 0x9;
+ private const uint OP_CMP = 0xA;
+ private const uint OP_CMN = 0xB;
+ private const uint OP_ORR = 0xC;
+ private const uint OP_MOV = 0xD;
+ private const uint OP_BIC = 0xE;
+ private const uint OP_MVN = 0xF;
+
+ private delegate void ExecuteInstruction();
+ private ExecuteInstruction[] NormalOps = null;
+
+ private Arm7Processor parent;
+ private Memory memory;
+ private uint[] registers;
+
+ private uint instructionQueue;
+ private uint curInstruction;
+
+ // CPU flags
+ private uint zero, carry, negative, overflow;
+ private uint shifterCarry;
+
+ private bool thumbMode;
+
+ public ArmCore(Arm7Processor parent, Memory memory)
+ {
+ this.parent = parent;
+ this.memory = memory;
+ this.registers = this.parent.Registers;
+
+ this.NormalOps = new ExecuteInstruction[8]
+ {
+ this.DataProcessing,
+ this.DataProcessingImmed,
+ this.LoadStoreImmediate,
+ this.LoadStoreRegister,
+ this.LoadStoreMultiple,
+ this.Branch,
+ this.CoprocessorLoadStore,
+ this.SoftwareInterrupt
+ };
+ }
+
+ public void BeginExecution()
+ {
+ this.FlushQueue();
+ }
+
+ public void Step()
+ {
+ this.UnpackFlags();
+
+ this.curInstruction = this.instructionQueue;
+ this.instructionQueue = this.memory.ReadU32(registers[15]);
+ registers[15] += 4;
+
+ uint cond = 0;
+ switch (this.curInstruction >> 28)
+ {
+ case COND_AL: cond = 1; break;
+ case COND_EQ: cond = zero; break;
+ case COND_NE: cond = 1 - zero; break;
+ case COND_CS: cond = carry; break;
+ case COND_CC: cond = 1 - carry; break;
+ case COND_MI: cond = negative; break;
+ case COND_PL: cond = 1 - negative; break;
+ case COND_VS: cond = overflow; break;
+ case COND_VC: cond = 1 - overflow; break;
+ case COND_HI: cond = carry & (1 - zero); break;
+ case COND_LS: cond = (1 - carry) | zero; break;
+ case COND_GE: cond = (1 - negative) ^ overflow; break;
+ case COND_LT: cond = negative ^ overflow; break;
+ case COND_GT: cond = (1 - zero) & (negative ^ (1 - overflow)); break;
+ case COND_LE: cond = (negative ^ overflow) | zero; break;
+ }
+
+ if (cond == 1)
+ {
+ // Execute the instruction
+ this.NormalOps[(curInstruction >> 25) & 0x7]();
+ }
+
+ this.parent.Cycles -= this.memory.WaitCycles;
+
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.parent.ReloadQueue();
+ }
+
+ this.PackFlags();
+ }
+
+ public void Execute()
+ {
+ this.UnpackFlags();
+ this.thumbMode = false;
+
+ while (this.parent.Cycles > 0)
+ {
+ this.curInstruction = this.instructionQueue;
+ this.instructionQueue = this.memory.ReadU32Aligned(registers[15]);
+ registers[15] += 4;
+
+ if ((this.curInstruction >> 28) == COND_AL)
+ {
+ this.NormalOps[(curInstruction >> 25) & 0x7]();
+ }
+ else
+ {
+ uint cond = 0;
+ switch (this.curInstruction >> 28)
+ {
+ case COND_EQ: cond = zero; break;
+ case COND_NE: cond = 1 - zero; break;
+ case COND_CS: cond = carry; break;
+ case COND_CC: cond = 1 - carry; break;
+ case COND_MI: cond = negative; break;
+ case COND_PL: cond = 1 - negative; break;
+ case COND_VS: cond = overflow; break;
+ case COND_VC: cond = 1 - overflow; break;
+ case COND_HI: cond = carry & (1 - zero); break;
+ case COND_LS: cond = (1 - carry) | zero; break;
+ case COND_GE: cond = (1 - negative) ^ overflow; break;
+ case COND_LT: cond = negative ^ overflow; break;
+ case COND_GT: cond = (1 - zero) & (negative ^ (1 - overflow)); break;
+ case COND_LE: cond = (negative ^ overflow) | zero; break;
+ }
+
+ if (cond == 1)
+ {
+ // Execute the instruction
+ this.NormalOps[(curInstruction >> 25) & 0x7]();
+ }
+ }
+
+ this.parent.Cycles -= this.memory.WaitCycles;
+
+ if (this.thumbMode)
+ {
+ this.parent.ReloadQueue();
+ break;
+ }
+
+#if ARM_DEBUG
+ // Check the current PC
+ if (this.parent.Breakpoints.ContainsKey(registers[15] - 4U))
+ {
+ this.parent.BreakpointHit = true;
+ break;
+ }
+#endif
+ }
+
+ this.PackFlags();
+ }
+
+ #region Barrel Shifter
+ private const uint SHIFT_LSL = 0;
+ private const uint SHIFT_LSR = 1;
+ private const uint SHIFT_ASR = 2;
+ private const uint SHIFT_ROR = 3;
+
+ private uint BarrelShifter(uint shifterOperand)
+ {
+ uint type = (shifterOperand >> 5) & 0x3;
+
+ bool registerShift = (shifterOperand & (1 << 4)) == (1 << 4);
+
+ uint rm = registers[shifterOperand & 0xF];
+
+ int amount;
+ if (registerShift)
+ {
+ uint rs = (shifterOperand >> 8) & 0xF;
+ if (rs == 15)
+ {
+ amount = (int)((registers[rs] + 0x4) & 0xFF);
+ }
+ else
+ {
+ amount = (int)(registers[rs] & 0xFF);
+ }
+
+ if ((shifterOperand & 0xF) == 15)
+ {
+ rm += 4;
+ }
+ }
+ else
+ {
+ amount = (int)((shifterOperand >> 7) & 0x1F);
+ }
+
+ if (registerShift)
+ {
+ if (amount == 0)
+ {
+ this.shifterCarry = this.carry;
+ return rm;
+ }
+
+ switch (type)
+ {
+ case SHIFT_LSL:
+ if (amount < 32)
+ {
+ this.shifterCarry = (rm >> (32 - amount)) & 1;
+ return rm << amount;
+ }
+ else if (amount == 32)
+ {
+ this.shifterCarry = rm & 1;
+ return 0;
+ }
+ else
+ {
+ this.shifterCarry = 0;
+ return 0;
+ }
+
+ case SHIFT_LSR:
+ if (amount < 32)
+ {
+ this.shifterCarry = (rm >> (amount - 1)) & 1;
+ return rm >> amount;
+ }
+ else if (amount == 32)
+ {
+ this.shifterCarry = (rm >> 31) & 1;
+ return 0;
+ }
+ else
+ {
+ this.shifterCarry = 0;
+ return 0;
+ }
+
+ case SHIFT_ASR:
+ if (amount >= 32)
+ {
+ if ((rm & (1 << 31)) == 0)
+ {
+ this.shifterCarry = 0;
+ return 0;
+ }
+ else
+ {
+ this.shifterCarry = 1;
+ return 0xFFFFFFFF;
+ }
+ }
+ else
+ {
+ this.shifterCarry = (rm >> (amount - 1)) & 1;
+ return (uint)(((int)rm) >> amount);
+ }
+
+ case SHIFT_ROR:
+ if ((amount & 0x1F) == 0)
+ {
+ this.shifterCarry = (rm >> 31) & 1;
+ return rm;
+ }
+ else
+ {
+ amount &= 0x1F;
+ this.shifterCarry = (rm >> amount) & 1;
+ return (rm >> amount) | (rm << (32 - amount));
+ }
+ }
+ }
+ else
+ {
+ switch (type)
+ {
+ case SHIFT_LSL:
+ if (amount == 0)
+ {
+ this.shifterCarry = this.carry;
+ return rm;
+ }
+ else
+ {
+ this.shifterCarry = (rm >> (32 - amount)) & 1;
+ return rm << amount;
+ }
+
+ case SHIFT_LSR:
+ if (amount == 0)
+ {
+ this.shifterCarry = (rm >> 31) & 1;
+ return 0;
+ }
+ else
+ {
+ this.shifterCarry = (rm >> (amount - 1)) & 1;
+ return rm >> amount;
+ }
+
+ case SHIFT_ASR:
+ if (amount == 0)
+ {
+ if ((rm & (1 << 31)) == 0)
+ {
+ this.shifterCarry = 0;
+ return 0;
+ }
+ else
+ {
+ this.shifterCarry = 1;
+ return 0xFFFFFFFF;
+ }
+ }
+ else
+ {
+ this.shifterCarry = (rm >> (amount - 1)) & 1;
+ return (uint)(((int)rm) >> amount);
+ }
+
+ case SHIFT_ROR:
+ if (amount == 0)
+ {
+ // Actually an RRX
+ this.shifterCarry = rm & 1;
+ return (this.carry << 31) | (rm >> 1);
+ }
+ else
+ {
+ this.shifterCarry = (rm >> (amount - 1)) & 1;
+ return (rm >> amount) | (rm << (32 - amount));
+ }
+ }
+ }
+
+ // Should never happen...
+ throw new Exception("Barrel Shifter has messed up.");
+ }
+ #endregion
+
+ #region Flag helpers
+ public void OverflowCarryAdd(uint a, uint b, uint r)
+ {
+ overflow = ((a & b & ~r) | (~a & ~b & r)) >> 31;
+ carry = ((a & b) | (a & ~r) | (b & ~r)) >> 31;
+ }
+
+ public void OverflowCarrySub(uint a, uint b, uint r)
+ {
+ overflow = ((a & ~b & ~r) | (~a & b & r)) >> 31;
+ carry = ((a & ~b) | (a & ~r) | (~b & ~r)) >> 31;
+ }
+ #endregion
+
+ #region Opcodes
+ private void DoDataProcessing(uint shifterOperand)
+ {
+ uint rn = (this.curInstruction >> 16) & 0xF;
+ uint rd = (this.curInstruction >> 12) & 0xF;
+ uint alu;
+
+ bool registerShift = (this.curInstruction & (1 << 4)) == (1 << 4);
+ if (rn == 15 && ((this.curInstruction >> 25) & 0x7) == 0 && registerShift)
+ {
+ rn = registers[rn] + 4;
+ }
+ else
+ {
+ rn = registers[rn];
+ }
+
+ uint opcode = (this.curInstruction >> 21) & 0xF;
+
+ if (((this.curInstruction >> 20) & 1) == 1)
+ {
+ // Set flag bit set
+ switch (opcode)
+ {
+ case OP_ADC:
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+ break;
+
+ case OP_ADD:
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+ break;
+
+ case OP_AND:
+ registers[rd] = rn & shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case OP_BIC:
+ registers[rd] = rn & ~shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case OP_CMN:
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ break;
+
+ case OP_CMP:
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ break;
+
+ case OP_EOR:
+ registers[rd] = rn ^ shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case OP_MOV:
+ registers[rd] = shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case OP_MVN:
+ registers[rd] = ~shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case OP_ORR:
+ registers[rd] = rn | shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case OP_RSB:
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+ break;
+
+ case OP_RSC:
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+ break;
+
+ case OP_SBC:
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+ break;
+
+ case OP_SUB:
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+ break;
+
+ case OP_TEQ:
+ alu = rn ^ shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case OP_TST:
+ alu = rn & shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+ }
+
+ if (rd == 15)
+ {
+ // Prevent writing if no SPSR exists (this will be true for USER or SYSTEM mode)
+ if (this.parent.SPSRExists) this.parent.WriteCpsr(this.parent.SPSR);
+ this.UnpackFlags();
+
+ // Check for branch back to Thumb Mode
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbMode = true;
+ return;
+ }
+
+ // Otherwise, flush the instruction queue
+ this.FlushQueue();
+ }
+ }
+ else
+ {
+ // Set flag bit not set
+ switch (opcode)
+ {
+ case OP_ADC: registers[rd] = rn + shifterOperand + carry; break;
+ case OP_ADD: registers[rd] = rn + shifterOperand; break;
+ case OP_AND: registers[rd] = rn & shifterOperand; break;
+ case OP_BIC: registers[rd] = rn & ~shifterOperand; break;
+ case OP_EOR: registers[rd] = rn ^ shifterOperand; break;
+ case OP_MOV: registers[rd] = shifterOperand; break;
+ case OP_MVN: registers[rd] = ~shifterOperand; break;
+ case OP_ORR: registers[rd] = rn | shifterOperand; break;
+ case OP_RSB: registers[rd] = shifterOperand - rn; break;
+ case OP_RSC: registers[rd] = shifterOperand - rn - (1U - carry); break;
+ case OP_SBC: registers[rd] = rn - shifterOperand - (1U - carry); break;
+ case OP_SUB: registers[rd] = rn - shifterOperand; break;
+
+ case OP_CMN:
+ // MSR SPSR, shifterOperand
+ if ((this.curInstruction & (1 << 16)) == 1 << 16 && this.parent.SPSRExists)
+ {
+ this.parent.SPSR &= 0xFFFFFF00;
+ this.parent.SPSR |= shifterOperand & 0x000000FF;
+ }
+ if ((this.curInstruction & (1 << 17)) == 1 << 17 && this.parent.SPSRExists)
+ {
+ this.parent.SPSR &= 0xFFFF00FF;
+ this.parent.SPSR |= shifterOperand & 0x0000FF00;
+ }
+ if ((this.curInstruction & (1 << 18)) == 1 << 18 && this.parent.SPSRExists)
+ {
+ this.parent.SPSR &= 0xFF00FFFF;
+ this.parent.SPSR |= shifterOperand & 0x00FF0000;
+ }
+ if ((this.curInstruction & (1 << 19)) == 1 << 19 && this.parent.SPSRExists)
+ {
+ this.parent.SPSR &= 0x00FFFFFF;
+ this.parent.SPSR |= shifterOperand & 0xFF000000;
+ }
+
+ // Queue will be flushed since rd == 15, so adjust the PC
+ registers[15] -= 4;
+ break;
+
+ case OP_CMP:
+ // MRS rd, SPSR
+ if (this.parent.SPSRExists) registers[rd] = this.parent.SPSR;
+ break;
+
+ case OP_TEQ:
+ if (((this.curInstruction >> 4) & 0xf) == 1)
+ {
+ // BX
+ uint rm = this.curInstruction & 0xf;
+
+ this.PackFlags();
+
+ this.parent.CPSR &= ~Arm7Processor.T_MASK;
+ this.parent.CPSR |= (registers[rm] & 1) << Arm7Processor.T_BIT;
+
+ registers[15] = registers[rm] & (~1U);
+
+ this.UnpackFlags();
+
+ // Check for branch back to Thumb Mode
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbMode = true;
+ return;
+ }
+
+ // Queue will be flushed later because rd == 15
+ }
+ else if (((this.curInstruction >> 4) & 0xf) == 0)
+ {
+ // MSR CPSR, shifterOperand
+ bool userMode = (this.parent.CPSR & 0x1F) == Arm7Processor.USR;
+
+ this.PackFlags();
+
+ uint tmpCPSR = this.parent.CPSR;
+
+ if ((this.curInstruction & (1 << 16)) == 1 << 16 && !userMode)
+ {
+ tmpCPSR &= 0xFFFFFF00;
+ tmpCPSR |= shifterOperand & 0x000000FF;
+ }
+ if ((this.curInstruction & (1 << 17)) == 1 << 17 && !userMode)
+ {
+ tmpCPSR &= 0xFFFF00FF;
+ tmpCPSR |= shifterOperand & 0x0000FF00;
+ }
+ if ((this.curInstruction & (1 << 18)) == 1 << 18 && !userMode)
+ {
+ tmpCPSR &= 0xFF00FFFF;
+ tmpCPSR |= shifterOperand & 0x00FF0000;
+ }
+ if ((this.curInstruction & (1 << 19)) == 1 << 19)
+ {
+ tmpCPSR &= 0x00FFFFFF;
+ tmpCPSR |= shifterOperand & 0xFF000000;
+ }
+
+ this.parent.WriteCpsr(tmpCPSR);
+
+ this.UnpackFlags();
+
+ // Check for branch back to Thumb Mode
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbMode = true;
+ return;
+ }
+
+ // Queue will be flushed since rd == 15, so adjust the PC
+ registers[15] -= 4;
+ }
+ break;
+
+ case OP_TST:
+ // MRS rd, CPSR
+ this.PackFlags();
+ registers[rd] = this.parent.CPSR;
+ break;
+ }
+
+ if (rd == 15)
+ {
+ // Flush the queue
+ this.FlushQueue();
+ }
+ }
+ }
+
+ private void DataProcessing()
+ {
+ // Special instruction
+ switch ((this.curInstruction >> 4) & 0xF)
+ {
+ case 0x9:
+ // Multiply or swap instructions
+ this.MultiplyOrSwap();
+ return;
+ case 0xB:
+ // Load/Store Unsigned halfword
+ this.LoadStoreHalfword();
+ return;
+ case 0xD:
+ // Load/Store Signed byte
+ this.LoadStoreHalfword();
+ return;
+ case 0xF:
+ // Load/Store Signed halfword
+ this.LoadStoreHalfword();
+ return;
+ }
+
+ this.DoDataProcessing(this.BarrelShifter(this.curInstruction));
+ }
+
+ private void DataProcessingImmed()
+ {
+ uint immed = this.curInstruction & 0xFF;
+ int rotateAmount = (int)(((this.curInstruction >> 8) & 0xF) * 2);
+
+ immed = (immed >> rotateAmount) | (immed << (32 - rotateAmount));
+
+ if (rotateAmount == 0)
+ {
+ this.shifterCarry = this.carry;
+ }
+ else
+ {
+ this.shifterCarry = (immed >> 31) & 1;
+ }
+
+ this.DoDataProcessing(immed);
+ }
+
+ private void LoadStore(uint offset)
+ {
+ uint rn = (this.curInstruction >> 16) & 0xF;
+ uint rd = (this.curInstruction >> 12) & 0xF;
+
+ uint address = registers[rn];
+
+ bool preIndexed = (this.curInstruction & (1 << 24)) == 1 << 24;
+ bool byteTransfer = (this.curInstruction & (1 << 22)) == 1 << 22;
+ bool writeback = (this.curInstruction & (1 << 21)) == 1 << 21;
+
+ // Add or subtract offset
+ if ((this.curInstruction & (1 << 23)) != 1 << 23) offset = (uint)-offset;
+
+ if (preIndexed)
+ {
+ address += offset;
+
+ if (writeback)
+ {
+ registers[rn] = address;
+ }
+ }
+
+ if ((this.curInstruction & (1 << 20)) == 1 << 20)
+ {
+ // Load
+ if (byteTransfer)
+ {
+ registers[rd] = this.memory.ReadU8(address);
+ }
+ else
+ {
+ registers[rd] = this.memory.ReadU32(address);
+ }
+
+ // ARM9 fix here
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (!preIndexed)
+ {
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ }
+ else
+ {
+ // Store
+ uint amount = registers[rd];
+ if (rd == 15) amount += 4;
+
+ if (byteTransfer)
+ {
+ this.memory.WriteU8(address, (byte)(amount & 0xFF));
+ }
+ else
+ {
+ this.memory.WriteU32(address, amount);
+ }
+
+ if (!preIndexed)
+ {
+ registers[rn] = address + offset;
+ }
+ }
+ }
+
+ private void LoadStoreImmediate()
+ {
+ this.LoadStore(this.curInstruction & 0xFFF);
+ }
+
+ private void LoadStoreRegister()
+ {
+ // The barrel shifter expects a 0 in bit 4 for immediate shifts, this is implicit in
+ // the meaning of the instruction, so it is fine
+ this.LoadStore(this.BarrelShifter(this.curInstruction));
+ }
+
+ private void LoadStoreMultiple()
+ {
+ uint rn = (this.curInstruction >> 16) & 0xF;
+
+ this.PackFlags();
+ uint curCpsr = this.parent.CPSR;
+
+ bool preIncrement = (this.curInstruction & (1 << 24)) != 0;
+ bool up = (this.curInstruction & (1 << 23)) != 0;
+ bool writeback = (this.curInstruction & (1 << 21)) != 0;
+
+ uint address;
+ uint bitsSet = 0;
+ for (int i = 0; i < 16; i++) if (((this.curInstruction >> i) & 1) != 0) bitsSet++;
+
+ if (preIncrement)
+ {
+ if (up)
+ {
+ // Increment before
+ address = this.registers[rn] + 4;
+ if (writeback) this.registers[rn] += bitsSet * 4;
+ }
+ else
+ {
+ // Decrement before
+ address = this.registers[rn] - (bitsSet * 4);
+ if (writeback) this.registers[rn] -= bitsSet * 4;
+ }
+ }
+ else
+ {
+ if (up)
+ {
+ // Increment after
+ address = this.registers[rn];
+ if (writeback) this.registers[rn] += bitsSet * 4;
+ }
+ else
+ {
+ // Decrement after
+ address = this.registers[rn] - (bitsSet * 4) + 4;
+ if (writeback) this.registers[rn] -= bitsSet * 4;
+ }
+ }
+
+ if ((this.curInstruction & (1 << 20)) != 0)
+ {
+ if ((this.curInstruction & (1 << 22)) != 0 && ((this.curInstruction >> 15) & 1) == 0)
+ {
+ // Switch to user mode temporarily
+ this.parent.WriteCpsr((curCpsr & ~0x1FU) | Arm7Processor.USR);
+ }
+
+ // Load multiple
+ for (int i = 0; i < 15; i++)
+ {
+ if (((this.curInstruction >> i) & 1) != 1) continue;
+ this.registers[i] = this.memory.ReadU32Aligned(address & (~0x3U));
+ address += 4;
+ }
+
+ if (((this.curInstruction >> 15) & 1) == 1)
+ {
+ // Arm9 fix here
+
+ this.registers[15] = this.memory.ReadU32Aligned(address & (~0x3U));
+
+ if ((this.curInstruction & (1 << 22)) != 0)
+ {
+ // Load the CPSR from the SPSR
+ if (this.parent.SPSRExists)
+ {
+ this.parent.WriteCpsr(this.parent.SPSR);
+ this.UnpackFlags();
+
+ // Check for branch back to Thumb Mode
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbMode = true;
+ this.registers[15] &= ~0x1U;
+ return;
+ }
+ }
+ }
+
+ this.registers[15] &= ~0x3U;
+ this.FlushQueue();
+ }
+ else
+ {
+ if ((this.curInstruction & (1 << 22)) != 0)
+ {
+ // Switch back to the correct mode
+ this.parent.WriteCpsr(curCpsr);
+ this.UnpackFlags();
+
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbMode = true;
+ return;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ((this.curInstruction & (1 << 22)) != 0)
+ {
+ // Switch to user mode temporarily
+ this.parent.WriteCpsr((curCpsr & ~0x1FU) | Arm7Processor.USR);
+ }
+
+ if (((this.curInstruction >> (int)rn) & 1) != 0 && writeback &&
+ (this.curInstruction & ~(0xFFFFFFFF << (int)rn)) == 0)
+ {
+ // If the lowest register is also the writeback, we use the original value
+ // Does anybody do this????
+ throw new Exception("Unhandled STM state");
+ }
+ else
+ {
+ // Store multiple
+ for (int i = 0; i < 15; i++)
+ {
+ if (((this.curInstruction >> i) & 1) == 0) continue;
+ this.memory.WriteU32(address, this.registers[i]);
+ address += 4;
+ }
+
+ if (((this.curInstruction >> 15) & 1) != 0)
+ {
+ this.memory.WriteU32(address, this.registers[15] + 4U);
+ }
+ }
+
+ if ((this.curInstruction & (1 << 22)) != 0)
+ {
+ // Switch back to the correct mode
+ this.parent.WriteCpsr(curCpsr);
+ this.UnpackFlags();
+ }
+ }
+ }
+
+ private void Branch()
+ {
+ if ((this.curInstruction & (1 << 24)) != 0)
+ {
+ this.registers[14] = (this.registers[15] - 4U) & ~3U;
+ }
+
+ uint branchOffset = this.curInstruction & 0x00FFFFFF;
+ if (branchOffset >> 23 == 1) branchOffset |= 0xFF000000;
+
+ this.registers[15] += branchOffset << 2;
+
+ this.FlushQueue();
+ }
+
+ private void CoprocessorLoadStore()
+ {
+ throw new Exception("Unhandled opcode - coproc load/store");
+ }
+
+ private void SoftwareInterrupt()
+ {
+ // Adjust PC for prefetch
+ this.registers[15] -= 4U;
+ this.parent.EnterException(Arm7Processor.SVC, 0x8, false, false);
+ }
+
+ private void MultiplyOrSwap()
+ {
+ if ((this.curInstruction & (1 << 24)) == 1 << 24)
+ {
+ // Swap instruction
+ uint rn = (this.curInstruction >> 16) & 0xF;
+ uint rd = (this.curInstruction >> 12) & 0xF;
+ uint rm = this.curInstruction & 0xF;
+
+ if ((this.curInstruction & (1 << 22)) != 0)
+ {
+ // SWPB
+ byte tmp = this.memory.ReadU8(registers[rn]);
+ this.memory.WriteU8(registers[rn], (byte)(registers[rm] & 0xFF));
+ registers[rd] = tmp;
+ }
+ else
+ {
+ // SWP
+ uint tmp = this.memory.ReadU32(registers[rn]);
+ this.memory.WriteU32(registers[rn], registers[rm]);
+ registers[rd] = tmp;
+ }
+ }
+ else
+ {
+ // Multiply instruction
+ switch ((this.curInstruction >> 21) & 0x7)
+ {
+ case 0:
+ case 1:
+ {
+ // Multiply/Multiply + Accumulate
+ uint rd = (this.curInstruction >> 16) & 0xF;
+ uint rn = registers[(this.curInstruction >> 12) & 0xF];
+ uint rs = (this.curInstruction >> 8) & 0xF;
+ uint rm = this.curInstruction & 0xF;
+
+ int cycles = 4;
+ // Multiply cycle calculations
+ if ((registers[rs] & 0xFFFFFF00) == 0 || (registers[rs] & 0xFFFFFF00) == 0xFFFFFF00)
+ {
+ cycles = 1;
+ }
+ else if ((registers[rs] & 0xFFFF0000) == 0 || (registers[rs] & 0xFFFF0000) == 0xFFFF0000)
+ {
+ cycles = 2;
+ }
+ else if ((registers[rs] & 0xFF000000) == 0 || (registers[rs] & 0xFF000000) == 0xFF000000)
+ {
+ cycles = 3;
+ }
+
+ registers[rd] = registers[rs] * registers[rm];
+ this.parent.Cycles -= cycles;
+
+ if ((this.curInstruction & (1 << 21)) == 1 << 21)
+ {
+ registers[rd] += rn;
+ this.parent.Cycles -= 1;
+ }
+
+ if ((this.curInstruction & (1 << 20)) == 1 << 20)
+ {
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ }
+ break;
+ }
+
+ case 2:
+ case 3:
+ throw new Exception("Invalid multiply");
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ {
+ // Multiply/Signed Multiply Long
+ uint rdhi = (this.curInstruction >> 16) & 0xF;
+ uint rdlo = (this.curInstruction >> 12) & 0xF;
+ uint rs = (this.curInstruction >> 8) & 0xF;
+ uint rm = this.curInstruction & 0xF;
+
+ int cycles = 5;
+ // Multiply cycle calculations
+ if ((registers[rs] & 0xFFFFFF00) == 0 || (registers[rs] & 0xFFFFFF00) == 0xFFFFFF00)
+ {
+ cycles = 2;
+ }
+ else if ((registers[rs] & 0xFFFF0000) == 0 || (registers[rs] & 0xFFFF0000) == 0xFFFF0000)
+ {
+ cycles = 3;
+ }
+ else if ((registers[rs] & 0xFF000000) == 0 || (registers[rs] & 0xFF000000) == 0xFF000000)
+ {
+ cycles = 4;
+ }
+
+ this.parent.Cycles -= cycles;
+
+ switch ((this.curInstruction >> 21) & 0x3)
+ {
+ case 0:
+ {
+ // UMULL
+ ulong result = ((ulong)registers[rm]) * registers[rs];
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+ break;
+ }
+ case 1:
+ {
+ // UMLAL
+ ulong accum = (((ulong)registers[rdhi]) << 32) | registers[rdlo];
+ ulong result = ((ulong)registers[rm]) * registers[rs];
+ result += accum;
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+ break;
+ }
+ case 2:
+ {
+ // SMULL
+ long result = ((long)((int)registers[rm])) * ((long)((int)registers[rs]));
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+ break;
+ }
+ case 3:
+ {
+ // SMLAL
+ long accum = (((long)((int)registers[rdhi])) << 32) | registers[rdlo];
+ long result = ((long)((int)registers[rm])) * ((long)((int)registers[rs]));
+ result += accum;
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+ break;
+ }
+ }
+
+ if ((this.curInstruction & (1 << 20)) == 1 << 20)
+ {
+ negative = registers[rdhi] >> 31;
+ zero = (registers[rdhi] == 0 && registers[rdlo] == 0) ? 1U : 0U;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ private void LoadStoreHalfword()
+ {
+ uint rn = (this.curInstruction >> 16) & 0xF;
+ uint rd = (this.curInstruction >> 12) & 0xF;
+
+ uint address = registers[rn];
+
+ bool preIndexed = (this.curInstruction & (1 << 24)) != 0;
+ bool byteTransfer = (this.curInstruction & (1 << 5)) == 0;
+ bool signedTransfer = (this.curInstruction & (1 << 6)) != 0;
+ bool writeback = (this.curInstruction & (1 << 21)) != 0;
+
+ uint offset;
+ if ((this.curInstruction & (1 << 22)) != 0)
+ {
+ // Immediate offset
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ }
+ else
+ {
+ // Register offset
+ offset = this.registers[this.curInstruction & 0xF];
+ }
+
+ // Add or subtract offset
+ if ((this.curInstruction & (1 << 23)) == 0) offset = (uint)-offset;
+
+ if (preIndexed)
+ {
+ address += offset;
+
+ if (writeback)
+ {
+ registers[rn] = address;
+ }
+ }
+
+ if ((this.curInstruction & (1 << 20)) != 0)
+ {
+ // Load
+ if (byteTransfer)
+ {
+ if (signedTransfer)
+ {
+ registers[rd] = this.memory.ReadU8(address);
+ if ((registers[rd] & 0x80) != 0)
+ {
+ registers[rd] |= 0xFFFFFF00;
+ }
+ }
+ else
+ {
+ registers[rd] = this.memory.ReadU8(address);
+ }
+ }
+ else
+ {
+ if (signedTransfer)
+ {
+ registers[rd] = this.memory.ReadU16(address);
+ if ((registers[rd] & 0x8000) != 0)
+ {
+ registers[rd] |= 0xFFFF0000;
+ }
+ }
+ else
+ {
+ registers[rd] = this.memory.ReadU16(address);
+ }
+ }
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (!preIndexed)
+ {
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ }
+ else
+ {
+ // Store
+ if (byteTransfer)
+ {
+ this.memory.WriteU8(address, (byte)(registers[rd] & 0xFF));
+ }
+ else
+ {
+ this.memory.WriteU16(address, (ushort)(registers[rd] & 0xFFFF));
+ }
+
+ if (!preIndexed)
+ {
+ registers[rn] = address + offset;
+ }
+ }
+ }
+ #endregion Opcodes
+
+ private void PackFlags()
+ {
+ this.parent.CPSR &= 0x0FFFFFFF;
+ this.parent.CPSR |= this.negative << Arm7Processor.N_BIT;
+ this.parent.CPSR |= this.zero << Arm7Processor.Z_BIT;
+ this.parent.CPSR |= this.carry << Arm7Processor.C_BIT;
+ this.parent.CPSR |= this.overflow << Arm7Processor.V_BIT;
+ }
+
+ private void UnpackFlags()
+ {
+ this.negative = (this.parent.CPSR >> Arm7Processor.N_BIT) & 1;
+ this.zero = (this.parent.CPSR >> Arm7Processor.Z_BIT) & 1;
+ this.carry = (this.parent.CPSR >> Arm7Processor.C_BIT) & 1;
+ this.overflow = (this.parent.CPSR >> Arm7Processor.V_BIT) & 1;
+ }
+
+ private void FlushQueue()
+ {
+ this.instructionQueue = this.memory.ReadU32(registers[15]);
+ registers[15] += 4;
+ }
+ }
+}
\ No newline at end of file
diff --git a/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/FastArmCore.cs b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/FastArmCore.cs
new file mode 100644
index 0000000000..c944036fb1
--- /dev/null
+++ b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/FastArmCore.cs
@@ -0,0 +1,9916 @@
+//#define ARM_DEBUG
+
+namespace GarboDev
+{
+ using System;
+
+ public partial class FastArmCore
+ {
+ private const uint COND_EQ = 0; // Z set
+ private const uint COND_NE = 1; // Z clear
+ private const uint COND_CS = 2; // C set
+ private const uint COND_CC = 3; // C clear
+ private const uint COND_MI = 4; // N set
+ private const uint COND_PL = 5; // N clear
+ private const uint COND_VS = 6; // V set
+ private const uint COND_VC = 7; // V clear
+ private const uint COND_HI = 8; // C set and Z clear
+ private const uint COND_LS = 9; // C clear or Z set
+ private const uint COND_GE = 10; // N equals V
+ private const uint COND_LT = 11; // N not equal to V
+ private const uint COND_GT = 12; // Z clear AND (N equals V)
+ private const uint COND_LE = 13; // Z set OR (N not equal to V)
+ private const uint COND_AL = 14; // Always
+ private const uint COND_NV = 15; // Never execute
+
+ private const uint OP_AND = 0x0;
+ private const uint OP_EOR = 0x1;
+ private const uint OP_SUB = 0x2;
+ private const uint OP_RSB = 0x3;
+ private const uint OP_ADD = 0x4;
+ private const uint OP_ADC = 0x5;
+ private const uint OP_SBC = 0x6;
+ private const uint OP_RSC = 0x7;
+ private const uint OP_TST = 0x8;
+ private const uint OP_TEQ = 0x9;
+ private const uint OP_CMP = 0xA;
+ private const uint OP_CMN = 0xB;
+ private const uint OP_ORR = 0xC;
+ private const uint OP_MOV = 0xD;
+ private const uint OP_BIC = 0xE;
+ private const uint OP_MVN = 0xF;
+
+ private delegate void ExecuteInstructionDelegate();
+ private ExecuteInstructionDelegate[] NormalOps = null;
+
+ private Arm7Processor parent;
+ private Memory memory;
+ private uint[] registers;
+
+ private uint instructionQueue;
+ private uint curInstruction;
+
+ // CPU flags
+ private uint zero, carry, negative, overflow;
+ private uint shifterCarry;
+
+ private bool thumbMode;
+
+ public FastArmCore(Arm7Processor parent, Memory memory)
+ {
+ this.parent = parent;
+ this.memory = memory;
+ this.registers = this.parent.Registers;
+
+ this.NormalOps = new ExecuteInstructionDelegate[8]
+ {
+ this.UndefinedInstruction,
+ this.UndefinedInstruction,
+ this.UndefinedInstruction,
+ this.UndefinedInstruction,
+ this.LoadStoreMultiple,
+ this.UndefinedInstruction,
+ this.CoprocessorLoadStore,
+ this.UndefinedInstruction
+ };
+
+ this.InitializeDispatchFunc();
+ }
+
+ public void BeginExecution()
+ {
+ this.FlushQueue();
+ }
+
+ public void Step()
+ {
+ this.UnpackFlags();
+
+ this.curInstruction = this.instructionQueue;
+ this.instructionQueue = this.memory.ReadU32(registers[15]);
+ registers[15] += 4;
+
+ uint cond = 0;
+ switch (this.curInstruction >> 28)
+ {
+ case COND_AL: cond = 1; break;
+ case COND_EQ: cond = zero; break;
+ case COND_NE: cond = 1 - zero; break;
+ case COND_CS: cond = carry; break;
+ case COND_CC: cond = 1 - carry; break;
+ case COND_MI: cond = negative; break;
+ case COND_PL: cond = 1 - negative; break;
+ case COND_VS: cond = overflow; break;
+ case COND_VC: cond = 1 - overflow; break;
+ case COND_HI: cond = carry & (1 - zero); break;
+ case COND_LS: cond = (1 - carry) | zero; break;
+ case COND_GE: cond = (1 - negative) ^ overflow; break;
+ case COND_LT: cond = negative ^ overflow; break;
+ case COND_GT: cond = (1 - zero) & (negative ^ (1 - overflow)); break;
+ case COND_LE: cond = (negative ^ overflow) | zero; break;
+ }
+
+ if (cond == 1)
+ {
+ // Execute the instruction
+ this.ExecuteInstruction((ushort)(((this.curInstruction >> 16) & 0xFF0) | ((this.curInstruction >> 4) & 0xF)));
+ }
+
+ this.parent.Cycles -= this.memory.WaitCycles;
+
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.parent.ReloadQueue();
+ }
+
+ this.PackFlags();
+ }
+
+ public void Execute()
+ {
+ this.UnpackFlags();
+ this.thumbMode = false;
+
+ while (this.parent.Cycles > 0)
+ {
+ this.curInstruction = this.instructionQueue;
+ this.instructionQueue = this.memory.ReadU32Aligned(registers[15]);
+ registers[15] += 4;
+
+ if ((this.curInstruction >> 28) == COND_AL)
+ {
+ this.fastDispatch[(ushort)(((this.curInstruction >> 16) & 0xFF0) | ((this.curInstruction >> 4) & 0xF))]();
+// this.ExecuteInstruction((ushort)(((this.curInstruction >> 16) & 0xFF0) | ((this.curInstruction >> 4) & 0xF)));
+ }
+ else
+ {
+ uint cond = 0;
+ switch (this.curInstruction >> 28)
+ {
+ case COND_EQ: cond = zero; break;
+ case COND_NE: cond = 1 - zero; break;
+ case COND_CS: cond = carry; break;
+ case COND_CC: cond = 1 - carry; break;
+ case COND_MI: cond = negative; break;
+ case COND_PL: cond = 1 - negative; break;
+ case COND_VS: cond = overflow; break;
+ case COND_VC: cond = 1 - overflow; break;
+ case COND_HI: cond = carry & (1 - zero); break;
+ case COND_LS: cond = (1 - carry) | zero; break;
+ case COND_GE: cond = (1 - negative) ^ overflow; break;
+ case COND_LT: cond = negative ^ overflow; break;
+ case COND_GT: cond = (1 - zero) & (negative ^ (1 - overflow)); break;
+ case COND_LE: cond = (negative ^ overflow) | zero; break;
+ }
+
+ if (cond == 1)
+ {
+ // Execute the instruction
+ this.fastDispatch[(ushort)(((this.curInstruction >> 16) & 0xFF0) | ((this.curInstruction >> 4) & 0xF))]();
+// this.ExecuteInstruction((ushort)(((this.curInstruction >> 16) & 0xFF0) | ((this.curInstruction >> 4) & 0xF)));
+ }
+ }
+
+ this.parent.Cycles -= this.memory.WaitCycles;
+
+ if (this.thumbMode)
+ {
+ this.parent.ReloadQueue();
+ break;
+ }
+
+#if ARM_DEBUG
+ // Check the current PC
+ if (this.parent.Breakpoints.ContainsKey(registers[15] - 4U))
+ {
+ this.parent.BreakpointHit = true;
+ break;
+ }
+#endif
+ }
+
+ this.PackFlags();
+ }
+
+ private void DataProcessingWriteToR15()
+ {
+ // Prevent writing if no SPSR exists (this will be true for USER or SYSTEM mode)
+ if (this.parent.SPSRExists) this.parent.WriteCpsr(this.parent.SPSR);
+ this.UnpackFlags();
+
+ // Check for branch back to Thumb Mode
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbMode = true;
+ return;
+ }
+
+ // Otherwise, flush the instruction queue
+ this.FlushQueue();
+ }
+
+ private uint BarrelShifterLslImmed()
+ {
+ // rm lsl immed
+ uint rm = registers[this.curInstruction & 0xF];
+ int amount = (int)((this.curInstruction >> 7) & 0x1F);
+
+ if (amount == 0)
+ {
+ this.shifterCarry = this.carry;
+ return rm;
+ }
+ else
+ {
+ this.shifterCarry = (rm >> (32 - amount)) & 1;
+ return rm << amount;
+ }
+ }
+
+ private uint BarrelShifterLslReg()
+ {
+ // rm lsl rs
+ uint rm = registers[this.curInstruction & 0xF];
+ uint rs = (this.curInstruction >> 8) & 0xF;
+
+ int amount;
+ if (rs == 15)
+ {
+ amount = (int)((registers[rs] + 0x4) & 0xFF);
+ }
+ else
+ {
+ amount = (int)(registers[rs] & 0xFF);
+ }
+
+ if ((this.curInstruction & 0xF) == 15)
+ {
+ rm += 4;
+ }
+
+ if (amount == 0)
+ {
+ this.shifterCarry = this.carry;
+ return rm;
+ }
+
+ if (amount < 32)
+ {
+ this.shifterCarry = (rm >> (32 - amount)) & 1;
+ return rm << amount;
+ }
+ else if (amount == 32)
+ {
+ this.shifterCarry = rm & 1;
+ return 0;
+ }
+ else
+ {
+ this.shifterCarry = 0;
+ return 0;
+ }
+ }
+
+ private uint BarrelShifterLsrImmed()
+ {
+ // rm lsr immed
+ uint rm = registers[this.curInstruction & 0xF];
+ int amount = (int)((this.curInstruction >> 7) & 0x1F);
+
+ if (amount == 0)
+ {
+ this.shifterCarry = (rm >> 31) & 1;
+ return 0;
+ }
+ else
+ {
+ this.shifterCarry = (rm >> (amount - 1)) & 1;
+ return rm >> amount;
+ }
+ }
+
+ private uint BarrelShifterLsrReg()
+ {
+ // rm lsr rs
+ uint rm = registers[this.curInstruction & 0xF];
+ uint rs = (this.curInstruction >> 8) & 0xF;
+
+ int amount;
+ if (rs == 15)
+ {
+ amount = (int)((registers[rs] + 0x4) & 0xFF);
+ }
+ else
+ {
+ amount = (int)(registers[rs] & 0xFF);
+ }
+
+ if ((this.curInstruction & 0xF) == 15)
+ {
+ rm += 4;
+ }
+
+ if (amount == 0)
+ {
+ this.shifterCarry = this.carry;
+ return rm;
+ }
+
+ if (amount < 32)
+ {
+ this.shifterCarry = (rm >> (amount - 1)) & 1;
+ return rm >> amount;
+ }
+ else if (amount == 32)
+ {
+ this.shifterCarry = (rm >> 31) & 1;
+ return 0;
+ }
+ else
+ {
+ this.shifterCarry = 0;
+ return 0;
+ }
+ }
+
+ private uint BarrelShifterAsrImmed()
+ {
+ // rm asr immed
+ uint rm = registers[this.curInstruction & 0xF];
+ int amount = (int)((this.curInstruction >> 7) & 0x1F);
+
+ if (amount == 0)
+ {
+ if ((rm & (1 << 31)) == 0)
+ {
+ this.shifterCarry = 0;
+ return 0;
+ }
+ else
+ {
+ this.shifterCarry = 1;
+ return 0xFFFFFFFF;
+ }
+ }
+ else
+ {
+ this.shifterCarry = (rm >> (amount - 1)) & 1;
+ return (uint)(((int)rm) >> amount);
+ }
+ }
+
+ private uint BarrelShifterAsrReg()
+ {
+ // rm asr rs
+ uint rm = registers[this.curInstruction & 0xF];
+ uint rs = (this.curInstruction >> 8) & 0xF;
+
+ int amount;
+ if (rs == 15)
+ {
+ amount = (int)((registers[rs] + 0x4) & 0xFF);
+ }
+ else
+ {
+ amount = (int)(registers[rs] & 0xFF);
+ }
+
+ if ((this.curInstruction & 0xF) == 15)
+ {
+ rm += 4;
+ }
+
+ if (amount == 0)
+ {
+ this.shifterCarry = this.carry;
+ return rm;
+ }
+
+ if (amount >= 32)
+ {
+ if ((rm & (1 << 31)) == 0)
+ {
+ this.shifterCarry = 0;
+ return 0;
+ }
+ else
+ {
+ this.shifterCarry = 1;
+ return 0xFFFFFFFF;
+ }
+ }
+ else
+ {
+ this.shifterCarry = (rm >> (amount - 1)) & 1;
+ return (uint)(((int)rm) >> amount);
+ }
+ }
+
+ private uint BarrelShifterRorImmed()
+ {
+ // rm ror immed
+ uint rm = registers[this.curInstruction & 0xF];
+ int amount = (int)((this.curInstruction >> 7) & 0x1F);
+
+ if (amount == 0)
+ {
+ // Actually an RRX
+ this.shifterCarry = rm & 1;
+ return (this.carry << 31) | (rm >> 1);
+ }
+ else
+ {
+ this.shifterCarry = (rm >> (amount - 1)) & 1;
+ return (rm >> amount) | (rm << (32 - amount));
+ }
+ }
+
+ private uint BarrelShifterRorReg()
+ {
+ // rm ror rs
+ uint rm = registers[this.curInstruction & 0xF];
+ uint rs = (this.curInstruction >> 8) & 0xF;
+
+ int amount;
+ if (rs == 15)
+ {
+ amount = (int)((registers[rs] + 0x4) & 0xFF);
+ }
+ else
+ {
+ amount = (int)(registers[rs] & 0xFF);
+ }
+
+ if ((this.curInstruction & 0xF) == 15)
+ {
+ rm += 4;
+ }
+
+ if (amount == 0)
+ {
+ this.shifterCarry = this.carry;
+ return rm;
+ }
+
+ if ((amount & 0x1F) == 0)
+ {
+ this.shifterCarry = (rm >> 31) & 1;
+ return rm;
+ }
+ else
+ {
+ amount &= 0x1F;
+ this.shifterCarry = (rm >> amount) & 1;
+ return (rm >> amount) | (rm << (32 - amount));
+ }
+ }
+
+ private uint BarrelShifterImmed()
+ {
+ uint immed = this.curInstruction & 0xFF;
+ int rotateAmount = (int)(((this.curInstruction >> 8) & 0xF) * 2);
+
+ if (rotateAmount == 0)
+ {
+ this.shifterCarry = this.carry;
+ return immed;
+ }
+ else
+ {
+ immed = (immed >> rotateAmount) | (immed << (32 - rotateAmount));
+ this.shifterCarry = (immed >> 31) & 1;
+ return immed;
+ }
+ }
+
+ private int MultiplyCycleCalculation(uint rs)
+ {
+ // Multiply cycle calculations
+ if ((registers[rs] & 0xFFFFFF00) == 0 || (registers[rs] & 0xFFFFFF00) == 0xFFFFFF00)
+ {
+ return 1;
+ }
+ else if ((registers[rs] & 0xFFFF0000) == 0 || (registers[rs] & 0xFFFF0000) == 0xFFFF0000)
+ {
+ return 2;
+ }
+ else if ((registers[rs] & 0xFF000000) == 0 || (registers[rs] & 0xFF000000) == 0xFF000000)
+ {
+ return 3;
+ }
+ return 4;
+ }
+
+ private void UndefinedInstruction()
+ {
+ // Do the undefined instruction dance here
+ throw new Exception("Undefined exception");
+ }
+
+ private void ExecuteInstruction(ushort op)
+ {
+ // Not emulating rn += 4 when register shift, in data operand when rn == pc
+
+ uint rn, rd, rs, rm, address, offset, shifterOperand, alu;
+ int cycles;
+
+ switch (op)
+ {
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // AND implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x000:
+ case 0x008:
+ // AND rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterLslImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x001:
+ // AND rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterLslReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x002:
+ case 0x00A:
+ // AND rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterLsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x003:
+ // AND rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterLsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x004:
+ case 0x00C:
+ // AND rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterAsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x005:
+ // AND rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterAsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x006:
+ case 0x00E:
+ // AND rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterRorImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x007:
+ // AND rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterRorReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x010:
+ case 0x018:
+ // ANDS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterLslImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x011:
+ // ANDS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterLslReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x012:
+ case 0x01A:
+ // ANDS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterLsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x013:
+ // ANDS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterLsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x014:
+ case 0x01C:
+ // ANDS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterAsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x015:
+ // ANDS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterAsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x016:
+ case 0x01E:
+ // ANDS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterRorImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x017:
+ // ANDS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterRorReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // Undefined instruction implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x00D: case 0x02D: case 0x04D: case 0x06D:
+ case 0x08D: case 0x0AD: case 0x0CD: case 0x0ED:
+ case 0x10D: case 0x12D: case 0x14D: case 0x16D:
+ case 0x18D: case 0x1AD: case 0x1CD: case 0x1ED:
+ case 0x00F: case 0x02F: case 0x04F: case 0x06F:
+ case 0x08F: case 0x0AF: case 0x0CF: case 0x0EF:
+ case 0x10F: case 0x12F: case 0x14F: case 0x16F:
+ case 0x18F: case 0x1AF: case 0x1CF: case 0x1EF:
+ UndefinedInstruction();
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // MUL implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x009:
+ // MUL rd, rm, rs
+ rd = (this.curInstruction >> 16) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs);
+
+ registers[rd] = registers[rs] * registers[rm];
+ this.parent.Cycles -= cycles;
+ break;
+
+ case 0x019:
+ // MULS rd, rm, rs
+ rd = (this.curInstruction >> 16) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs);
+
+ registers[rd] = registers[rs] * registers[rm];
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+
+ this.parent.Cycles -= cycles;
+ break;
+
+ case 0x029:
+ // MLA rd, rm, rs, rn
+ rd = (this.curInstruction >> 16) & 0xF;
+ rn = registers[(this.curInstruction >> 12) & 0xF];
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs);
+
+ registers[rd] = registers[rs] * registers[rm] + rn;
+ this.parent.Cycles -= cycles + 1;
+ break;
+
+ case 0x039:
+ // MLAS rd, rm, rs
+ rd = (this.curInstruction >> 16) & 0xF;
+ rn = registers[(this.curInstruction >> 12) & 0xF];
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs);
+
+ registers[rd] = registers[rs] * registers[rm] + rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+
+ this.parent.Cycles -= cycles + 1;
+ break;
+
+ case 0x089:
+ // UMULL rdlo, rdhi, rm, rs
+ {
+ uint rdhi = (this.curInstruction >> 16) & 0xF;
+ uint rdlo = (this.curInstruction >> 12) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs) + 1;
+
+ ulong result = ((ulong)registers[rm]) * registers[rs];
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+
+ this.parent.Cycles -= cycles;
+ }
+ break;
+
+ case 0x099:
+ // UMULLS rdlo, rdhi, rm, rs
+ {
+ uint rdhi = (this.curInstruction >> 16) & 0xF;
+ uint rdlo = (this.curInstruction >> 12) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs) + 1;
+
+ ulong result = ((ulong)registers[rm]) * registers[rs];
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+
+ negative = registers[rdhi] >> 31;
+ zero = (registers[rdhi] == 0 && registers[rdlo] == 0) ? 1U : 0U;
+
+ this.parent.Cycles -= cycles;
+ }
+ break;
+
+ case 0x0A9:
+ // UMLAL rdlo, rdhi, rm, rs
+ {
+ uint rdhi = (this.curInstruction >> 16) & 0xF;
+ uint rdlo = (this.curInstruction >> 12) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs) + 2;
+
+ ulong accum = (((ulong)registers[rdhi]) << 32) | registers[rdlo];
+ ulong result = ((ulong)registers[rm]) * registers[rs];
+ result += accum;
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+
+ this.parent.Cycles -= cycles;
+ }
+ break;
+
+ case 0x0B9:
+ // UMLALS rdlo, rdhi, rm, rs
+ {
+ uint rdhi = (this.curInstruction >> 16) & 0xF;
+ uint rdlo = (this.curInstruction >> 12) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs) + 2;
+
+ ulong accum = (((ulong)registers[rdhi]) << 32) | registers[rdlo];
+ ulong result = ((ulong)registers[rm]) * registers[rs];
+ result += accum;
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+
+ negative = registers[rdhi] >> 31;
+ zero = (registers[rdhi] == 0 && registers[rdlo] == 0) ? 1U : 0U;
+
+ this.parent.Cycles -= cycles;
+ }
+ break;
+
+ case 0x0C9:
+ // SMULL rdlo, rdhi, rm, rs
+ {
+ uint rdhi = (this.curInstruction >> 16) & 0xF;
+ uint rdlo = (this.curInstruction >> 12) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs) + 1;
+
+ long result = ((long)((int)registers[rm])) * ((long)((int)registers[rs]));
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+
+ this.parent.Cycles -= cycles;
+ }
+ break;
+
+ case 0x0D9:
+ // SMULLS rdlo, rdhi, rm, rs
+ {
+ uint rdhi = (this.curInstruction >> 16) & 0xF;
+ uint rdlo = (this.curInstruction >> 12) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs) + 1;
+
+ long result = ((long)((int)registers[rm])) * ((long)((int)registers[rs]));
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+
+ negative = registers[rdhi] >> 31;
+ zero = (registers[rdhi] == 0 && registers[rdlo] == 0) ? 1U : 0U;
+
+ this.parent.Cycles -= cycles;
+ }
+ break;
+
+ case 0x0E9:
+ // SMLAL rdlo, rdhi, rm, rs
+ {
+ uint rdhi = (this.curInstruction >> 16) & 0xF;
+ uint rdlo = (this.curInstruction >> 12) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs) + 2;
+
+ long accum = (((long)((int)registers[rdhi])) << 32) | registers[rdlo];
+ long result = ((long)((int)registers[rm])) * ((long)((int)registers[rs]));
+ result += accum;
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+
+ this.parent.Cycles -= cycles;
+ }
+ break;
+
+ case 0x0F9:
+ // SMLALS rdlo, rdhi, rm, rs
+ {
+ uint rdhi = (this.curInstruction >> 16) & 0xF;
+ uint rdlo = (this.curInstruction >> 12) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs) + 2;
+
+ long accum = (((long)((int)registers[rdhi])) << 32) | registers[rdlo];
+ long result = ((long)((int)registers[rm])) * ((long)((int)registers[rs]));
+ result += accum;
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+
+ negative = registers[rdhi] >> 31;
+ zero = (registers[rdhi] == 0 && registers[rdlo] == 0) ? 1U : 0U;
+
+ this.parent.Cycles -= cycles;
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // STRH implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x00B:
+ // STRH rd, [rn], -rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ this.memory.WriteU16(address, (ushort)(registers[rd] & 0xFFFF));
+ registers[rn] = address + offset;
+ break;
+
+ case 0x02B:
+ // Writeback bit set, instruction is unpredictable
+ // STRH rd, [rn], -rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ this.memory.WriteU16(address, (ushort)(registers[rd] & 0xFFFF));
+ registers[rn] = address + offset;
+ break;
+
+ case 0x04B:
+ // STRH rd, [rn], -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ this.memory.WriteU16(address, (ushort)(registers[rd] & 0xFFFF));
+ registers[rn] = address + offset;
+ break;
+
+ case 0x06B:
+ // Writeback bit set, instruction is unpredictable
+ // STRH rd, [rn], -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ this.memory.WriteU16(address, (ushort)(registers[rd] & 0xFFFF));
+ registers[rn] = address + offset;
+ break;
+
+ case 0x08B:
+ // STRH rd, [rn], rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ this.memory.WriteU16(address, (ushort)(registers[rd] & 0xFFFF));
+ registers[rn] = address + offset;
+ break;
+
+ case 0x0AB:
+ // Writeback bit set, instruction is unpredictable
+ // STRH rd, [rn], rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ this.memory.WriteU16(address, (ushort)(registers[rd] & 0xFFFF));
+ registers[rn] = address + offset;
+ break;
+
+ case 0x0CB:
+ // STRH rd, [rn], immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ this.memory.WriteU16(address, (ushort)(registers[rd] & 0xFFFF));
+ registers[rn] = address + offset;
+ break;
+
+ case 0x0EB:
+ // Writeback bit set, instruction is unpredictable
+ // STRH rd, [rn], immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ this.memory.WriteU16(address, (ushort)(registers[rd] & 0xFFFF));
+ registers[rn] = address + offset;
+ break;
+
+ case 0x10B:
+ // STRH rd, [rn, -rm]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ this.memory.WriteU16(registers[rn] + offset, (ushort)(registers[rd] & 0xFFFF));
+ break;
+
+ case 0x12B:
+ // STRH rd, [rn, -rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ this.memory.WriteU16(registers[rn], (ushort)(registers[rd] & 0xFFFF));
+ break;
+
+ case 0x14B:
+ // STRH rd, [rn, -immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ this.memory.WriteU16(registers[rn] + offset, (ushort)(registers[rd] & 0xFFFF));
+ break;
+
+ case 0x16B:
+ // STRH rd, [rn], -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ this.memory.WriteU16(registers[rn], (ushort)(registers[rd] & 0xFFFF));
+ break;
+
+ case 0x18B:
+ // STRH rd, [rn, rm]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ this.memory.WriteU16(registers[rn] + offset, (ushort)(registers[rd] & 0xFFFF));
+ break;
+
+ case 0x1AB:
+ // STRH rd, [rn, rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rn] += offset;
+ this.memory.WriteU16(registers[rn], (ushort)(registers[rd] & 0xFFFF));
+ break;
+
+ case 0x1CB:
+ // STRH rd, [rn, immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ this.memory.WriteU16(registers[rn] + offset, (ushort)(registers[rd] & 0xFFFF));
+ break;
+
+ case 0x1EB:
+ // STRH rd, [rn, immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rn] += offset;
+ this.memory.WriteU16(registers[rn], (ushort)(registers[rd] & 0xFFFF));
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // LDRH implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x01B:
+ // LDRH rd, [rn], -rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x03B:
+ // Writeback bit set, instruction is unpredictable
+ // LDRH rd, [rn], -rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x05B:
+ // LDRH rd, [rn], -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x07B:
+ // Writeback bit set, instruction is unpredictable
+ // LDRH rd, [rn], -rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x09B:
+ // LDRH rd, [rn], rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x0BB:
+ // Writeback bit set, instruction is unpredictable
+ // LDRH rd, [rn], rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x0DB:
+ // LDRH rd, [rn], immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rd] = this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x0FB:
+ // Writeback bit set, instruction is unpredictable
+ // LDRH rd, [rn], rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rd] = this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x11B:
+ // LDRH rd, [rn, -rm]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU16(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x13B:
+ // LDRH rd, [rn, -rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+
+ registers[rd] = this.memory.ReadU16(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x15B:
+ // LDRH rd, [rn, -immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU16(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x17B:
+ // LDRH rd, [rn, -rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU16(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x19B:
+ // LDRH rd, [rn, rm]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = this.memory.ReadU16(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1BB:
+ // LDRH rd, [rn, rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU16(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1DB:
+ // LDRH rd, [rn, immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rd] = this.memory.ReadU16(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1FB:
+ // LDRH rd, [rn, rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU16(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // LDRSB implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x01D:
+ // LDRSB rd, [rn], -rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x03D:
+ // Writeback bit set, instruction is unpredictable
+ // LDRSB rd, [rn], -rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x05D:
+ // LDRSB rd, [rn], -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x07D:
+ // Writeback bit set, instruction is unpredictable
+ // LDRSB rd, [rn], -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x09D:
+ // LDRSB rd, [rn], rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x0BD:
+ // Writeback bit set, instruction is unpredictable
+ // LDRSB rd, [rn], rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x0DD:
+ // LDRSB rd, [rn], immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x0FD:
+ // Writeback bit set, instruction is unpredictable
+ // LDRSB rd, [rn], immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x11D:
+ // LDRSB rd, [rn, -rm]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x13D:
+ // LDRSB rd, [rn, -rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x15D:
+ // LDRSB rd, [rn, -immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x17D:
+ // LDRSB rd, [rn, -immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x19D:
+ // LDRSB rd, [rn, rm]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1BD:
+ // LDRSB rd, [rn, rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1DD:
+ // LDRSB rd, [rn, immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1FD:
+ // LDRSB rd, [rn, immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rn] += offset;
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // LDRSH implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x01F:
+ // LDRSH rd, [rn], -rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x03F:
+ // Writeback bit set, instruction is unpredictable
+ // LDRSH rd, [rn], -rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x05F:
+ // LDRSH rd, [rn], -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x07F:
+ // Writeback bit set, instruction is unpredictable
+ // LDRSH rd, [rn], -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x09F:
+ // LDRSH rd, [rn], rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x0BF:
+ // Writeback bit set, instruction is unpredictable
+ // LDRSH rd, [rn], rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x0DF:
+ // LDRSH rd, [rn], immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x0FF:
+ // Writeback bit set, instruction is unpredictable
+ // LDRSH rd, [rn], immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ break;
+
+ case 0x11F:
+ // LDRSH rd, [rn, -rm]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x13F:
+ // LDRSH rd, [rn, -rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = (uint)(short)this.memory.ReadU16(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x15F:
+ // LDRSH rd, [rn, -immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x17F:
+ // LDRSH rd, [rn, -immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = (uint)(short)this.memory.ReadU16(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x19F:
+ // LDRSH rd, [rn, rm]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1BF:
+ // LDRSH rd, [rn, rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rn] += offset;
+ registers[rd] = (uint)(short)this.memory.ReadU16(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1DF:
+ // LDRSH rd, [rn, immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1FF:
+ // LDRSH rd, [rn, immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rn] += offset;
+ registers[rd] = (uint)(short)this.memory.ReadU16(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // EOR implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x020:
+ case 0x028:
+ // EOR rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterLslImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x021:
+ // EOR rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterLslReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x022:
+ case 0x02A:
+ // EOR rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterLsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x023:
+ // EOR rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterLsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x024:
+ case 0x02C:
+ // EOR rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterAsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x025:
+ // EOR rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterAsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x026:
+ case 0x02E:
+ // EOR rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterRorImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x027:
+ // EOR rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterRorReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x030:
+ case 0x038:
+ // EORS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterLslImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x031:
+ // EORS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterLslReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x032:
+ case 0x03A:
+ // EORS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterLsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x033:
+ // EORS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterLsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x034:
+ case 0x03C:
+ // EORS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterAsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x035:
+ // EORS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterAsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x036:
+ case 0x03E:
+ // EORS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterRorImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x037:
+ // EORS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterRorReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // SUB implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x040:
+ case 0x048:
+ // SUB rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterLslImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x041:
+ // SUB rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterLslReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x042:
+ case 0x04A:
+ // SUB rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterLsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x043:
+ // SUB rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterLsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x044:
+ case 0x04C:
+ // SUB rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterAsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x045:
+ // SUB rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterAsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x046:
+ case 0x04E:
+ // SUB rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterRorImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x047:
+ // SUB rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterRorReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x050:
+ case 0x058:
+ // SUBS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslImmed();
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x051:
+ // SUBS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslReg();
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x052:
+ case 0x05A:
+ // SUBS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrImmed();
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x053:
+ // SUBS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrReg();
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x054:
+ case 0x05C:
+ // SUBS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrImmed();
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x055:
+ // SUBS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrReg();
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x056:
+ case 0x05E:
+ // SUBS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorImmed();
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x057:
+ // SUBS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorReg();
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // RSB implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x060:
+ case 0x068:
+ // RSB rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLslImmed() - rn;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x061:
+ // RSB rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLslReg() - rn;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x062:
+ case 0x06A:
+ // RSB rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLsrImmed() - rn;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x063:
+ // RSB rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLsrReg() - rn;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x064:
+ case 0x06C:
+ // RSB rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterAsrImmed() - rn;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x065:
+ // RSB rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterAsrReg() - rn;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x066:
+ case 0x06E:
+ // RSB rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterRorImmed() - rn;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x067:
+ // RSB rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterRorReg() - rn;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x070:
+ case 0x078:
+ // RSBS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslImmed();
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x071:
+ // RSBS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslReg();
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x072:
+ case 0x07A:
+ // RSBS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrImmed();
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x073:
+ // RSBS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrReg();
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x074:
+ case 0x07C:
+ // RSBS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrImmed();
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x075:
+ // RSBS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrReg();
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x076:
+ case 0x07E:
+ // RSBS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorImmed();
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x077:
+ // RSBS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorReg();
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // ADD implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x080:
+ case 0x088:
+ // ADD rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterLslImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x081:
+ // ADD rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterLslReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x082:
+ case 0x08A:
+ // ADD rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterLsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x083:
+ // ADD rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterLsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x084:
+ case 0x08C:
+ // ADD rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterAsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x085:
+ // ADD rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterAsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x086:
+ case 0x08E:
+ // ADD rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterRorImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x087:
+ // ADD rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterRorReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x090:
+ case 0x098:
+ // ADDS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslImmed();
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x091:
+ // ADDS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslReg();
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x092:
+ case 0x09A:
+ // ADDS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrImmed();
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x093:
+ // ADDS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrReg();
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x094:
+ case 0x09C:
+ // ADDS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrImmed();
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x095:
+ // ADDS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrReg();
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x096:
+ case 0x09E:
+ // ADDS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorImmed();
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x097:
+ // ADDS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorReg();
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // ADC implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x0A0:
+ case 0x0A8:
+ // ADC rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterLslImmed() + carry;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0A1:
+ // ADC rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterLslReg() + carry;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0A2:
+ case 0x0AA:
+ // ADC rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterLsrImmed() + carry;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0A3:
+ // ADC rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterLsrReg() + carry;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0A4:
+ case 0x0AC:
+ // ADC rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterAsrImmed() + carry;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0A5:
+ // ADC rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterAsrReg() + carry;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0A6:
+ case 0x0AE:
+ // ADC rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterRorImmed() + carry;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0A7:
+ // ADC rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterRorReg() + carry;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0B0:
+ case 0x0B8:
+ // ADCS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslImmed();
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0B1:
+ // ADCS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslReg();
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0B2:
+ case 0x0BA:
+ // ADCS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrImmed();
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0B3:
+ // ADCS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrReg();
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0B4:
+ case 0x0BC:
+ // ADCS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrImmed();
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0B5:
+ // ADCS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrReg();
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0B6:
+ case 0x0BE:
+ // ADCS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorImmed();
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0B7:
+ // ADCS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorReg();
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // SBC implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x0C0:
+ case 0x0C8:
+ // SBC rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterLslImmed() - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0C1:
+ // SBC rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterLslReg() - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0C2:
+ case 0x0CA:
+ // SBC rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterLsrImmed() - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0C3:
+ // SBC rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterLsrReg() - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0C4:
+ case 0x0CC:
+ // SBC rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterAsrImmed() - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0C5:
+ // SBC rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterAsrReg() - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0C6:
+ case 0x0CE:
+ // SBC rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterRorImmed() - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0C7:
+ // SBC rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterRorReg() - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0D0:
+ case 0x0D8:
+ // SBCS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslImmed();
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0D1:
+ // SBCS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslReg();
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0D2:
+ case 0x0DA:
+ // SBCS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrImmed();
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0D3:
+ // SBCS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrReg();
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0D4:
+ case 0x0DC:
+ // SBCS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrImmed();
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0D5:
+ // SBCS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrReg();
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0D6:
+ case 0x0DE:
+ // SBCS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorImmed();
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0D7:
+ // SBCS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorReg();
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // RSC implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x0E0:
+ case 0x0E8:
+ // RSC rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLslImmed() - rn - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0E1:
+ // RSC rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLslReg() - rn - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0E2:
+ case 0x0EA:
+ // RSC rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLsrImmed() - rn - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0E3:
+ // RSC rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLsrReg() - rn - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0E4:
+ case 0x0EC:
+ // RSC rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterAsrImmed() - rn - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0E5:
+ // RSC rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterAsrReg() - rn - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0E6:
+ case 0x0EE:
+ // RSC rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterRorImmed() - rn - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0E7:
+ // RSC rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterRorReg() - rn - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x0F0:
+ case 0x0F8:
+ // RSCS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslImmed();
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0F1:
+ // RSCS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslReg();
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0F2:
+ case 0x0FA:
+ // RSCS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrImmed();
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0F3:
+ // RSCS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrReg();
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0F4:
+ case 0x0FC:
+ // RSCS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrImmed();
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0F5:
+ // RSCS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrReg();
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0F6:
+ case 0x0FE:
+ // RSCS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorImmed();
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x0F7:
+ // RSCS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorReg();
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // Misc. instructions (MSR, MRS, SWP, BX)
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x109:
+ // SWP rd, rm, [rn]
+ {
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+ rm = this.curInstruction & 0xF;
+ uint tmp = this.memory.ReadU32(registers[rn]);
+ this.memory.WriteU32(registers[rn], registers[rm]);
+ registers[rd] = tmp;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ break;
+
+ case 0x149:
+ // SWPB rd, rm, [rn]
+ {
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ byte tmp = this.memory.ReadU8(registers[rn]);
+ this.memory.WriteU8(registers[rn], (byte)(registers[rm] & 0xFF));
+ registers[rd] = tmp;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ break;
+
+ case 0x100:
+ // MRS rd, cpsr
+ rd = (this.curInstruction >> 12) & 0xF;
+ this.PackFlags();
+ registers[rd] = this.parent.CPSR;
+ break;
+
+ case 0x140:
+ // MRS rd, spsr
+ rd = (this.curInstruction >> 12) & 0xF;
+ if (this.parent.SPSRExists) registers[rd] = this.parent.SPSR;
+ break;
+
+ case 0x120:
+ // MSR cpsr, rm
+ {
+ rm = registers[this.curInstruction & 0xF];
+ bool userMode = (this.parent.CPSR & 0x1F) == Arm7Processor.USR;
+
+ this.PackFlags();
+
+ uint tmpCPSR = this.parent.CPSR;
+
+ if ((this.curInstruction & (1 << 16)) == 1 << 16 && !userMode)
+ {
+ tmpCPSR &= 0xFFFFFF00;
+ tmpCPSR |= rm & 0x000000FF;
+ }
+ if ((this.curInstruction & (1 << 17)) == 1 << 17 && !userMode)
+ {
+ tmpCPSR &= 0xFFFF00FF;
+ tmpCPSR |= rm & 0x0000FF00;
+ }
+ if ((this.curInstruction & (1 << 18)) == 1 << 18 && !userMode)
+ {
+ tmpCPSR &= 0xFF00FFFF;
+ tmpCPSR |= rm & 0x00FF0000;
+ }
+ if ((this.curInstruction & (1 << 19)) == 1 << 19)
+ {
+ tmpCPSR &= 0x00FFFFFF;
+ tmpCPSR |= rm & 0xFF000000;
+ }
+
+ this.parent.WriteCpsr(tmpCPSR);
+
+ this.UnpackFlags();
+
+ // Check for branch back to Thumb Mode
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbMode = true;
+ return;
+ }
+ }
+ break;
+
+ case 0x160:
+ // MSR spsr, rm
+ if (this.parent.SPSRExists)
+ {
+ rm = registers[this.curInstruction & 0xF];
+ if ((this.curInstruction & (1 << 16)) == 1 << 16)
+ {
+ this.parent.SPSR &= 0xFFFFFF00;
+ this.parent.SPSR |= rm & 0x000000FF;
+ }
+ if ((this.curInstruction & (1 << 17)) == 1 << 17)
+ {
+ this.parent.SPSR &= 0xFFFF00FF;
+ this.parent.SPSR |= rm & 0x0000FF00;
+ }
+ if ((this.curInstruction & (1 << 18)) == 1 << 18)
+ {
+ this.parent.SPSR &= 0xFF00FFFF;
+ this.parent.SPSR |= rm & 0x00FF0000;
+ }
+ if ((this.curInstruction & (1 << 19)) == 1 << 19)
+ {
+ this.parent.SPSR &= 0x00FFFFFF;
+ this.parent.SPSR |= rm & 0xFF000000;
+ }
+ }
+ break;
+
+ case 0x320:
+ // MSR cpsr, immed
+ {
+ uint immed = this.curInstruction & 0xFF;
+ int rotateAmount = (int)(((this.curInstruction >> 8) & 0xF) * 2);
+
+ immed = (immed >> rotateAmount) | (immed << (32 - rotateAmount));
+
+ bool userMode = (this.parent.CPSR & 0x1F) == Arm7Processor.USR;
+
+ this.PackFlags();
+
+ uint tmpCPSR = this.parent.CPSR;
+
+ if ((this.curInstruction & (1 << 16)) == 1 << 16 && !userMode)
+ {
+ tmpCPSR &= 0xFFFFFF00;
+ tmpCPSR |= immed & 0x000000FF;
+ }
+ if ((this.curInstruction & (1 << 17)) == 1 << 17 && !userMode)
+ {
+ tmpCPSR &= 0xFFFF00FF;
+ tmpCPSR |= immed & 0x0000FF00;
+ }
+ if ((this.curInstruction & (1 << 18)) == 1 << 18 && !userMode)
+ {
+ tmpCPSR &= 0xFF00FFFF;
+ tmpCPSR |= immed & 0x00FF0000;
+ }
+ if ((this.curInstruction & (1 << 19)) == 1 << 19)
+ {
+ tmpCPSR &= 0x00FFFFFF;
+ tmpCPSR |= immed & 0xFF000000;
+ }
+
+ this.parent.WriteCpsr(tmpCPSR);
+
+ this.UnpackFlags();
+
+ // Check for branch back to Thumb Mode
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbMode = true;
+ return;
+ }
+ }
+ break;
+
+ case 0x360:
+ // MSR spsr, immed
+ if (this.parent.SPSRExists)
+ {
+ uint immed = this.curInstruction & 0xFF;
+ int rotateAmount = (int)(((this.curInstruction >> 8) & 0xF) * 2);
+
+ immed = (immed >> rotateAmount) | (immed << (32 - rotateAmount));
+
+ if ((this.curInstruction & (1 << 16)) == 1 << 16)
+ {
+ this.parent.SPSR &= 0xFFFFFF00;
+ this.parent.SPSR |= immed & 0x000000FF;
+ }
+ if ((this.curInstruction & (1 << 17)) == 1 << 17)
+ {
+ this.parent.SPSR &= 0xFFFF00FF;
+ this.parent.SPSR |= immed & 0x0000FF00;
+ }
+ if ((this.curInstruction & (1 << 18)) == 1 << 18)
+ {
+ this.parent.SPSR &= 0xFF00FFFF;
+ this.parent.SPSR |= immed & 0x00FF0000;
+ }
+ if ((this.curInstruction & (1 << 19)) == 1 << 19)
+ {
+ this.parent.SPSR &= 0x00FFFFFF;
+ this.parent.SPSR |= immed & 0xFF000000;
+ }
+ }
+ break;
+
+ case 0x121:
+ // BX rm
+ rm = this.curInstruction & 0xf;
+
+ this.PackFlags();
+
+ this.parent.CPSR &= ~Arm7Processor.T_MASK;
+ this.parent.CPSR |= (registers[rm] & 1) << Arm7Processor.T_BIT;
+
+ registers[15] = registers[rm] & (~1U);
+
+ this.UnpackFlags();
+
+ // Check for branch back to Thumb Mode
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbMode = true;
+ return;
+ }
+
+ this.FlushQueue();
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // TST implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x110:
+ case 0x118:
+ // TSTS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn & BarrelShifterLslImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case 0x111:
+ // TSTS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn & BarrelShifterLslReg();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case 0x112:
+ case 0x11A:
+ // TSTS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn & BarrelShifterLsrImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case 0x113:
+ // TSTS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn & BarrelShifterLsrReg();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case 0x114:
+ case 0x11C:
+ // TSTS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn & BarrelShifterAsrImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case 0x115:
+ // TSTS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn & BarrelShifterAsrReg();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case 0x116:
+ case 0x11E:
+ // TSTS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn & BarrelShifterRorImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case 0x117:
+ // TSTS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = rn & BarrelShifterRorReg();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // TEQ implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x130:
+ case 0x138:
+ // TEQS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn ^ BarrelShifterLslImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case 0x131:
+ // TEQS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn ^ BarrelShifterLslReg();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case 0x132:
+ case 0x13A:
+ // TEQS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn ^ BarrelShifterLsrImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case 0x133:
+ // TEQS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn ^ BarrelShifterLsrReg();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case 0x134:
+ case 0x13C:
+ // TEQS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn ^ BarrelShifterAsrImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case 0x135:
+ // TEQS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn ^ BarrelShifterAsrReg();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case 0x136:
+ case 0x13E:
+ // TEQS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn ^ BarrelShifterRorImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case 0x137:
+ // TEQS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = rn ^ BarrelShifterRorReg();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // CMP implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x150:
+ case 0x158:
+ // CMP rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterLslImmed();
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ break;
+
+ case 0x151:
+ // CMP rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterLslReg();
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ break;
+
+ case 0x152:
+ case 0x15A:
+ // CMP rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterLsrImmed();
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ break;
+
+ case 0x153:
+ // CMP rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterLsrReg();
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ break;
+
+ case 0x154:
+ case 0x15C:
+ // CMP rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterAsrImmed();
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ break;
+
+ case 0x155:
+ // CMP rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterAsrReg();
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ break;
+
+ case 0x156:
+ case 0x15E:
+ // CMP rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterRorImmed();
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ break;
+
+ case 0x157:
+ // CMP rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterRorReg();
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // CMN implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x170:
+ case 0x178:
+ // CMN rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterLslImmed();
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ break;
+
+ case 0x171:
+ // CMN rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterLslReg();
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ break;
+
+ case 0x172:
+ case 0x17A:
+ // CMN rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterLsrImmed();
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ break;
+
+ case 0x173:
+ // CMN rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterLsrReg();
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ break;
+
+ case 0x174:
+ case 0x17C:
+ // CMN rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterAsrImmed();
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ break;
+
+ case 0x175:
+ // CMN rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterAsrReg();
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ break;
+
+ case 0x176:
+ case 0x17E:
+ // CMN rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterRorImmed();
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ break;
+
+ case 0x177:
+ // CMN rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterRorReg();
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // ORR implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x180:
+ case 0x188:
+ // ORR rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterLslImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x181:
+ // ORR rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterLslReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x182:
+ case 0x18A:
+ // ORR rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterLsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x183:
+ // ORR rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterLsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x184:
+ case 0x18C:
+ // ORR rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterAsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x185:
+ // ORR rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterAsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x186:
+ case 0x18E:
+ // ORR rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterRorImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x187:
+ // ORR rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterRorReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x190:
+ case 0x198:
+ // ORRS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterLslImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x191:
+ // ORRS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterLslReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x192:
+ case 0x19A:
+ // ORRS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterLsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x193:
+ // ORRS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterLsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x194:
+ case 0x19C:
+ // ORRS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterAsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x195:
+ // ORRS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterAsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x196:
+ case 0x19E:
+ // ORRS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterRorImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x197:
+ // ORRS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterRorReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // MOV implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x1A0:
+ case 0x1A8:
+ // MOV rd, rm lsl immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLslImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1A1:
+ // MOV rd, rm lsl rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLslReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1A2:
+ case 0x1AA:
+ // MOV rd, rm lsr immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1A3:
+ // MOV rd, rm lsr rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1A4:
+ case 0x1AC:
+ // MOV rd, rm asr immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterAsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1A5:
+ // MOV rd, rm asr rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterAsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1A6:
+ case 0x1AE:
+ // MOV rd, rm ror immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterRorImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1A7:
+ // MOV rd, rm ror rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterRorReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1B0:
+ case 0x1B8:
+ // MOVS rd, rm lsl immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLslImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1B1:
+ // MOVS rd, rm lsl rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLslReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1B2:
+ case 0x1BA:
+ // MOVS rd, rm lsr immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1B3:
+ // MOVS rd, rn, rm lsr rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1B4:
+ case 0x1BC:
+ // MOVS rd, rn, rm asr immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterAsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1B5:
+ // MOVS rd, rn, rm asr rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterAsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1B6:
+ case 0x1BE:
+ // MOVS rd, rn, rm ror immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterRorImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1B7:
+ // MOVS rd, rn, rm ror rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterRorReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // BIC implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x1C0:
+ case 0x1C8:
+ // BIC rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterLslImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1C1:
+ // BIC rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterLslReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1C2:
+ case 0x1CA:
+ // BIC rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterLsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1C3:
+ // BIC rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterLsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1C4:
+ case 0x1CC:
+ // BIC rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterAsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1C5:
+ // BIC rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterAsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1C6:
+ case 0x1CE:
+ // BIC rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterRorImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1C7:
+ // BIC rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterRorReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1D0:
+ case 0x1D8:
+ // BICS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterLslImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1D1:
+ // BICS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterLslReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1D2:
+ case 0x1DA:
+ // BICS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterLsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1D3:
+ // BICS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterLsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1D4:
+ case 0x1DC:
+ // BICS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterAsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1D5:
+ // BICS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterAsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1D6:
+ case 0x1DE:
+ // BICS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterRorImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1D7:
+ // BICS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterRorReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // MVN implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x1E0:
+ case 0x1E8:
+ // MVN rd, rm lsl immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterLslImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1E1:
+ // MVN rd, rm lsl rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterLslReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1E2:
+ case 0x1EA:
+ // MVN rd, rm lsr immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterLsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1E3:
+ // MVN rd, rm lsr rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterLsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1E4:
+ case 0x1EC:
+ // MVN rd, rm asr immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterAsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1E5:
+ // MVN rd, rm asr rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterAsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1E6:
+ case 0x1EE:
+ // MVN rd, rm ror immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterRorImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1E7:
+ // MVN rd, rm ror rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterRorReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x1F0:
+ case 0x1F8:
+ // MVNS rd, rm lsl immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterLslImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1F1:
+ // MVNS rd, rm lsl rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterLslReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1F2:
+ case 0x1FA:
+ // MVNS rd, rm lsr immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterLsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1F3:
+ // MVNS rd, rn, rm lsr rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterLsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1F4:
+ case 0x1FC:
+ // MVNS rd, rn, rm asr immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterAsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1F5:
+ // MVNS rd, rn, rm asr rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterAsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1F6:
+ case 0x1FE:
+ // MVNS rd, rn, rm ror immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterRorImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x1F7:
+ // MVNS rd, rn, rm ror rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterRorReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // Data processing immediate operand implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x200: case 0x201: case 0x202: case 0x203: case 0x204: case 0x205: case 0x206: case 0x207:
+ case 0x208: case 0x209: case 0x20A: case 0x20B: case 0x20C: case 0x20D: case 0x20E: case 0x20F:
+ // AND rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn & BarrelShifterImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x210: case 0x211: case 0x212: case 0x213: case 0x214: case 0x215: case 0x216: case 0x217:
+ case 0x218: case 0x219: case 0x21A: case 0x21B: case 0x21C: case 0x21D: case 0x21E: case 0x21F:
+ // ANDS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn & BarrelShifterImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x220: case 0x221: case 0x222: case 0x223: case 0x224: case 0x225: case 0x226: case 0x227:
+ case 0x228: case 0x229: case 0x22A: case 0x22B: case 0x22C: case 0x22D: case 0x22E: case 0x22F:
+ // EOR rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn ^ BarrelShifterImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x230: case 0x231: case 0x232: case 0x233: case 0x234: case 0x235: case 0x236: case 0x237:
+ case 0x238: case 0x239: case 0x23A: case 0x23B: case 0x23C: case 0x23D: case 0x23E: case 0x23F:
+ // EORS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn ^ BarrelShifterImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x240: case 0x241: case 0x242: case 0x243: case 0x244: case 0x245: case 0x246: case 0x247:
+ case 0x248: case 0x249: case 0x24A: case 0x24B: case 0x24C: case 0x24D: case 0x24E: case 0x24F:
+ // SUB rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn - BarrelShifterImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x250: case 0x251: case 0x252: case 0x253: case 0x254: case 0x255: case 0x256: case 0x257:
+ case 0x258: case 0x259: case 0x25A: case 0x25B: case 0x25C: case 0x25D: case 0x25E: case 0x25F:
+ // SUBS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterImmed();
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x260: case 0x261: case 0x262: case 0x263: case 0x264: case 0x265: case 0x266: case 0x267:
+ case 0x268: case 0x269: case 0x26A: case 0x26B: case 0x26C: case 0x26D: case 0x26E: case 0x26F:
+ // RSB rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = BarrelShifterImmed() - rn;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x270: case 0x271: case 0x272: case 0x273: case 0x274: case 0x275: case 0x276: case 0x277:
+ case 0x278: case 0x279: case 0x27A: case 0x27B: case 0x27C: case 0x27D: case 0x27E: case 0x27F:
+ // RSBS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterImmed();
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x280: case 0x281: case 0x282: case 0x283: case 0x284: case 0x285: case 0x286: case 0x287:
+ case 0x288: case 0x289: case 0x28A: case 0x28B: case 0x28C: case 0x28D: case 0x28E: case 0x28F:
+ // ADD rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn + BarrelShifterImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x290: case 0x291: case 0x292: case 0x293: case 0x294: case 0x295: case 0x296: case 0x297:
+ case 0x298: case 0x299: case 0x29A: case 0x29B: case 0x29C: case 0x29D: case 0x29E: case 0x29F:
+ // ADDS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterImmed();
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x2A0: case 0x2A1: case 0x2A2: case 0x2A3: case 0x2A4: case 0x2A5: case 0x2A6: case 0x2A7:
+ case 0x2A8: case 0x2A9: case 0x2AA: case 0x2AB: case 0x2AC: case 0x2AD: case 0x2AE: case 0x2AF:
+ // ADC rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn + BarrelShifterImmed() + carry;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x2B0: case 0x2B1: case 0x2B2: case 0x2B3: case 0x2B4: case 0x2B5: case 0x2B6: case 0x2B7:
+ case 0x2B8: case 0x2B9: case 0x2BA: case 0x2BB: case 0x2BC: case 0x2BD: case 0x2BE: case 0x2BF:
+ // ADCS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterImmed();
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x2C0: case 0x2C1: case 0x2C2: case 0x2C3: case 0x2C4: case 0x2C5: case 0x2C6: case 0x2C7:
+ case 0x2C8: case 0x2C9: case 0x2CA: case 0x2CB: case 0x2CC: case 0x2CD: case 0x2CE: case 0x2CF:
+ // SBC rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn - BarrelShifterImmed() - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x2D0: case 0x2D1: case 0x2D2: case 0x2D3: case 0x2D4: case 0x2D5: case 0x2D6: case 0x2D7:
+ case 0x2D8: case 0x2D9: case 0x2DA: case 0x2DB: case 0x2DC: case 0x2DD: case 0x2DE: case 0x2DF:
+ // SBCS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterImmed();
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x2E0: case 0x2E1: case 0x2E2: case 0x2E3: case 0x2E4: case 0x2E5: case 0x2E6: case 0x2E7:
+ case 0x2E8: case 0x2E9: case 0x2EA: case 0x2EB: case 0x2EC: case 0x2ED: case 0x2EE: case 0x2EF:
+ // RSC rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = BarrelShifterImmed() - rn - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x2F0: case 0x2F1: case 0x2F2: case 0x2F3: case 0x2F4: case 0x2F5: case 0x2F6: case 0x2F7:
+ case 0x2F8: case 0x2F9: case 0x2FA: case 0x2FB: case 0x2FC: case 0x2FD: case 0x2FE: case 0x2FF:
+ // RSCS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterImmed();
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x310: case 0x311: case 0x312: case 0x313: case 0x314: case 0x315: case 0x316: case 0x317:
+ case 0x318: case 0x319: case 0x31A: case 0x31B: case 0x31C: case 0x31D: case 0x31E: case 0x31F:
+ // TSTS rn, immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn & BarrelShifterImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case 0x330: case 0x331: case 0x332: case 0x333: case 0x334: case 0x335: case 0x336: case 0x337:
+ case 0x338: case 0x339: case 0x33A: case 0x33B: case 0x33C: case 0x33D: case 0x33E: case 0x33F:
+ // TEQS rn, immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn ^ BarrelShifterImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case 0x350: case 0x351: case 0x352: case 0x353: case 0x354: case 0x355: case 0x356: case 0x357:
+ case 0x358: case 0x359: case 0x35A: case 0x35B: case 0x35C: case 0x35D: case 0x35E: case 0x35F:
+ // CMP rn, immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterImmed();
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ break;
+
+ case 0x370: case 0x371: case 0x372: case 0x373: case 0x374: case 0x375: case 0x376: case 0x377:
+ case 0x378: case 0x379: case 0x37A: case 0x37B: case 0x37C: case 0x37D: case 0x37E: case 0x37F:
+ // CMN rn, immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterImmed();
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ break;
+
+ case 0x380: case 0x381: case 0x382: case 0x383: case 0x384: case 0x385: case 0x386: case 0x387:
+ case 0x388: case 0x389: case 0x38A: case 0x38B: case 0x38C: case 0x38D: case 0x38E: case 0x38F:
+ // ORR rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn | BarrelShifterImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x390: case 0x391: case 0x392: case 0x393: case 0x394: case 0x395: case 0x396: case 0x397:
+ case 0x398: case 0x399: case 0x39A: case 0x39B: case 0x39C: case 0x39D: case 0x39E: case 0x39F:
+ // ORRS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn | BarrelShifterImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x3A0: case 0x3A1: case 0x3A2: case 0x3A3: case 0x3A4: case 0x3A5: case 0x3A6: case 0x3A7:
+ case 0x3A8: case 0x3A9: case 0x3AA: case 0x3AB: case 0x3AC: case 0x3AD: case 0x3AE: case 0x3AF:
+ // MOV rd, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x3B0: case 0x3B1: case 0x3B2: case 0x3B3: case 0x3B4: case 0x3B5: case 0x3B6: case 0x3B7:
+ case 0x3B8: case 0x3B9: case 0x3BA: case 0x3BB: case 0x3BC: case 0x3BD: case 0x3BE: case 0x3BF:
+ // MOVS rd, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x3C0: case 0x3C1: case 0x3C2: case 0x3C3: case 0x3C4: case 0x3C5: case 0x3C6: case 0x3C7:
+ case 0x3C8: case 0x3C9: case 0x3CA: case 0x3CB: case 0x3CC: case 0x3CD: case 0x3CE: case 0x3CF:
+ // BIC rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn & ~BarrelShifterImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x3D0: case 0x3D1: case 0x3D2: case 0x3D3: case 0x3D4: case 0x3D5: case 0x3D6: case 0x3D7:
+ case 0x3D8: case 0x3D9: case 0x3DA: case 0x3DB: case 0x3DC: case 0x3DD: case 0x3DE: case 0x3DF:
+ // BICS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn & ~BarrelShifterImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ case 0x3E0: case 0x3E1: case 0x3E2: case 0x3E3: case 0x3E4: case 0x3E5: case 0x3E6: case 0x3E7:
+ case 0x3E8: case 0x3E9: case 0x3EA: case 0x3EB: case 0x3EC: case 0x3ED: case 0x3EE: case 0x3EF:
+ // MVN rd, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x3F0: case 0x3F1: case 0x3F2: case 0x3F3: case 0x3F4: case 0x3F5: case 0x3F6: case 0x3F7:
+ case 0x3F8: case 0x3F9: case 0x3FA: case 0x3FB: case 0x3FC: case 0x3FD: case 0x3FE: case 0x3FF:
+ // MVNS rd, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // STR immediate implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x400: case 0x401: case 0x402: case 0x403: case 0x404: case 0x405: case 0x406: case 0x407:
+ case 0x408: case 0x409: case 0x40A: case 0x40B: case 0x40C: case 0x40D: case 0x40E: case 0x40F:
+ // STR rd, rn, -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ break;
+
+ case 0x420: case 0x421: case 0x422: case 0x423: case 0x424: case 0x425: case 0x426: case 0x427:
+ case 0x428: case 0x429: case 0x42A: case 0x42B: case 0x42C: case 0x42D: case 0x42E: case 0x42F:
+ // STRT rd, rn, -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ break;
+
+ case 0x440: case 0x441: case 0x442: case 0x443: case 0x444: case 0x445: case 0x446: case 0x447:
+ case 0x448: case 0x449: case 0x44A: case 0x44B: case 0x44C: case 0x44D: case 0x44E: case 0x44F:
+ // STRB rd, rn, -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ break;
+
+ case 0x460: case 0x461: case 0x462: case 0x463: case 0x464: case 0x465: case 0x466: case 0x467:
+ case 0x468: case 0x469: case 0x46A: case 0x46B: case 0x46C: case 0x46D: case 0x46E: case 0x46F:
+ // STRBT rd, rn, -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ break;
+
+ case 0x480: case 0x481: case 0x482: case 0x483: case 0x484: case 0x485: case 0x486: case 0x487:
+ case 0x488: case 0x489: case 0x48A: case 0x48B: case 0x48C: case 0x48D: case 0x48E: case 0x48F:
+ // STR rd, rn, immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.curInstruction & 0xFFF;
+ break;
+
+ case 0x4A0: case 0x4A1: case 0x4A2: case 0x4A3: case 0x4A4: case 0x4A5: case 0x4A6: case 0x4A7:
+ case 0x4A8: case 0x4A9: case 0x4AA: case 0x4AB: case 0x4AC: case 0x4AD: case 0x4AE: case 0x4AF:
+ // STRT rd, rn, immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.curInstruction & 0xFFF;
+ break;
+
+ case 0x4C0: case 0x4C1: case 0x4C2: case 0x4C3: case 0x4C4: case 0x4C5: case 0x4C6: case 0x4C7:
+ case 0x4C8: case 0x4C9: case 0x4CA: case 0x4CB: case 0x4CC: case 0x4CD: case 0x4CE: case 0x4CF:
+ // STRB rd, rn, immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.curInstruction & 0xFFF;
+ break;
+
+ case 0x4E0: case 0x4E1: case 0x4E2: case 0x4E3: case 0x4E4: case 0x4E5: case 0x4E6: case 0x4E7:
+ case 0x4E8: case 0x4E9: case 0x4EA: case 0x4EB: case 0x4EC: case 0x4ED: case 0x4EE: case 0x4EF:
+ // STRBT rd, rn, immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.curInstruction & 0xFFF;
+ break;
+
+ case 0x500: case 0x501: case 0x502: case 0x503: case 0x504: case 0x505: case 0x506: case 0x507:
+ case 0x508: case 0x509: case 0x50A: case 0x50B: case 0x50C: case 0x50D: case 0x50E: case 0x50F:
+ // STR rd, [rn, -immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + offset, alu);
+ break;
+
+ case 0x520: case 0x521: case 0x522: case 0x523: case 0x524: case 0x525: case 0x526: case 0x527:
+ case 0x528: case 0x529: case 0x52A: case 0x52B: case 0x52C: case 0x52D: case 0x52E: case 0x52F:
+ // STR rd, [rn, -immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU32(registers[rn], alu);
+ break;
+
+ case 0x540: case 0x541: case 0x542: case 0x543: case 0x544: case 0x545: case 0x546: case 0x547:
+ case 0x548: case 0x549: case 0x54A: case 0x54B: case 0x54C: case 0x54D: case 0x54E: case 0x54F:
+ // STRB rd, [rn, -immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + offset, (byte)(alu & 0xFF));
+ break;
+
+ case 0x560: case 0x561: case 0x562: case 0x563: case 0x564: case 0x565: case 0x566: case 0x567:
+ case 0x568: case 0x569: case 0x56A: case 0x56B: case 0x56C: case 0x56D: case 0x56E: case 0x56F:
+ // STRB rd, [rn, -immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ break;
+
+ case 0x580: case 0x581: case 0x582: case 0x583: case 0x584: case 0x585: case 0x586: case 0x587:
+ case 0x588: case 0x589: case 0x58A: case 0x58B: case 0x58C: case 0x58D: case 0x58E: case 0x58F:
+ // STR rd, [rn, immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + (this.curInstruction & 0xFFF), alu);
+ break;
+
+ case 0x5A0: case 0x5A1: case 0x5A2: case 0x5A3: case 0x5A4: case 0x5A5: case 0x5A6: case 0x5A7:
+ case 0x5A8: case 0x5A9: case 0x5AA: case 0x5AB: case 0x5AC: case 0x5AD: case 0x5AE: case 0x5AF:
+ // STRT rd, [rn, immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.curInstruction & 0xFFF;
+ this.memory.WriteU32(registers[rn], alu);
+ break;
+
+ case 0x5C0: case 0x5C1: case 0x5C2: case 0x5C3: case 0x5C4: case 0x5C5: case 0x5C6: case 0x5C7:
+ case 0x5C8: case 0x5C9: case 0x5CA: case 0x5CB: case 0x5CC: case 0x5CD: case 0x5CE: case 0x5CF:
+ // STRB rd, [rn, immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + (this.curInstruction & 0xFFF), (byte)(alu & 0xFF));
+ break;
+
+ case 0x5E0: case 0x5E1: case 0x5E2: case 0x5E3: case 0x5E4: case 0x5E5: case 0x5E6: case 0x5E7:
+ case 0x5E8: case 0x5E9: case 0x5EA: case 0x5EB: case 0x5EC: case 0x5ED: case 0x5EE: case 0x5EF:
+ // STRB rd, [rn, immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.curInstruction & 0xFFF;
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // LDR immediate implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x410: case 0x411: case 0x412: case 0x413: case 0x414: case 0x415: case 0x416: case 0x417:
+ case 0x418: case 0x419: case 0x41A: case 0x41B: case 0x41C: case 0x41D: case 0x41E: case 0x41F:
+ // LDR rd, rn, -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x430: case 0x431: case 0x432: case 0x433: case 0x434: case 0x435: case 0x436: case 0x437:
+ case 0x438: case 0x439: case 0x43A: case 0x43B: case 0x43C: case 0x43D: case 0x43E: case 0x43F:
+ // LDRT rd, rn, -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x450: case 0x451: case 0x452: case 0x453: case 0x454: case 0x455: case 0x456: case 0x457:
+ case 0x458: case 0x459: case 0x45A: case 0x45B: case 0x45C: case 0x45D: case 0x45E: case 0x45F:
+ // LDRB rd, rn, -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x470: case 0x471: case 0x472: case 0x473: case 0x474: case 0x475: case 0x476: case 0x477:
+ case 0x478: case 0x479: case 0x47A: case 0x47B: case 0x47C: case 0x47D: case 0x47E: case 0x47F:
+ // LDRBT rd, rn, -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x490: case 0x491: case 0x492: case 0x493: case 0x494: case 0x495: case 0x496: case 0x497:
+ case 0x498: case 0x499: case 0x49A: case 0x49B: case 0x49C: case 0x49D: case 0x49E: case 0x49F:
+ // LDR rd, rn, immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += this.curInstruction & 0xFFF;
+ break;
+
+ case 0x4B0: case 0x4B1: case 0x4B2: case 0x4B3: case 0x4B4: case 0x4B5: case 0x4B6: case 0x4B7:
+ case 0x4B8: case 0x4B9: case 0x4BA: case 0x4BB: case 0x4BC: case 0x4BD: case 0x4BE: case 0x4BF:
+ // LDRT rd, rn, immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += this.curInstruction & 0xFFF;
+ break;
+
+ case 0x4D0: case 0x4D1: case 0x4D2: case 0x4D3: case 0x4D4: case 0x4D5: case 0x4D6: case 0x4D7:
+ case 0x4D8: case 0x4D9: case 0x4DA: case 0x4DB: case 0x4DC: case 0x4DD: case 0x4DE: case 0x4DF:
+ // LDRB rd, rn, immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += this.curInstruction & 0xFFF;
+ break;
+
+ case 0x4F0: case 0x4F1: case 0x4F2: case 0x4F3: case 0x4F4: case 0x4F5: case 0x4F6: case 0x4F7:
+ case 0x4F8: case 0x4F9: case 0x4FA: case 0x4FB: case 0x4FC: case 0x4FD: case 0x4FE: case 0x4FF:
+ // LDRBT rd, rn, immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += this.curInstruction & 0xFFF;
+ break;
+
+ case 0x510: case 0x511: case 0x512: case 0x513: case 0x514: case 0x515: case 0x516: case 0x517:
+ case 0x518: case 0x519: case 0x51A: case 0x51B: case 0x51C: case 0x51D: case 0x51E: case 0x51F:
+ // LDR rd, [rn, -immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x530: case 0x531: case 0x532: case 0x533: case 0x534: case 0x535: case 0x536: case 0x537:
+ case 0x538: case 0x539: case 0x53A: case 0x53B: case 0x53C: case 0x53D: case 0x53E: case 0x53F:
+ // LDR rd, [rn, -immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x550: case 0x551: case 0x552: case 0x553: case 0x554: case 0x555: case 0x556: case 0x557:
+ case 0x558: case 0x559: case 0x55A: case 0x55B: case 0x55C: case 0x55D: case 0x55E: case 0x55F:
+ // LDRB rd, [rn, -immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x570: case 0x571: case 0x572: case 0x573: case 0x574: case 0x575: case 0x576: case 0x577:
+ case 0x578: case 0x579: case 0x57A: case 0x57B: case 0x57C: case 0x57D: case 0x57E: case 0x57F:
+ // LDRB rd, [rn, -immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x590: case 0x591: case 0x592: case 0x593: case 0x594: case 0x595: case 0x596: case 0x597:
+ case 0x598: case 0x599: case 0x59A: case 0x59B: case 0x59C: case 0x59D: case 0x59E: case 0x59F:
+ // LDR rd, [rn, immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + (this.curInstruction & 0xFFF));
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x5B0: case 0x5B1: case 0x5B2: case 0x5B3: case 0x5B4: case 0x5B5: case 0x5B6: case 0x5B7:
+ case 0x5B8: case 0x5B9: case 0x5BA: case 0x5BB: case 0x5BC: case 0x5BD: case 0x5BE: case 0x5BF:
+ // LDR rd, [rn, immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.curInstruction & 0xFFF;
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x5D0: case 0x5D1: case 0x5D2: case 0x5D3: case 0x5D4: case 0x5D5: case 0x5D6: case 0x5D7:
+ case 0x5D8: case 0x5D9: case 0x5DA: case 0x5DB: case 0x5DC: case 0x5DD: case 0x5DE: case 0x5DF:
+ // LDRB rd, [rn, immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + (this.curInstruction & 0xFFF));
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x5F0: case 0x5F1: case 0x5F2: case 0x5F3: case 0x5F4: case 0x5F5: case 0x5F6: case 0x5F7:
+ case 0x5F8: case 0x5F9: case 0x5FA: case 0x5FB: case 0x5FC: case 0x5FD: case 0x5FE: case 0x5FF:
+ // LDRB rd, [rn, immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.curInstruction & 0xFFF;
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // STR register shift implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x600:
+ case 0x608:
+ // STR rd, rn, -rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ break;
+
+ case 0x602:
+ case 0x60A:
+ // STR rd, rn, -rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ break;
+
+ case 0x604:
+ case 0x60C:
+ // STR rd, rn, -rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ break;
+
+ case 0x606:
+ case 0x60E:
+ // STR rd, rn, -rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ break;
+
+ case 0x620:
+ case 0x628:
+ // STRT rd, rn, -rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ break;
+
+ case 0x622:
+ case 0x62A:
+ // STRT rd, rn, -rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ break;
+
+ case 0x624:
+ case 0x62C:
+ // STRT rd, rn, -rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ break;
+
+ case 0x626:
+ case 0x62E:
+ // STRT rd, rn, -rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ break;
+
+ case 0x640:
+ case 0x648:
+ // STRB rd, rn, -rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ break;
+
+ case 0x642:
+ case 0x64A:
+ // STRB rd, rn, -rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ break;
+
+ case 0x644:
+ case 0x64C:
+ // STRB rd, rn, -rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ break;
+
+ case 0x646:
+ case 0x64E:
+ // STRB rd, rn, -rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ break;
+
+ case 0x660:
+ case 0x668:
+ // STRBT rd, rn, -rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ break;
+
+ case 0x662:
+ case 0x66A:
+ // STRBT rd, rn, -rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ break;
+
+ case 0x664:
+ case 0x66C:
+ // STRBT rd, rn, -rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ break;
+
+ case 0x666:
+ case 0x66E:
+ // STRBT rd, rn, -rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ break;
+
+ case 0x680:
+ case 0x688:
+ // STR rd, rn, rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.BarrelShifterLslImmed();
+ break;
+
+ case 0x682:
+ case 0x68A:
+ // STR rd, rn, rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.BarrelShifterLsrImmed();
+ break;
+
+ case 0x684:
+ case 0x68C:
+ // STR rd, rn, rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.BarrelShifterAsrImmed();
+ break;
+
+ case 0x686:
+ case 0x68E:
+ // STR rd, rn, rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.BarrelShifterRorImmed();
+ break;
+
+ case 0x6A0:
+ case 0x6A2:
+ // STRT rd, rn, rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.BarrelShifterLslImmed();
+ break;
+
+ case 0x6A4:
+ case 0x6A6:
+ // STRT rd, rn, rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.BarrelShifterLsrImmed();
+ break;
+
+ case 0x6A8:
+ case 0x6AA:
+ // STRT rd, rn, rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.BarrelShifterAsrImmed();
+ break;
+
+ case 0x6AC:
+ case 0x6AE:
+ // STRT rd, rn, rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.BarrelShifterRorImmed();
+ break;
+
+ case 0x6C0:
+ case 0x6C8:
+ // STRB rd, rn, rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.BarrelShifterLslImmed();
+ break;
+
+ case 0x6C2:
+ case 0x6CA:
+ // STRB rd, rn, rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.BarrelShifterLsrImmed();
+ break;
+
+ case 0x6C4:
+ case 0x6CC:
+ // STRB rd, rn, rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.BarrelShifterAsrImmed();
+ break;
+
+ case 0x6C6:
+ case 0x6CE:
+ // STRB rd, rn, rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.BarrelShifterRorImmed();
+ break;
+
+ case 0x6E0:
+ case 0x6E8:
+ // STRBT rd, rn, rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.BarrelShifterLslImmed();
+ break;
+
+ case 0x6E2:
+ case 0x6EA:
+ // STRBT rd, rn, rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.BarrelShifterLsrImmed();
+ break;
+
+ case 0x6E4:
+ case 0x6EC:
+ // STRBT rd, rn, rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.BarrelShifterAsrImmed();
+ break;
+
+ case 0x6E6:
+ case 0x6EE:
+ // STRBT rd, rn, rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.BarrelShifterRorImmed();
+ break;
+
+ case 0x700:
+ case 0x708:
+ // STR rd, [rn, -rm lsl immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + offset, alu);
+ break;
+
+ case 0x702:
+ case 0x70A:
+ // STR rd, [rn, -rm lsr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + offset, alu);
+ break;
+
+ case 0x704:
+ case 0x70C:
+ // STR rd, [rn, -rm asr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + offset, alu);
+ break;
+
+ case 0x706:
+ case 0x70E:
+ // STR rd, [rn, -rm ror immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + offset, alu);
+ break;
+
+ case 0x720:
+ case 0x728:
+ // STR rd, [rn, -rm lsl immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU32(registers[rn], alu);
+ break;
+
+ case 0x722:
+ case 0x72A:
+ // STR rd, [rn, -rm lsr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU32(registers[rn], alu);
+ break;
+
+ case 0x724:
+ case 0x72C:
+ // STR rd, [rn, -rm asr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU32(registers[rn], alu);
+ break;
+
+ case 0x726:
+ case 0x72E:
+ // STR rd, [rn, -rm ror immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU32(registers[rn], alu);
+ break;
+
+ case 0x740:
+ case 0x748:
+ // STRB rd, [rn, -rm lsl immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + offset, (byte)(alu & 0xFF));
+ break;
+
+ case 0x742:
+ case 0x74A:
+ // STRB rd, [rn, -rm lsr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + offset, (byte)(alu & 0xFF));
+ break;
+
+ case 0x744:
+ case 0x74C:
+ // STRB rd, [rn, -rm asr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + offset, (byte)(alu & 0xFF));
+ break;
+
+ case 0x746:
+ case 0x74E:
+ // STRB rd, [rn, -rm ror immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + offset, (byte)(alu & 0xFF));
+ break;
+
+ case 0x760:
+ case 0x768:
+ // STRB rd, [rn, -rm lsl immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ break;
+
+ case 0x762:
+ case 0x76A:
+ // STRB rd, [rn, -rm lsr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ break;
+
+ case 0x764:
+ case 0x76C:
+ // STRB rd, [rn, -rm asr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ break;
+
+ case 0x766:
+ case 0x76E:
+ // STRB rd, [rn, -rm ror immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ break;
+
+ case 0x780:
+ case 0x788:
+ // STR rd, [rn, rm lsl immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + this.BarrelShifterLslImmed(), alu);
+ break;
+
+ case 0x782:
+ case 0x78A:
+ // STR rd, [rn, rm lsr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + this.BarrelShifterLsrImmed(), alu);
+ break;
+
+ case 0x784:
+ case 0x78C:
+ // STR rd, [rn, rm asr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + this.BarrelShifterAsrImmed(), alu);
+ break;
+
+ case 0x786:
+ case 0x78E:
+ // STR rd, [rn, rm ror immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + this.BarrelShifterRorImmed(), alu);
+ break;
+
+ case 0x7A0:
+ case 0x7A8:
+ // STR rd, [rn, rm lsl immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.BarrelShifterLslImmed();
+ this.memory.WriteU32(registers[rn], alu);
+ break;
+
+ case 0x7A2:
+ case 0x7AA:
+ // STR rd, [rn, rm lsr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.BarrelShifterLsrImmed();
+ this.memory.WriteU32(registers[rn], alu);
+ break;
+
+ case 0x7A4:
+ case 0x7AC:
+ // STR rd, [rn, rm asr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.BarrelShifterAsrImmed();
+ this.memory.WriteU32(registers[rn], alu);
+ break;
+
+ case 0x7A6:
+ case 0x7AE:
+ // STR rd, [rn, rm ror immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.BarrelShifterRorImmed();
+ this.memory.WriteU32(registers[rn], alu);
+ break;
+
+ case 0x7C0:
+ case 0x7C8:
+ // STRB rd, [rn, rm lsl immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + this.BarrelShifterLslImmed(), (byte)(alu & 0xFF));
+ break;
+
+ case 0x7C2:
+ case 0x7CA:
+ // STRB rd, [rn, rm lsr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + this.BarrelShifterLsrImmed(), (byte)(alu & 0xFF));
+ break;
+
+ case 0x7C4:
+ case 0x7CC:
+ // STRB rd, [rn, rm asr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + this.BarrelShifterAsrImmed(), (byte)(alu & 0xFF));
+ break;
+
+ case 0x7C6:
+ case 0x7CE:
+ // STRB rd, [rn, rm ror immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + this.BarrelShifterRorImmed(), (byte)(alu & 0xFF));
+ break;
+
+ case 0x7E0:
+ case 0x7E8:
+ // STRB rd, [rn, rm lsl immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.BarrelShifterLslImmed();
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ break;
+
+ case 0x7E2:
+ case 0x7EA:
+ // STRB rd, [rn, rm lsr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.BarrelShifterLsrImmed();
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ break;
+
+ case 0x7E4:
+ case 0x7EC:
+ // STRB rd, [rn, rm asr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.BarrelShifterAsrImmed();
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ break;
+
+ case 0x7E6:
+ case 0x7EE:
+ // STRB rd, [rn, rm ror immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.BarrelShifterRorImmed();
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // LDR register shift implementations
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0x610:
+ case 0x618:
+ // LDR rd, rn, -rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x612:
+ case 0x61A:
+ // LDR rd, rn, -rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x614:
+ case 0x61C:
+ // LDR rd, rn, -rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x616:
+ case 0x61E:
+ // LDR rd, rn, -rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x630:
+ case 0x638:
+ // LDRT rd, rn, -rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x632:
+ case 0x63A:
+ // LDRT rd, rn, -rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x634:
+ case 0x63C:
+ // LDRT rd, rn, -rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x636:
+ case 0x63E:
+ // LDRT rd, rn, -rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x650:
+ case 0x658:
+ // LDRB rd, rn, -rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x652:
+ case 0x65A:
+ // LDRB rd, rn, -rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x654:
+ case 0x65C:
+ // LDRB rd, rn, -rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x656:
+ case 0x65E:
+ // LDRB rd, rn, -rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x670:
+ case 0x678:
+ // LDRBT rd, rn, -rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x672:
+ case 0x67A:
+ // LDRBT rd, rn, -rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x674:
+ case 0x67C:
+ // LDRBT rd, rn, -rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x676:
+ case 0x67E:
+ // LDRBT rd, rn, -rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x690:
+ case 0x698:
+ // LDR rd, rn, rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x692:
+ case 0x69A:
+ // LDR rd, rn, rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x694:
+ case 0x69C:
+ // LDR rd, rn, rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x696:
+ case 0x69E:
+ // LDR rd, rn, rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x6B0:
+ case 0x6B8:
+ // LDRT rd, rn, rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x6B2:
+ case 0x6BA:
+ // LDRT rd, rn, rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x6B4:
+ case 0x6BC:
+ // LDRT rd, rn, rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x6B6:
+ case 0x6BE:
+ // LDRT rd, rn, rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x6D0:
+ case 0x6D8:
+ // LDRB rd, rn, rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x6D2:
+ case 0x6DA:
+ // LDRB rd, rn, rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x6D4:
+ case 0x6DC:
+ // LDRB rd, rn, rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x6D6:
+ case 0x6DE:
+ // LDRB rd, rn, rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x6F0:
+ case 0x6F8:
+ // LDRBT rd, rn, rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x6F2:
+ case 0x6FA:
+ // LDRBT rd, rn, rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x6F4:
+ case 0x6FC:
+ // LDRBT rd, rn, rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x6F6:
+ case 0x6FE:
+ // LDRBT rd, rn, rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ break;
+
+ case 0x710:
+ case 0x718:
+ // LDR rd, [rn, -rm lsl immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x712:
+ case 0x71A:
+ // LDR rd, [rn, -rm lsr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x714:
+ case 0x71C:
+ // LDR rd, [rn, -rm asr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x716:
+ case 0x71E:
+ // LDR rd, [rn, -rm ror immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x730:
+ case 0x738:
+ // LDR rd, [rn, -rm lsl immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x732:
+ case 0x73A:
+ // LDR rd, [rn, -rm lsr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x734:
+ case 0x73C:
+ // LDR rd, [rn, -rm asr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x736:
+ case 0x73E:
+ // LDR rd, [rn, -rm ror immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x750:
+ case 0x758:
+ // LDRB rd, [rn, -rm lsl immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x752:
+ case 0x75A:
+ // LDRB rd, [rn, -rm lsr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x754:
+ case 0x75C:
+ // LDRB rd, [rn, -rm asr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x756:
+ case 0x75E:
+ // LDRB rd, [rn, -rm ror immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x770:
+ case 0x778:
+ // LDRB rd, [rn, -rm lsl immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x772:
+ case 0x77A:
+ // LDRB rd, [rn, -rm lsr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x774:
+ case 0x77C:
+ // LDRB rd, [rn, -rm asr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x776:
+ case 0x77E:
+ // LDRB rd, [rn, -rm ror immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x790:
+ case 0x798:
+ // LDR rd, [rn, rm lsl immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + this.BarrelShifterLslImmed());
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x792:
+ case 0x79A:
+ // LDR rd, [rn, rm lsr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + this.BarrelShifterLsrImmed());
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x794:
+ case 0x79C:
+ // LDR rd, [rn, rm asr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + this.BarrelShifterAsrImmed());
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x796:
+ case 0x79E:
+ // LDR rd, [rn, rm ror immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + this.BarrelShifterRorImmed());
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x7B0:
+ case 0x7B8:
+ // LDR rd, [rn, rm lsl immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.BarrelShifterLslImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x7B2:
+ case 0x7BA:
+ // LDR rd, [rn, rm lsr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.BarrelShifterLsrImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x7B4:
+ case 0x7BC:
+ // LDR rd, [rn, rm asr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.BarrelShifterAsrImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x7B6:
+ case 0x7BE:
+ // LDR rd, [rn, rm ror immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.BarrelShifterRorImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x7D0:
+ case 0x7D8:
+ // LDRB rd, [rn, rm lsl immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + this.BarrelShifterLslImmed());
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x7D2:
+ case 0x7DA:
+ // LDRB rd, [rn, rm lsr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + this.BarrelShifterLsrImmed());
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x7D4:
+ case 0x7DC:
+ // LDRB rd, [rn, rm asr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + this.BarrelShifterAsrImmed());
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x7D6:
+ case 0x7DE:
+ // LDRB rd, [rn, rm ror immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + this.BarrelShifterRorImmed());
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x7F0:
+ case 0x7F8:
+ // LDRB rd, [rn, rm lsl immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.BarrelShifterLslImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x7F2:
+ case 0x7FA:
+ // LDRB rd, [rn, rm lsr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.BarrelShifterLsrImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x7F4:
+ case 0x7FC:
+ // LDRB rd, [rn, rm asr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.BarrelShifterAsrImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ case 0x7F6:
+ case 0x7FE:
+ // LDRB rd, [rn, rm ror immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.BarrelShifterRorImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // LDM implementations (TODO)
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // STM implementations (TODO)
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // B implementation
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0xA00: case 0xA01: case 0xA02: case 0xA03: case 0xA04: case 0xA05: case 0xA06: case 0xA07:
+ case 0xA08: case 0xA09: case 0xA0A: case 0xA0B: case 0xA0C: case 0xA0D: case 0xA0E: case 0xA0F:
+ case 0xA10: case 0xA11: case 0xA12: case 0xA13: case 0xA14: case 0xA15: case 0xA16: case 0xA17:
+ case 0xA18: case 0xA19: case 0xA1A: case 0xA1B: case 0xA1C: case 0xA1D: case 0xA1E: case 0xA1F:
+ case 0xA20: case 0xA21: case 0xA22: case 0xA23: case 0xA24: case 0xA25: case 0xA26: case 0xA27:
+ case 0xA28: case 0xA29: case 0xA2A: case 0xA2B: case 0xA2C: case 0xA2D: case 0xA2E: case 0xA2F:
+ case 0xA30: case 0xA31: case 0xA32: case 0xA33: case 0xA34: case 0xA35: case 0xA36: case 0xA37:
+ case 0xA38: case 0xA39: case 0xA3A: case 0xA3B: case 0xA3C: case 0xA3D: case 0xA3E: case 0xA3F:
+ case 0xA40: case 0xA41: case 0xA42: case 0xA43: case 0xA44: case 0xA45: case 0xA46: case 0xA47:
+ case 0xA48: case 0xA49: case 0xA4A: case 0xA4B: case 0xA4C: case 0xA4D: case 0xA4E: case 0xA4F:
+ case 0xA50: case 0xA51: case 0xA52: case 0xA53: case 0xA54: case 0xA55: case 0xA56: case 0xA57:
+ case 0xA58: case 0xA59: case 0xA5A: case 0xA5B: case 0xA5C: case 0xA5D: case 0xA5E: case 0xA5F:
+ case 0xA60: case 0xA61: case 0xA62: case 0xA63: case 0xA64: case 0xA65: case 0xA66: case 0xA67:
+ case 0xA68: case 0xA69: case 0xA6A: case 0xA6B: case 0xA6C: case 0xA6D: case 0xA6E: case 0xA6F:
+ case 0xA70: case 0xA71: case 0xA72: case 0xA73: case 0xA74: case 0xA75: case 0xA76: case 0xA77:
+ case 0xA78: case 0xA79: case 0xA7A: case 0xA7B: case 0xA7C: case 0xA7D: case 0xA7E: case 0xA7F:
+ case 0xA80: case 0xA81: case 0xA82: case 0xA83: case 0xA84: case 0xA85: case 0xA86: case 0xA87:
+ case 0xA88: case 0xA89: case 0xA8A: case 0xA8B: case 0xA8C: case 0xA8D: case 0xA8E: case 0xA8F:
+ case 0xA90: case 0xA91: case 0xA92: case 0xA93: case 0xA94: case 0xA95: case 0xA96: case 0xA97:
+ case 0xA98: case 0xA99: case 0xA9A: case 0xA9B: case 0xA9C: case 0xA9D: case 0xA9E: case 0xA9F:
+ case 0xAA0: case 0xAA1: case 0xAA2: case 0xAA3: case 0xAA4: case 0xAA5: case 0xAA6: case 0xAA7:
+ case 0xAA8: case 0xAA9: case 0xAAA: case 0xAAB: case 0xAAC: case 0xAAD: case 0xAAE: case 0xAAF:
+ case 0xAB0: case 0xAB1: case 0xAB2: case 0xAB3: case 0xAB4: case 0xAB5: case 0xAB6: case 0xAB7:
+ case 0xAB8: case 0xAB9: case 0xABA: case 0xABB: case 0xABC: case 0xABD: case 0xABE: case 0xABF:
+ case 0xAC0: case 0xAC1: case 0xAC2: case 0xAC3: case 0xAC4: case 0xAC5: case 0xAC6: case 0xAC7:
+ case 0xAC8: case 0xAC9: case 0xACA: case 0xACB: case 0xACC: case 0xACD: case 0xACE: case 0xACF:
+ case 0xAD0: case 0xAD1: case 0xAD2: case 0xAD3: case 0xAD4: case 0xAD5: case 0xAD6: case 0xAD7:
+ case 0xAD8: case 0xAD9: case 0xADA: case 0xADB: case 0xADC: case 0xADD: case 0xADE: case 0xADF:
+ case 0xAE0: case 0xAE1: case 0xAE2: case 0xAE3: case 0xAE4: case 0xAE5: case 0xAE6: case 0xAE7:
+ case 0xAE8: case 0xAE9: case 0xAEA: case 0xAEB: case 0xAEC: case 0xAED: case 0xAEE: case 0xAEF:
+ case 0xAF0: case 0xAF1: case 0xAF2: case 0xAF3: case 0xAF4: case 0xAF5: case 0xAF6: case 0xAF7:
+ case 0xAF8: case 0xAF9: case 0xAFA: case 0xAFB: case 0xAFC: case 0xAFD: case 0xAFE: case 0xAFF:
+ {
+ uint branchOffset = this.curInstruction & 0x00FFFFFF;
+ if (branchOffset >> 23 == 1) branchOffset |= 0xFF000000;
+
+ this.registers[15] += branchOffset << 2;
+
+ this.FlushQueue();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // BL implementation
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0xB00: case 0xB01: case 0xB02: case 0xB03: case 0xB04: case 0xB05: case 0xB06: case 0xB07:
+ case 0xB08: case 0xB09: case 0xB0A: case 0xB0B: case 0xB0C: case 0xB0D: case 0xB0E: case 0xB0F:
+ case 0xB10: case 0xB11: case 0xB12: case 0xB13: case 0xB14: case 0xB15: case 0xB16: case 0xB17:
+ case 0xB18: case 0xB19: case 0xB1A: case 0xB1B: case 0xB1C: case 0xB1D: case 0xB1E: case 0xB1F:
+ case 0xB20: case 0xB21: case 0xB22: case 0xB23: case 0xB24: case 0xB25: case 0xB26: case 0xB27:
+ case 0xB28: case 0xB29: case 0xB2A: case 0xB2B: case 0xB2C: case 0xB2D: case 0xB2E: case 0xB2F:
+ case 0xB30: case 0xB31: case 0xB32: case 0xB33: case 0xB34: case 0xB35: case 0xB36: case 0xB37:
+ case 0xB38: case 0xB39: case 0xB3A: case 0xB3B: case 0xB3C: case 0xB3D: case 0xB3E: case 0xB3F:
+ case 0xB40: case 0xB41: case 0xB42: case 0xB43: case 0xB44: case 0xB45: case 0xB46: case 0xB47:
+ case 0xB48: case 0xB49: case 0xB4A: case 0xB4B: case 0xB4C: case 0xB4D: case 0xB4E: case 0xB4F:
+ case 0xB50: case 0xB51: case 0xB52: case 0xB53: case 0xB54: case 0xB55: case 0xB56: case 0xB57:
+ case 0xB58: case 0xB59: case 0xB5A: case 0xB5B: case 0xB5C: case 0xB5D: case 0xB5E: case 0xB5F:
+ case 0xB60: case 0xB61: case 0xB62: case 0xB63: case 0xB64: case 0xB65: case 0xB66: case 0xB67:
+ case 0xB68: case 0xB69: case 0xB6A: case 0xB6B: case 0xB6C: case 0xB6D: case 0xB6E: case 0xB6F:
+ case 0xB70: case 0xB71: case 0xB72: case 0xB73: case 0xB74: case 0xB75: case 0xB76: case 0xB77:
+ case 0xB78: case 0xB79: case 0xB7A: case 0xB7B: case 0xB7C: case 0xB7D: case 0xB7E: case 0xB7F:
+ case 0xB80: case 0xB81: case 0xB82: case 0xB83: case 0xB84: case 0xB85: case 0xB86: case 0xB87:
+ case 0xB88: case 0xB89: case 0xB8A: case 0xB8B: case 0xB8C: case 0xB8D: case 0xB8E: case 0xB8F:
+ case 0xB90: case 0xB91: case 0xB92: case 0xB93: case 0xB94: case 0xB95: case 0xB96: case 0xB97:
+ case 0xB98: case 0xB99: case 0xB9A: case 0xB9B: case 0xB9C: case 0xB9D: case 0xB9E: case 0xB9F:
+ case 0xBA0: case 0xBA1: case 0xBA2: case 0xBA3: case 0xBA4: case 0xBA5: case 0xBA6: case 0xBA7:
+ case 0xBA8: case 0xBA9: case 0xBAA: case 0xBAB: case 0xBAC: case 0xBAD: case 0xBAE: case 0xBAF:
+ case 0xBB0: case 0xBB1: case 0xBB2: case 0xBB3: case 0xBB4: case 0xBB5: case 0xBB6: case 0xBB7:
+ case 0xBB8: case 0xBB9: case 0xBBA: case 0xBBB: case 0xBBC: case 0xBBD: case 0xBBE: case 0xBBF:
+ case 0xBC0: case 0xBC1: case 0xBC2: case 0xBC3: case 0xBC4: case 0xBC5: case 0xBC6: case 0xBC7:
+ case 0xBC8: case 0xBC9: case 0xBCA: case 0xBCB: case 0xBCC: case 0xBCD: case 0xBCE: case 0xBCF:
+ case 0xBD0: case 0xBD1: case 0xBD2: case 0xBD3: case 0xBD4: case 0xBD5: case 0xBD6: case 0xBD7:
+ case 0xBD8: case 0xBD9: case 0xBDA: case 0xBDB: case 0xBDC: case 0xBDD: case 0xBDE: case 0xBDF:
+ case 0xBE0: case 0xBE1: case 0xBE2: case 0xBE3: case 0xBE4: case 0xBE5: case 0xBE6: case 0xBE7:
+ case 0xBE8: case 0xBE9: case 0xBEA: case 0xBEB: case 0xBEC: case 0xBED: case 0xBEE: case 0xBEF:
+ case 0xBF0: case 0xBF1: case 0xBF2: case 0xBF3: case 0xBF4: case 0xBF5: case 0xBF6: case 0xBF7:
+ case 0xBF8: case 0xBF9: case 0xBFA: case 0xBFB: case 0xBFC: case 0xBFD: case 0xBFE: case 0xBFF:
+ {
+ uint branchOffset = this.curInstruction & 0x00FFFFFF;
+ if (branchOffset >> 23 == 1) branchOffset |= 0xFF000000;
+
+ this.registers[14] = this.registers[15] - 4U;
+ this.registers[15] += branchOffset << 2;
+
+ this.FlushQueue();
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // SWI implementation
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ case 0xF00: case 0xF01: case 0xF02: case 0xF03: case 0xF04: case 0xF05: case 0xF06: case 0xF07:
+ case 0xF08: case 0xF09: case 0xF0A: case 0xF0B: case 0xF0C: case 0xF0D: case 0xF0E: case 0xF0F:
+ case 0xF10: case 0xF11: case 0xF12: case 0xF13: case 0xF14: case 0xF15: case 0xF16: case 0xF17:
+ case 0xF18: case 0xF19: case 0xF1A: case 0xF1B: case 0xF1C: case 0xF1D: case 0xF1E: case 0xF1F:
+ case 0xF20: case 0xF21: case 0xF22: case 0xF23: case 0xF24: case 0xF25: case 0xF26: case 0xF27:
+ case 0xF28: case 0xF29: case 0xF2A: case 0xF2B: case 0xF2C: case 0xF2D: case 0xF2E: case 0xF2F:
+ case 0xF30: case 0xF31: case 0xF32: case 0xF33: case 0xF34: case 0xF35: case 0xF36: case 0xF37:
+ case 0xF38: case 0xF39: case 0xF3A: case 0xF3B: case 0xF3C: case 0xF3D: case 0xF3E: case 0xF3F:
+ case 0xF40: case 0xF41: case 0xF42: case 0xF43: case 0xF44: case 0xF45: case 0xF46: case 0xF47:
+ case 0xF48: case 0xF49: case 0xF4A: case 0xF4B: case 0xF4C: case 0xF4D: case 0xF4E: case 0xF4F:
+ case 0xF50: case 0xF51: case 0xF52: case 0xF53: case 0xF54: case 0xF55: case 0xF56: case 0xF57:
+ case 0xF58: case 0xF59: case 0xF5A: case 0xF5B: case 0xF5C: case 0xF5D: case 0xF5E: case 0xF5F:
+ case 0xF60: case 0xF61: case 0xF62: case 0xF63: case 0xF64: case 0xF65: case 0xF66: case 0xF67:
+ case 0xF68: case 0xF69: case 0xF6A: case 0xF6B: case 0xF6C: case 0xF6D: case 0xF6E: case 0xF6F:
+ case 0xF70: case 0xF71: case 0xF72: case 0xF73: case 0xF74: case 0xF75: case 0xF76: case 0xF77:
+ case 0xF78: case 0xF79: case 0xF7A: case 0xF7B: case 0xF7C: case 0xF7D: case 0xF7E: case 0xF7F:
+ case 0xF80: case 0xF81: case 0xF82: case 0xF83: case 0xF84: case 0xF85: case 0xF86: case 0xF87:
+ case 0xF88: case 0xF89: case 0xF8A: case 0xF8B: case 0xF8C: case 0xF8D: case 0xF8E: case 0xF8F:
+ case 0xF90: case 0xF91: case 0xF92: case 0xF93: case 0xF94: case 0xF95: case 0xF96: case 0xF97:
+ case 0xF98: case 0xF99: case 0xF9A: case 0xF9B: case 0xF9C: case 0xF9D: case 0xF9E: case 0xF9F:
+ case 0xFA0: case 0xFA1: case 0xFA2: case 0xFA3: case 0xFA4: case 0xFA5: case 0xFA6: case 0xFA7:
+ case 0xFA8: case 0xFA9: case 0xFAA: case 0xFAB: case 0xFAC: case 0xFAD: case 0xFAE: case 0xFAF:
+ case 0xFB0: case 0xFB1: case 0xFB2: case 0xFB3: case 0xFB4: case 0xFB5: case 0xFB6: case 0xFB7:
+ case 0xFB8: case 0xFB9: case 0xFBA: case 0xFBB: case 0xFBC: case 0xFBD: case 0xFBE: case 0xFBF:
+ case 0xFC0: case 0xFC1: case 0xFC2: case 0xFC3: case 0xFC4: case 0xFC5: case 0xFC6: case 0xFC7:
+ case 0xFC8: case 0xFC9: case 0xFCA: case 0xFCB: case 0xFCC: case 0xFCD: case 0xFCE: case 0xFCF:
+ case 0xFD0: case 0xFD1: case 0xFD2: case 0xFD3: case 0xFD4: case 0xFD5: case 0xFD6: case 0xFD7:
+ case 0xFD8: case 0xFD9: case 0xFDA: case 0xFDB: case 0xFDC: case 0xFDD: case 0xFDE: case 0xFDF:
+ case 0xFE0: case 0xFE1: case 0xFE2: case 0xFE3: case 0xFE4: case 0xFE5: case 0xFE6: case 0xFE7:
+ case 0xFE8: case 0xFE9: case 0xFEA: case 0xFEB: case 0xFEC: case 0xFED: case 0xFEE: case 0xFEF:
+ case 0xFF0: case 0xFF1: case 0xFF2: case 0xFF3: case 0xFF4: case 0xFF5: case 0xFF6: case 0xFF7:
+ case 0xFF8: case 0xFF9: case 0xFFA: case 0xFFB: case 0xFFC: case 0xFFD: case 0xFFE: case 0xFFF:
+ this.registers[15] -= 4U;
+ this.parent.EnterException(Arm7Processor.SVC, 0x8, false, false);
+ break;
+
+ default:
+ this.NormalOps[(curInstruction >> 25) & 0x7]();
+ break;
+ }
+ }
+
+ #region Barrel Shifter
+ private const uint SHIFT_LSL = 0;
+ private const uint SHIFT_LSR = 1;
+ private const uint SHIFT_ASR = 2;
+ private const uint SHIFT_ROR = 3;
+
+ private uint BarrelShifter(uint shifterOperand)
+ {
+ uint type = (shifterOperand >> 5) & 0x3;
+
+ bool registerShift = (shifterOperand & (1 << 4)) == (1 << 4);
+
+ uint rm = registers[shifterOperand & 0xF];
+
+ int amount;
+ if (registerShift)
+ {
+ uint rs = (shifterOperand >> 8) & 0xF;
+ if (rs == 15)
+ {
+ amount = (int)((registers[rs] + 0x4) & 0xFF);
+ }
+ else
+ {
+ amount = (int)(registers[rs] & 0xFF);
+ }
+
+ if ((shifterOperand & 0xF) == 15)
+ {
+ rm += 4;
+ }
+ }
+ else
+ {
+ amount = (int)((shifterOperand >> 7) & 0x1F);
+ }
+
+ if (registerShift)
+ {
+ if (amount == 0)
+ {
+ this.shifterCarry = this.carry;
+ return rm;
+ }
+
+ switch (type)
+ {
+ case SHIFT_LSL:
+ if (amount < 32)
+ {
+ this.shifterCarry = (rm >> (32 - amount)) & 1;
+ return rm << amount;
+ }
+ else if (amount == 32)
+ {
+ this.shifterCarry = rm & 1;
+ return 0;
+ }
+ else
+ {
+ this.shifterCarry = 0;
+ return 0;
+ }
+
+ case SHIFT_LSR:
+ if (amount < 32)
+ {
+ this.shifterCarry = (rm >> (amount - 1)) & 1;
+ return rm >> amount;
+ }
+ else if (amount == 32)
+ {
+ this.shifterCarry = (rm >> 31) & 1;
+ return 0;
+ }
+ else
+ {
+ this.shifterCarry = 0;
+ return 0;
+ }
+
+ case SHIFT_ASR:
+ if (amount >= 32)
+ {
+ if ((rm & (1 << 31)) == 0)
+ {
+ this.shifterCarry = 0;
+ return 0;
+ }
+ else
+ {
+ this.shifterCarry = 1;
+ return 0xFFFFFFFF;
+ }
+ }
+ else
+ {
+ this.shifterCarry = (rm >> (amount - 1)) & 1;
+ return (uint)(((int)rm) >> amount);
+ }
+
+ case SHIFT_ROR:
+ if ((amount & 0x1F) == 0)
+ {
+ this.shifterCarry = (rm >> 31) & 1;
+ return rm;
+ }
+ else
+ {
+ amount &= 0x1F;
+ this.shifterCarry = (rm >> amount) & 1;
+ return (rm >> amount) | (rm << (32 - amount));
+ }
+ }
+ }
+ else
+ {
+ switch (type)
+ {
+ case SHIFT_LSL:
+ if (amount == 0)
+ {
+ this.shifterCarry = this.carry;
+ return rm;
+ }
+ else
+ {
+ this.shifterCarry = (rm >> (32 - amount)) & 1;
+ return rm << amount;
+ }
+
+ case SHIFT_LSR:
+ if (amount == 0)
+ {
+ this.shifterCarry = (rm >> 31) & 1;
+ return 0;
+ }
+ else
+ {
+ this.shifterCarry = (rm >> (amount - 1)) & 1;
+ return rm >> amount;
+ }
+
+ case SHIFT_ASR:
+ if (amount == 0)
+ {
+ if ((rm & (1 << 31)) == 0)
+ {
+ this.shifterCarry = 0;
+ return 0;
+ }
+ else
+ {
+ this.shifterCarry = 1;
+ return 0xFFFFFFFF;
+ }
+ }
+ else
+ {
+ this.shifterCarry = (rm >> (amount - 1)) & 1;
+ return (uint)(((int)rm) >> amount);
+ }
+
+ case SHIFT_ROR:
+ if (amount == 0)
+ {
+ // Actually an RRX
+ this.shifterCarry = rm & 1;
+ return (this.carry << 31) | (rm >> 1);
+ }
+ else
+ {
+ this.shifterCarry = (rm >> (amount - 1)) & 1;
+ return (rm >> amount) | (rm << (32 - amount));
+ }
+ }
+ }
+
+ // Should never happen...
+ throw new Exception("Barrel Shifter has messed up.");
+ }
+ #endregion
+
+ #region Flag helpers
+ public void OverflowCarryAdd(uint a, uint b, uint r)
+ {
+ overflow = ((a & b & ~r) | (~a & ~b & r)) >> 31;
+ carry = ((a & b) | (a & ~r) | (b & ~r)) >> 31;
+ }
+
+ public void OverflowCarrySub(uint a, uint b, uint r)
+ {
+ overflow = ((a & ~b & ~r) | (~a & b & r)) >> 31;
+ carry = ((a & ~b) | (a & ~r) | (~b & ~r)) >> 31;
+ }
+ #endregion
+ #region Opcodes
+ private void DoDataProcessing(uint shifterOperand)
+ {
+ uint rn = (this.curInstruction >> 16) & 0xF;
+ uint rd = (this.curInstruction >> 12) & 0xF;
+ uint alu;
+
+ bool registerShift = (this.curInstruction & (1 << 4)) == (1 << 4);
+ if (rn == 15 && ((this.curInstruction >> 25) & 0x7) == 0 && registerShift)
+ {
+ rn = registers[rn] + 4;
+ }
+ else
+ {
+ rn = registers[rn];
+ }
+
+ uint opcode = (this.curInstruction >> 21) & 0xF;
+
+ if (((this.curInstruction >> 20) & 1) == 1)
+ {
+ // Set flag bit set
+ switch (opcode)
+ {
+ case OP_ADC:
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+ break;
+
+ case OP_ADD:
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+ break;
+
+ case OP_AND:
+ registers[rd] = rn & shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case OP_BIC:
+ registers[rd] = rn & ~shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case OP_CMN:
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ break;
+
+ case OP_CMP:
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ break;
+
+ case OP_EOR:
+ registers[rd] = rn ^ shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case OP_MOV:
+ registers[rd] = shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case OP_MVN:
+ registers[rd] = ~shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case OP_ORR:
+ registers[rd] = rn | shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case OP_RSB:
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+ break;
+
+ case OP_RSC:
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+ break;
+
+ case OP_SBC:
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+ break;
+
+ case OP_SUB:
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+ break;
+
+ case OP_TEQ:
+ alu = rn ^ shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+
+ case OP_TST:
+ alu = rn & shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ break;
+ }
+
+ if (rd == 15)
+ {
+ // Prevent writing if no SPSR exists (this will be true for USER or SYSTEM mode)
+ if (this.parent.SPSRExists) this.parent.WriteCpsr(this.parent.SPSR);
+ this.UnpackFlags();
+
+ // Check for branch back to Thumb Mode
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbMode = true;
+ return;
+ }
+
+ // Otherwise, flush the instruction queue
+ this.FlushQueue();
+ }
+ }
+ else
+ {
+ // Set flag bit not set
+ switch (opcode)
+ {
+ case OP_ADC: registers[rd] = rn + shifterOperand + carry; break;
+ case OP_ADD: registers[rd] = rn + shifterOperand; break;
+ case OP_AND: registers[rd] = rn & shifterOperand; break;
+ case OP_BIC: registers[rd] = rn & ~shifterOperand; break;
+ case OP_EOR: registers[rd] = rn ^ shifterOperand; break;
+ case OP_MOV: registers[rd] = shifterOperand; break;
+ case OP_MVN: registers[rd] = ~shifterOperand; break;
+ case OP_ORR: registers[rd] = rn | shifterOperand; break;
+ case OP_RSB: registers[rd] = shifterOperand - rn; break;
+ case OP_RSC: registers[rd] = shifterOperand - rn - (1U - carry); break;
+ case OP_SBC: registers[rd] = rn - shifterOperand - (1U - carry); break;
+ case OP_SUB: registers[rd] = rn - shifterOperand; break;
+
+ case OP_CMN:
+ // MSR SPSR, shifterOperand
+ if ((this.curInstruction & (1 << 16)) == 1 << 16 && this.parent.SPSRExists)
+ {
+ this.parent.SPSR &= 0xFFFFFF00;
+ this.parent.SPSR |= shifterOperand & 0x000000FF;
+ }
+ if ((this.curInstruction & (1 << 17)) == 1 << 17 && this.parent.SPSRExists)
+ {
+ this.parent.SPSR &= 0xFFFF00FF;
+ this.parent.SPSR |= shifterOperand & 0x0000FF00;
+ }
+ if ((this.curInstruction & (1 << 18)) == 1 << 18 && this.parent.SPSRExists)
+ {
+ this.parent.SPSR &= 0xFF00FFFF;
+ this.parent.SPSR |= shifterOperand & 0x00FF0000;
+ }
+ if ((this.curInstruction & (1 << 19)) == 1 << 19 && this.parent.SPSRExists)
+ {
+ this.parent.SPSR &= 0x00FFFFFF;
+ this.parent.SPSR |= shifterOperand & 0xFF000000;
+ }
+
+ // Queue will be flushed since rd == 15, so adjust the PC
+ registers[15] -= 4;
+ break;
+
+ case OP_CMP:
+ // MRS rd, SPSR
+ if (this.parent.SPSRExists) registers[rd] = this.parent.SPSR;
+ break;
+
+ case OP_TEQ:
+ if (((this.curInstruction >> 4) & 0xf) == 1)
+ {
+ // BX
+ uint rm = this.curInstruction & 0xf;
+
+ this.PackFlags();
+
+ this.parent.CPSR &= ~Arm7Processor.T_MASK;
+ this.parent.CPSR |= (registers[rm] & 1) << Arm7Processor.T_BIT;
+
+ registers[15] = registers[rm] & (~1U);
+
+ this.UnpackFlags();
+
+ // Check for branch back to Thumb Mode
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbMode = true;
+ return;
+ }
+
+ // Queue will be flushed later because rd == 15
+ }
+ else if (((this.curInstruction >> 4) & 0xf) == 0)
+ {
+ // MSR CPSR, shifterOperand
+ bool userMode = (this.parent.CPSR & 0x1F) == Arm7Processor.USR;
+
+ this.PackFlags();
+
+ uint tmpCPSR = this.parent.CPSR;
+
+ if ((this.curInstruction & (1 << 16)) == 1 << 16 && !userMode)
+ {
+ tmpCPSR &= 0xFFFFFF00;
+ tmpCPSR |= shifterOperand & 0x000000FF;
+ }
+ if ((this.curInstruction & (1 << 17)) == 1 << 17 && !userMode)
+ {
+ tmpCPSR &= 0xFFFF00FF;
+ tmpCPSR |= shifterOperand & 0x0000FF00;
+ }
+ if ((this.curInstruction & (1 << 18)) == 1 << 18 && !userMode)
+ {
+ tmpCPSR &= 0xFF00FFFF;
+ tmpCPSR |= shifterOperand & 0x00FF0000;
+ }
+ if ((this.curInstruction & (1 << 19)) == 1 << 19)
+ {
+ tmpCPSR &= 0x00FFFFFF;
+ tmpCPSR |= shifterOperand & 0xFF000000;
+ }
+
+ this.parent.WriteCpsr(tmpCPSR);
+
+ this.UnpackFlags();
+
+ // Check for branch back to Thumb Mode
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbMode = true;
+ return;
+ }
+
+ // Queue will be flushed since rd == 15, so adjust the PC
+ registers[15] -= 4;
+ }
+ break;
+
+ case OP_TST:
+ // MRS rd, CPSR
+ this.PackFlags();
+ registers[rd] = this.parent.CPSR;
+ break;
+ }
+
+ if (rd == 15)
+ {
+ // Flush the queue
+ this.FlushQueue();
+ }
+ }
+ }
+
+ private void DataProcessing()
+ {
+ // Special instruction
+ switch ((this.curInstruction >> 4) & 0xF)
+ {
+ case 0x9:
+ // Multiply or swap instructions
+ this.MultiplyOrSwap();
+ return;
+ case 0xB:
+ // Load/Store Unsigned halfword
+ this.LoadStoreHalfword();
+ return;
+ case 0xD:
+ // Load/Store Signed byte
+ this.LoadStoreHalfword();
+ return;
+ case 0xF:
+ // Load/Store Signed halfword
+ this.LoadStoreHalfword();
+ return;
+ }
+
+ this.DoDataProcessing(this.BarrelShifter(this.curInstruction));
+ }
+
+ private void DataProcessingImmed()
+ {
+ uint immed = this.curInstruction & 0xFF;
+ int rotateAmount = (int)(((this.curInstruction >> 8) & 0xF) * 2);
+
+ immed = (immed >> rotateAmount) | (immed << (32 - rotateAmount));
+
+ if (rotateAmount == 0)
+ {
+ this.shifterCarry = this.carry;
+ }
+ else
+ {
+ this.shifterCarry = (immed >> 31) & 1;
+ }
+
+ this.DoDataProcessing(immed);
+ }
+
+ private void LoadStore(uint offset)
+ {
+ uint rn = (this.curInstruction >> 16) & 0xF;
+ uint rd = (this.curInstruction >> 12) & 0xF;
+
+ uint address = registers[rn];
+
+ bool preIndexed = (this.curInstruction & (1 << 24)) == 1 << 24;
+ bool byteTransfer = (this.curInstruction & (1 << 22)) == 1 << 22;
+ bool writeback = (this.curInstruction & (1 << 21)) == 1 << 21;
+
+ // Add or subtract offset
+ if ((this.curInstruction & (1 << 23)) != 1 << 23) offset = (uint)-offset;
+
+ if (preIndexed)
+ {
+ address += offset;
+
+ if (writeback)
+ {
+ registers[rn] = address;
+ }
+ }
+
+ if ((this.curInstruction & (1 << 20)) == 1 << 20)
+ {
+ // Load
+ if (byteTransfer)
+ {
+ registers[rd] = this.memory.ReadU8(address);
+ }
+ else
+ {
+ registers[rd] = this.memory.ReadU32(address);
+ }
+
+ // ARM9 fix here
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (!preIndexed)
+ {
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ }
+ else
+ {
+ // Store
+ uint amount = registers[rd];
+ if (rd == 15) amount += 4;
+
+ if (byteTransfer)
+ {
+ this.memory.WriteU8(address, (byte)(amount & 0xFF));
+ }
+ else
+ {
+ this.memory.WriteU32(address, amount);
+ }
+
+ if (!preIndexed)
+ {
+ registers[rn] = address + offset;
+ }
+ }
+ }
+
+ private void LoadStoreImmediate()
+ {
+ this.LoadStore(this.curInstruction & 0xFFF);
+ }
+
+ private void LoadStoreRegister()
+ {
+ // The barrel shifter expects a 0 in bit 4 for immediate shifts, this is implicit in
+ // the meaning of the instruction, so it is fine
+ this.LoadStore(this.BarrelShifter(this.curInstruction));
+ }
+
+ private void LoadStoreMultiple()
+ {
+ uint rn = (this.curInstruction >> 16) & 0xF;
+
+ this.PackFlags();
+ uint curCpsr = this.parent.CPSR;
+
+ bool preIncrement = (this.curInstruction & (1 << 24)) != 0;
+ bool up = (this.curInstruction & (1 << 23)) != 0;
+ bool writeback = (this.curInstruction & (1 << 21)) != 0;
+
+ uint address;
+ uint bitsSet = 0;
+ for (int i = 0; i < 16; i++) if (((this.curInstruction >> i) & 1) != 0) bitsSet++;
+
+ if (preIncrement)
+ {
+ if (up)
+ {
+ // Increment before
+ address = this.registers[rn] + 4;
+ if (writeback) this.registers[rn] += bitsSet * 4;
+ }
+ else
+ {
+ // Decrement before
+ address = this.registers[rn] - (bitsSet * 4);
+ if (writeback) this.registers[rn] -= bitsSet * 4;
+ }
+ }
+ else
+ {
+ if (up)
+ {
+ // Increment after
+ address = this.registers[rn];
+ if (writeback) this.registers[rn] += bitsSet * 4;
+ }
+ else
+ {
+ // Decrement after
+ address = this.registers[rn] - (bitsSet * 4) + 4;
+ if (writeback) this.registers[rn] -= bitsSet * 4;
+ }
+ }
+
+ if ((this.curInstruction & (1 << 20)) != 0)
+ {
+ if ((this.curInstruction & (1 << 22)) != 0 && ((this.curInstruction >> 15) & 1) == 0)
+ {
+ // Switch to user mode temporarily
+ this.parent.WriteCpsr((curCpsr & ~0x1FU) | Arm7Processor.USR);
+ }
+
+ // Load multiple
+ for (int i = 0; i < 15; i++)
+ {
+ if (((this.curInstruction >> i) & 1) != 1) continue;
+ this.registers[i] = this.memory.ReadU32Aligned(address & (~0x3U));
+ address += 4;
+ }
+
+ if (((this.curInstruction >> 15) & 1) == 1)
+ {
+ // Arm9 fix here
+
+ this.registers[15] = this.memory.ReadU32Aligned(address & (~0x3U));
+
+ if ((this.curInstruction & (1 << 22)) != 0)
+ {
+ // Load the CPSR from the SPSR
+ if (this.parent.SPSRExists)
+ {
+ this.parent.WriteCpsr(this.parent.SPSR);
+ this.UnpackFlags();
+
+ // Check for branch back to Thumb Mode
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbMode = true;
+ this.registers[15] &= ~0x1U;
+ return;
+ }
+ }
+ }
+
+ this.registers[15] &= ~0x3U;
+ this.FlushQueue();
+ }
+ else
+ {
+ if ((this.curInstruction & (1 << 22)) != 0)
+ {
+ // Switch back to the correct mode
+ this.parent.WriteCpsr(curCpsr);
+ this.UnpackFlags();
+
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbMode = true;
+ return;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ((this.curInstruction & (1 << 22)) != 0)
+ {
+ // Switch to user mode temporarily
+ this.parent.WriteCpsr((curCpsr & ~0x1FU) | Arm7Processor.USR);
+ }
+
+/* if (((this.curInstruction >> (int)rn) & 1) != 0 && writeback &&
+ (this.curInstruction & ~(0xFFFFFFFF << (int)rn)) == 0)
+ {
+ // If the lowest register is also the writeback, we use the original value
+ // Does anybody do this????
+ throw new Exception("Unhandled STM state");
+ }
+ else*/
+ {
+ // Store multiple
+ for (int i = 0; i < 15; i++)
+ {
+ if (((this.curInstruction >> i) & 1) == 0) continue;
+ this.memory.WriteU32(address, this.registers[i]);
+ address += 4;
+ }
+
+ if (((this.curInstruction >> 15) & 1) != 0)
+ {
+ this.memory.WriteU32(address, this.registers[15] + 4U);
+ }
+ }
+
+ if ((this.curInstruction & (1 << 22)) != 0)
+ {
+ // Switch back to the correct mode
+ this.parent.WriteCpsr(curCpsr);
+ this.UnpackFlags();
+ }
+ }
+ }
+
+ private void Branch()
+ {
+ if ((this.curInstruction & (1 << 24)) != 0)
+ {
+ this.registers[14] = (this.registers[15] - 4U) & ~3U;
+ }
+
+ uint branchOffset = this.curInstruction & 0x00FFFFFF;
+ if (branchOffset >> 23 == 1) branchOffset |= 0xFF000000;
+
+ this.registers[15] += branchOffset << 2;
+
+ this.FlushQueue();
+ }
+
+ private void CoprocessorLoadStore()
+ {
+ throw new Exception("Unhandled opcode - coproc load/store");
+ }
+
+ private void SoftwareInterrupt()
+ {
+ // Adjust PC for prefetch
+ this.registers[15] -= 4U;
+ this.parent.EnterException(Arm7Processor.SVC, 0x8, false, false);
+ }
+
+ private void MultiplyOrSwap()
+ {
+ if ((this.curInstruction & (1 << 24)) == 1 << 24)
+ {
+ // Swap instruction
+ uint rn = (this.curInstruction >> 16) & 0xF;
+ uint rd = (this.curInstruction >> 12) & 0xF;
+ uint rm = this.curInstruction & 0xF;
+
+ if ((this.curInstruction & (1 << 22)) != 0)
+ {
+ // SWPB
+ byte tmp = this.memory.ReadU8(registers[rn]);
+ this.memory.WriteU8(registers[rn], (byte)(registers[rm] & 0xFF));
+ registers[rd] = tmp;
+ }
+ else
+ {
+ // SWP
+ uint tmp = this.memory.ReadU32(registers[rn]);
+ this.memory.WriteU32(registers[rn], registers[rm]);
+ registers[rd] = tmp;
+ }
+ }
+ else
+ {
+ // Multiply instruction
+ switch ((this.curInstruction >> 21) & 0x7)
+ {
+ case 0:
+ case 1:
+ {
+ // Multiply/Multiply + Accumulate
+ uint rd = (this.curInstruction >> 16) & 0xF;
+ uint rn = registers[(this.curInstruction >> 12) & 0xF];
+ uint rs = (this.curInstruction >> 8) & 0xF;
+ uint rm = this.curInstruction & 0xF;
+
+ int cycles = 4;
+ // Multiply cycle calculations
+ if ((registers[rs] & 0xFFFFFF00) == 0 || (registers[rs] & 0xFFFFFF00) == 0xFFFFFF00)
+ {
+ cycles = 1;
+ }
+ else if ((registers[rs] & 0xFFFF0000) == 0 || (registers[rs] & 0xFFFF0000) == 0xFFFF0000)
+ {
+ cycles = 2;
+ }
+ else if ((registers[rs] & 0xFF000000) == 0 || (registers[rs] & 0xFF000000) == 0xFF000000)
+ {
+ cycles = 3;
+ }
+
+ registers[rd] = registers[rs] * registers[rm];
+ this.parent.Cycles -= cycles;
+
+ if ((this.curInstruction & (1 << 21)) == 1 << 21)
+ {
+ registers[rd] += rn;
+ this.parent.Cycles -= 1;
+ }
+
+ if ((this.curInstruction & (1 << 20)) == 1 << 20)
+ {
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ }
+ break;
+ }
+
+ case 2:
+ case 3:
+ throw new Exception("Invalid multiply");
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ {
+ // Multiply/Signed Multiply Long
+ uint rdhi = (this.curInstruction >> 16) & 0xF;
+ uint rdlo = (this.curInstruction >> 12) & 0xF;
+ uint rs = (this.curInstruction >> 8) & 0xF;
+ uint rm = this.curInstruction & 0xF;
+
+ int cycles = 5;
+ // Multiply cycle calculations
+ if ((registers[rs] & 0xFFFFFF00) == 0 || (registers[rs] & 0xFFFFFF00) == 0xFFFFFF00)
+ {
+ cycles = 2;
+ }
+ else if ((registers[rs] & 0xFFFF0000) == 0 || (registers[rs] & 0xFFFF0000) == 0xFFFF0000)
+ {
+ cycles = 3;
+ }
+ else if ((registers[rs] & 0xFF000000) == 0 || (registers[rs] & 0xFF000000) == 0xFF000000)
+ {
+ cycles = 4;
+ }
+
+ this.parent.Cycles -= cycles;
+
+ switch ((this.curInstruction >> 21) & 0x3)
+ {
+ case 0:
+ {
+ // UMULL
+ ulong result = ((ulong)registers[rm]) * registers[rs];
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+ break;
+ }
+ case 1:
+ {
+ // UMLAL
+ ulong accum = (((ulong)registers[rdhi]) << 32) | registers[rdlo];
+ ulong result = ((ulong)registers[rm]) * registers[rs];
+ result += accum;
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+ break;
+ }
+ case 2:
+ {
+ // SMULL
+ long result = ((long)((int)registers[rm])) * ((long)((int)registers[rs]));
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+ break;
+ }
+ case 3:
+ {
+ // SMLAL
+ long accum = (((long)((int)registers[rdhi])) << 32) | registers[rdlo];
+ long result = ((long)((int)registers[rm])) * ((long)((int)registers[rs]));
+ result += accum;
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+ break;
+ }
+ }
+
+ if ((this.curInstruction & (1 << 20)) == 1 << 20)
+ {
+ negative = registers[rdhi] >> 31;
+ zero = (registers[rdhi] == 0 && registers[rdlo] == 0) ? 1U : 0U;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ private void LoadStoreHalfword()
+ {
+ uint rn = (this.curInstruction >> 16) & 0xF;
+ uint rd = (this.curInstruction >> 12) & 0xF;
+
+ uint address = registers[rn];
+
+ bool preIndexed = (this.curInstruction & (1 << 24)) != 0;
+ bool byteTransfer = (this.curInstruction & (1 << 5)) == 0;
+ bool signedTransfer = (this.curInstruction & (1 << 6)) != 0;
+ bool writeback = (this.curInstruction & (1 << 21)) != 0;
+
+ uint offset;
+ if ((this.curInstruction & (1 << 22)) != 0)
+ {
+ // Immediate offset
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ }
+ else
+ {
+ // Register offset
+ offset = this.registers[this.curInstruction & 0xF];
+ }
+
+ // Add or subtract offset
+ if ((this.curInstruction & (1 << 23)) == 0) offset = (uint)-offset;
+
+ if (preIndexed)
+ {
+ address += offset;
+
+ if (writeback)
+ {
+ registers[rn] = address;
+ }
+ }
+
+ if ((this.curInstruction & (1 << 20)) != 0)
+ {
+ // Load
+ if (byteTransfer)
+ {
+ if (signedTransfer)
+ {
+ registers[rd] = this.memory.ReadU8(address);
+ if ((registers[rd] & 0x80) != 0)
+ {
+ registers[rd] |= 0xFFFFFF00;
+ }
+ }
+ else
+ {
+ registers[rd] = this.memory.ReadU8(address);
+ }
+ }
+ else
+ {
+ if (signedTransfer)
+ {
+ registers[rd] = this.memory.ReadU16(address);
+ if ((registers[rd] & 0x8000) != 0)
+ {
+ registers[rd] |= 0xFFFF0000;
+ }
+ }
+ else
+ {
+ registers[rd] = this.memory.ReadU16(address);
+ }
+ }
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (!preIndexed)
+ {
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ }
+ else
+ {
+ // Store
+ if (byteTransfer)
+ {
+ this.memory.WriteU8(address, (byte)(registers[rd] & 0xFF));
+ }
+ else
+ {
+ this.memory.WriteU16(address, (ushort)(registers[rd] & 0xFFFF));
+ }
+
+ if (!preIndexed)
+ {
+ registers[rn] = address + offset;
+ }
+ }
+ }
+ #endregion Opcodes
+
+ private void PackFlags()
+ {
+ this.parent.CPSR &= 0x0FFFFFFF;
+ this.parent.CPSR |= this.negative << Arm7Processor.N_BIT;
+ this.parent.CPSR |= this.zero << Arm7Processor.Z_BIT;
+ this.parent.CPSR |= this.carry << Arm7Processor.C_BIT;
+ this.parent.CPSR |= this.overflow << Arm7Processor.V_BIT;
+ }
+
+ private void UnpackFlags()
+ {
+ this.negative = (this.parent.CPSR >> Arm7Processor.N_BIT) & 1;
+ this.zero = (this.parent.CPSR >> Arm7Processor.Z_BIT) & 1;
+ this.carry = (this.parent.CPSR >> Arm7Processor.C_BIT) & 1;
+ this.overflow = (this.parent.CPSR >> Arm7Processor.V_BIT) & 1;
+ }
+
+ private void FlushQueue()
+ {
+ this.instructionQueue = this.memory.ReadU32(registers[15]);
+ registers[15] += 4;
+ }
+ }
+}
\ No newline at end of file
diff --git a/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/FastDispatchCore.cs b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/FastDispatchCore.cs
new file mode 100644
index 0000000000..cb2c5e6a0f
--- /dev/null
+++ b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/FastDispatchCore.cs
@@ -0,0 +1,8469 @@
+namespace GarboDev
+{
+ partial class FastArmCore
+ {
+ #region Delegate Dispatcher
+ private void DispatchFunc0()
+ {
+ uint rn, rd;
+ // AND rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterLslImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc1()
+ {
+ uint rn, rd;
+ // AND rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterLslReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc2()
+ {
+ uint rn, rd;
+ // AND rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterLsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc3()
+ {
+ uint rn, rd;
+ // AND rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterLsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc4()
+ {
+ uint rn, rd;
+ // AND rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterAsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc5()
+ {
+ uint rn, rd;
+ // AND rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterAsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc6()
+ {
+ uint rn, rd;
+ // AND rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterRorImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc7()
+ {
+ uint rn, rd;
+ // AND rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterRorReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc8()
+ {
+ uint rn, rd;
+ // ANDS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterLslImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc9()
+ {
+ uint rn, rd;
+ // ANDS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterLslReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc10()
+ {
+ uint rn, rd;
+ // ANDS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterLsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc11()
+ {
+ uint rn, rd;
+ // ANDS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterLsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc12()
+ {
+ uint rn, rd;
+ // ANDS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterAsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc13()
+ {
+ uint rn, rd;
+ // ANDS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterAsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc14()
+ {
+ uint rn, rd;
+ // ANDS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterRorImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc15()
+ {
+ uint rn, rd;
+ // ANDS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & BarrelShifterRorReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc16()
+ {
+ UndefinedInstruction();
+ }
+ private void DispatchFunc17()
+ {
+ uint rd, rs, rm;
+ int cycles;
+ // MUL rd, rm, rs
+ rd = (this.curInstruction >> 16) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs);
+
+ registers[rd] = registers[rs] * registers[rm];
+ this.parent.Cycles -= cycles;
+ }
+ private void DispatchFunc18()
+ {
+ uint rd, rs, rm;
+ int cycles;
+ // MULS rd, rm, rs
+ rd = (this.curInstruction >> 16) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs);
+
+ registers[rd] = registers[rs] * registers[rm];
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+
+ this.parent.Cycles -= cycles;
+ }
+ private void DispatchFunc19()
+ {
+ uint rn, rd, rs, rm;
+ int cycles;
+ // MLA rd, rm, rs, rn
+ rd = (this.curInstruction >> 16) & 0xF;
+ rn = registers[(this.curInstruction >> 12) & 0xF];
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs);
+
+ registers[rd] = registers[rs] * registers[rm] + rn;
+ this.parent.Cycles -= cycles + 1;
+ }
+ private void DispatchFunc20()
+ {
+ uint rn, rd, rs, rm;
+ int cycles;
+ // MLAS rd, rm, rs
+ rd = (this.curInstruction >> 16) & 0xF;
+ rn = registers[(this.curInstruction >> 12) & 0xF];
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs);
+
+ registers[rd] = registers[rs] * registers[rm] + rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+
+ this.parent.Cycles -= cycles + 1;
+ }
+ private void DispatchFunc21()
+ {
+ uint rs, rm;
+ int cycles;
+ // UMULL rdlo, rdhi, rm, rs
+ {
+ uint rdhi = (this.curInstruction >> 16) & 0xF;
+ uint rdlo = (this.curInstruction >> 12) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs) + 1;
+
+ ulong result = ((ulong)registers[rm]) * registers[rs];
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+
+ this.parent.Cycles -= cycles;
+ }
+ }
+ private void DispatchFunc22()
+ {
+ uint rs, rm;
+ int cycles;
+ // UMULLS rdlo, rdhi, rm, rs
+ {
+ uint rdhi = (this.curInstruction >> 16) & 0xF;
+ uint rdlo = (this.curInstruction >> 12) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs) + 1;
+
+ ulong result = ((ulong)registers[rm]) * registers[rs];
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+
+ negative = registers[rdhi] >> 31;
+ zero = (registers[rdhi] == 0 && registers[rdlo] == 0) ? 1U : 0U;
+
+ this.parent.Cycles -= cycles;
+ }
+ }
+ private void DispatchFunc23()
+ {
+ uint rs, rm;
+ int cycles;
+ // UMLAL rdlo, rdhi, rm, rs
+ {
+ uint rdhi = (this.curInstruction >> 16) & 0xF;
+ uint rdlo = (this.curInstruction >> 12) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs) + 2;
+
+ ulong accum = (((ulong)registers[rdhi]) << 32) | registers[rdlo];
+ ulong result = ((ulong)registers[rm]) * registers[rs];
+ result += accum;
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+
+ this.parent.Cycles -= cycles;
+ }
+ }
+ private void DispatchFunc24()
+ {
+ uint rs, rm;
+ int cycles;
+ // UMLALS rdlo, rdhi, rm, rs
+ {
+ uint rdhi = (this.curInstruction >> 16) & 0xF;
+ uint rdlo = (this.curInstruction >> 12) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs) + 2;
+
+ ulong accum = (((ulong)registers[rdhi]) << 32) | registers[rdlo];
+ ulong result = ((ulong)registers[rm]) * registers[rs];
+ result += accum;
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+
+ negative = registers[rdhi] >> 31;
+ zero = (registers[rdhi] == 0 && registers[rdlo] == 0) ? 1U : 0U;
+
+ this.parent.Cycles -= cycles;
+ }
+ }
+ private void DispatchFunc25()
+ {
+ uint rs, rm;
+ int cycles;
+ // SMULL rdlo, rdhi, rm, rs
+ {
+ uint rdhi = (this.curInstruction >> 16) & 0xF;
+ uint rdlo = (this.curInstruction >> 12) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs) + 1;
+
+ long result = ((long)((int)registers[rm])) * ((long)((int)registers[rs]));
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+
+ this.parent.Cycles -= cycles;
+ }
+ }
+ private void DispatchFunc26()
+ {
+ uint rs, rm;
+ int cycles;
+ // SMULLS rdlo, rdhi, rm, rs
+ {
+ uint rdhi = (this.curInstruction >> 16) & 0xF;
+ uint rdlo = (this.curInstruction >> 12) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs) + 1;
+
+ long result = ((long)((int)registers[rm])) * ((long)((int)registers[rs]));
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+
+ negative = registers[rdhi] >> 31;
+ zero = (registers[rdhi] == 0 && registers[rdlo] == 0) ? 1U : 0U;
+
+ this.parent.Cycles -= cycles;
+ }
+ }
+ private void DispatchFunc27()
+ {
+ uint rs, rm;
+ int cycles;
+ // SMLAL rdlo, rdhi, rm, rs
+ {
+ uint rdhi = (this.curInstruction >> 16) & 0xF;
+ uint rdlo = (this.curInstruction >> 12) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs) + 2;
+
+ long accum = (((long)((int)registers[rdhi])) << 32) | registers[rdlo];
+ long result = ((long)((int)registers[rm])) * ((long)((int)registers[rs]));
+ result += accum;
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+
+ this.parent.Cycles -= cycles;
+ }
+ }
+ private void DispatchFunc28()
+ {
+ uint rs, rm;
+ int cycles;
+ // SMLALS rdlo, rdhi, rm, rs
+ {
+ uint rdhi = (this.curInstruction >> 16) & 0xF;
+ uint rdlo = (this.curInstruction >> 12) & 0xF;
+ rs = (this.curInstruction >> 8) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ cycles = this.MultiplyCycleCalculation(rs) + 2;
+
+ long accum = (((long)((int)registers[rdhi])) << 32) | registers[rdlo];
+ long result = ((long)((int)registers[rm])) * ((long)((int)registers[rs]));
+ result += accum;
+ registers[rdhi] = (uint)(result >> 32);
+ registers[rdlo] = (uint)(result & 0xFFFFFFFF);
+
+ negative = registers[rdhi] >> 31;
+ zero = (registers[rdhi] == 0 && registers[rdlo] == 0) ? 1U : 0U;
+
+ this.parent.Cycles -= cycles;
+ }
+ }
+ private void DispatchFunc29()
+ {
+ uint rn, rd, address, offset;
+ // STRH rd, [rn], -rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ this.memory.WriteU16(address, (ushort)(registers[rd] & 0xFFFF));
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc30()
+ {
+ uint rn, rd, address, offset;
+ // Writeback bit set, instruction is unpredictable
+ // STRH rd, [rn], -rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ this.memory.WriteU16(address, (ushort)(registers[rd] & 0xFFFF));
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc31()
+ {
+ uint rn, rd, address, offset;
+ // STRH rd, [rn], -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ this.memory.WriteU16(address, (ushort)(registers[rd] & 0xFFFF));
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc32()
+ {
+ uint rn, rd, address, offset;
+ // Writeback bit set, instruction is unpredictable
+ // STRH rd, [rn], -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ this.memory.WriteU16(address, (ushort)(registers[rd] & 0xFFFF));
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc33()
+ {
+ uint rn, rd, address, offset;
+ // STRH rd, [rn], rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ this.memory.WriteU16(address, (ushort)(registers[rd] & 0xFFFF));
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc34()
+ {
+ uint rn, rd, address, offset;
+ // Writeback bit set, instruction is unpredictable
+ // STRH rd, [rn], rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ this.memory.WriteU16(address, (ushort)(registers[rd] & 0xFFFF));
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc35()
+ {
+ uint rn, rd, address, offset;
+ // STRH rd, [rn], immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ this.memory.WriteU16(address, (ushort)(registers[rd] & 0xFFFF));
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc36()
+ {
+ uint rn, rd, address, offset;
+ // Writeback bit set, instruction is unpredictable
+ // STRH rd, [rn], immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ this.memory.WriteU16(address, (ushort)(registers[rd] & 0xFFFF));
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc37()
+ {
+ uint rn, rd, offset;
+ // STRH rd, [rn, -rm]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ this.memory.WriteU16(registers[rn] + offset, (ushort)(registers[rd] & 0xFFFF));
+ }
+ private void DispatchFunc38()
+ {
+ uint rn, rd, offset;
+ // STRH rd, [rn, -rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ this.memory.WriteU16(registers[rn], (ushort)(registers[rd] & 0xFFFF));
+ }
+ private void DispatchFunc39()
+ {
+ uint rn, rd, offset;
+ // STRH rd, [rn, -immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ this.memory.WriteU16(registers[rn] + offset, (ushort)(registers[rd] & 0xFFFF));
+ }
+ private void DispatchFunc40()
+ {
+ uint rn, rd, offset;
+ // STRH rd, [rn], -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ this.memory.WriteU16(registers[rn], (ushort)(registers[rd] & 0xFFFF));
+ }
+ private void DispatchFunc41()
+ {
+ uint rn, rd, offset;
+ // STRH rd, [rn, rm]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ this.memory.WriteU16(registers[rn] + offset, (ushort)(registers[rd] & 0xFFFF));
+ }
+ private void DispatchFunc42()
+ {
+ uint rn, rd, offset;
+ // STRH rd, [rn, rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rn] += offset;
+ this.memory.WriteU16(registers[rn], (ushort)(registers[rd] & 0xFFFF));
+ }
+ private void DispatchFunc43()
+ {
+ uint rn, rd, offset;
+ // STRH rd, [rn, immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ this.memory.WriteU16(registers[rn] + offset, (ushort)(registers[rd] & 0xFFFF));
+ }
+ private void DispatchFunc44()
+ {
+ uint rn, rd, offset;
+ // STRH rd, [rn, immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rn] += offset;
+ this.memory.WriteU16(registers[rn], (ushort)(registers[rd] & 0xFFFF));
+ }
+ private void DispatchFunc45()
+ {
+ uint rn, rd, address, offset;
+ // LDRH rd, [rn], -rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc46()
+ {
+ uint rn, rd, address, offset;
+ // Writeback bit set, instruction is unpredictable
+ // LDRH rd, [rn], -rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc47()
+ {
+ uint rn, rd, address, offset;
+ // LDRH rd, [rn], -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc48()
+ {
+ uint rn, rd, address, offset;
+ // Writeback bit set, instruction is unpredictable
+ // LDRH rd, [rn], -rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc49()
+ {
+ uint rn, rd, address, offset;
+ // LDRH rd, [rn], rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc50()
+ {
+ uint rn, rd, address, offset;
+ // Writeback bit set, instruction is unpredictable
+ // LDRH rd, [rn], rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc51()
+ {
+ uint rn, rd, address, offset;
+ // LDRH rd, [rn], immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rd] = this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc52()
+ {
+ uint rn, rd, address, offset;
+ // Writeback bit set, instruction is unpredictable
+ // LDRH rd, [rn], rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rd] = this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc53()
+ {
+ uint rn, rd, offset;
+ // LDRH rd, [rn, -rm]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU16(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc54()
+ {
+ uint rn, rd, offset;
+ // LDRH rd, [rn, -rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+
+ registers[rd] = this.memory.ReadU16(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc55()
+ {
+ uint rn, rd, offset;
+ // LDRH rd, [rn, -immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU16(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc56()
+ {
+ uint rn, rd, offset;
+ // LDRH rd, [rn, -rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU16(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc57()
+ {
+ uint rn, rd, offset;
+ // LDRH rd, [rn, rm]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = this.memory.ReadU16(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc58()
+ {
+ uint rn, rd, offset;
+ // LDRH rd, [rn, rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU16(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc59()
+ {
+ uint rn, rd, offset;
+ // LDRH rd, [rn, immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rd] = this.memory.ReadU16(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc60()
+ {
+ uint rn, rd, offset;
+ // LDRH rd, [rn, rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU16(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc61()
+ {
+ uint rn, rd, address, offset;
+ // LDRSB rd, [rn], -rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc62()
+ {
+ uint rn, rd, address, offset;
+ // Writeback bit set, instruction is unpredictable
+ // LDRSB rd, [rn], -rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc63()
+ {
+ uint rn, rd, address, offset;
+ // LDRSB rd, [rn], -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc64()
+ {
+ uint rn, rd, address, offset;
+ // Writeback bit set, instruction is unpredictable
+ // LDRSB rd, [rn], -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc65()
+ {
+ uint rn, rd, address, offset;
+ // LDRSB rd, [rn], rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc66()
+ {
+ uint rn, rd, address, offset;
+ // Writeback bit set, instruction is unpredictable
+ // LDRSB rd, [rn], rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc67()
+ {
+ uint rn, rd, address, offset;
+ // LDRSB rd, [rn], immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc68()
+ {
+ uint rn, rd, address, offset;
+ // Writeback bit set, instruction is unpredictable
+ // LDRSB rd, [rn], immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc69()
+ {
+ uint rn, rd, offset;
+ // LDRSB rd, [rn, -rm]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc70()
+ {
+ uint rn, rd, offset;
+ // LDRSB rd, [rn, -rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc71()
+ {
+ uint rn, rd, offset;
+ // LDRSB rd, [rn, -immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc72()
+ {
+ uint rn, rd, offset;
+ // LDRSB rd, [rn, -immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc73()
+ {
+ uint rn, rd, offset;
+ // LDRSB rd, [rn, rm]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc74()
+ {
+ uint rn, rd, offset;
+ // LDRSB rd, [rn, rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc75()
+ {
+ uint rn, rd, offset;
+ // LDRSB rd, [rn, immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc76()
+ {
+ uint rn, rd, offset;
+ // LDRSB rd, [rn, immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rn] += offset;
+ registers[rd] = (uint)(sbyte)this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc77()
+ {
+ uint rn, rd, address, offset;
+ // LDRSH rd, [rn], -rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc78()
+ {
+ uint rn, rd, address, offset;
+ // Writeback bit set, instruction is unpredictable
+ // LDRSH rd, [rn], -rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc79()
+ {
+ uint rn, rd, address, offset;
+ // LDRSH rd, [rn], -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc80()
+ {
+ uint rn, rd, address, offset;
+ // Writeback bit set, instruction is unpredictable
+ // LDRSH rd, [rn], -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc81()
+ {
+ uint rn, rd, address, offset;
+ // LDRSH rd, [rn], rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc82()
+ {
+ uint rn, rd, address, offset;
+ // Writeback bit set, instruction is unpredictable
+ // LDRSH rd, [rn], rm
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc83()
+ {
+ uint rn, rd, address, offset;
+ // LDRSH rd, [rn], immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc84()
+ {
+ uint rn, rd, address, offset;
+ // Writeback bit set, instruction is unpredictable
+ // LDRSH rd, [rn], immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ address = registers[rn];
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(address);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] = address + offset;
+ }
+ private void DispatchFunc85()
+ {
+ uint rn, rd, offset;
+ // LDRSH rd, [rn, -rm]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc86()
+ {
+ uint rn, rd, offset;
+ // LDRSH rd, [rn, -rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = (uint)(short)this.memory.ReadU16(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc87()
+ {
+ uint rn, rd, offset;
+ // LDRSH rd, [rn, -immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc88()
+ {
+ uint rn, rd, offset;
+ // LDRSH rd, [rn, -immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = (uint)(short)this.memory.ReadU16(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc89()
+ {
+ uint rn, rd, offset;
+ // LDRSH rd, [rn, rm]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc90()
+ {
+ uint rn, rd, offset;
+ // LDRSH rd, [rn, rm]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.registers[this.curInstruction & 0xF];
+
+ registers[rn] += offset;
+ registers[rd] = (uint)(short)this.memory.ReadU16(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc91()
+ {
+ uint rn, rd, offset;
+ // LDRSH rd, [rn, immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rd] = (uint)(short)this.memory.ReadU16(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc92()
+ {
+ uint rn, rd, offset;
+ // LDRSH rd, [rn, immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = ((this.curInstruction & 0xF00) >> 4) | (this.curInstruction & 0xF);
+
+ registers[rn] += offset;
+ registers[rd] = (uint)(short)this.memory.ReadU16(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc93()
+ {
+ uint rn, rd;
+ // EOR rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterLslImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc94()
+ {
+ uint rn, rd;
+ // EOR rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterLslReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc95()
+ {
+ uint rn, rd;
+ // EOR rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterLsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc96()
+ {
+ uint rn, rd;
+ // EOR rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterLsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc97()
+ {
+ uint rn, rd;
+ // EOR rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterAsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc98()
+ {
+ uint rn, rd;
+ // EOR rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterAsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc99()
+ {
+ uint rn, rd;
+ // EOR rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterRorImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc100()
+ {
+ uint rn, rd;
+ // EOR rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterRorReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc101()
+ {
+ uint rn, rd;
+ // EORS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterLslImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc102()
+ {
+ uint rn, rd;
+ // EORS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterLslReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc103()
+ {
+ uint rn, rd;
+ // EORS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterLsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc104()
+ {
+ uint rn, rd;
+ // EORS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterLsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc105()
+ {
+ uint rn, rd;
+ // EORS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterAsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc106()
+ {
+ uint rn, rd;
+ // EORS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterAsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc107()
+ {
+ uint rn, rd;
+ // EORS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterRorImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc108()
+ {
+ uint rn, rd;
+ // EORS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn ^ BarrelShifterRorReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc109()
+ {
+ uint rn, rd;
+ // SUB rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterLslImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc110()
+ {
+ uint rn, rd;
+ // SUB rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterLslReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc111()
+ {
+ uint rn, rd;
+ // SUB rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterLsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc112()
+ {
+ uint rn, rd;
+ // SUB rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterLsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc113()
+ {
+ uint rn, rd;
+ // SUB rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterAsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc114()
+ {
+ uint rn, rd;
+ // SUB rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterAsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc115()
+ {
+ uint rn, rd;
+ // SUB rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterRorImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc116()
+ {
+ uint rn, rd;
+ // SUB rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterRorReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc117()
+ {
+ uint rn, rd, shifterOperand;
+ // SUBS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslImmed();
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc118()
+ {
+ uint rn, rd, shifterOperand;
+ // SUBS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslReg();
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc119()
+ {
+ uint rn, rd, shifterOperand;
+ // SUBS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrImmed();
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc120()
+ {
+ uint rn, rd, shifterOperand;
+ // SUBS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrReg();
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc121()
+ {
+ uint rn, rd, shifterOperand;
+ // SUBS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrImmed();
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc122()
+ {
+ uint rn, rd, shifterOperand;
+ // SUBS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrReg();
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc123()
+ {
+ uint rn, rd, shifterOperand;
+ // SUBS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorImmed();
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc124()
+ {
+ uint rn, rd, shifterOperand;
+ // SUBS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorReg();
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc125()
+ {
+ uint rn, rd;
+ // RSB rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLslImmed() - rn;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc126()
+ {
+ uint rn, rd;
+ // RSB rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLslReg() - rn;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc127()
+ {
+ uint rn, rd;
+ // RSB rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLsrImmed() - rn;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc128()
+ {
+ uint rn, rd;
+ // RSB rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLsrReg() - rn;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc129()
+ {
+ uint rn, rd;
+ // RSB rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterAsrImmed() - rn;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc130()
+ {
+ uint rn, rd;
+ // RSB rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterAsrReg() - rn;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc131()
+ {
+ uint rn, rd;
+ // RSB rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterRorImmed() - rn;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc132()
+ {
+ uint rn, rd;
+ // RSB rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterRorReg() - rn;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc133()
+ {
+ uint rn, rd, shifterOperand;
+ // RSBS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslImmed();
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc134()
+ {
+ uint rn, rd, shifterOperand;
+ // RSBS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslReg();
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc135()
+ {
+ uint rn, rd, shifterOperand;
+ // RSBS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrImmed();
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc136()
+ {
+ uint rn, rd, shifterOperand;
+ // RSBS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrReg();
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc137()
+ {
+ uint rn, rd, shifterOperand;
+ // RSBS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrImmed();
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc138()
+ {
+ uint rn, rd, shifterOperand;
+ // RSBS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrReg();
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc139()
+ {
+ uint rn, rd, shifterOperand;
+ // RSBS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorImmed();
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc140()
+ {
+ uint rn, rd, shifterOperand;
+ // RSBS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorReg();
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc141()
+ {
+ uint rn, rd;
+ // ADD rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterLslImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc142()
+ {
+ uint rn, rd;
+ // ADD rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterLslReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc143()
+ {
+ uint rn, rd;
+ // ADD rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterLsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc144()
+ {
+ uint rn, rd;
+ // ADD rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterLsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc145()
+ {
+ uint rn, rd;
+ // ADD rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterAsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc146()
+ {
+ uint rn, rd;
+ // ADD rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterAsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc147()
+ {
+ uint rn, rd;
+ // ADD rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterRorImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc148()
+ {
+ uint rn, rd;
+ // ADD rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterRorReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc149()
+ {
+ uint rn, rd, shifterOperand;
+ // ADDS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslImmed();
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc150()
+ {
+ uint rn, rd, shifterOperand;
+ // ADDS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslReg();
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc151()
+ {
+ uint rn, rd, shifterOperand;
+ // ADDS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrImmed();
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc152()
+ {
+ uint rn, rd, shifterOperand;
+ // ADDS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrReg();
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc153()
+ {
+ uint rn, rd, shifterOperand;
+ // ADDS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrImmed();
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc154()
+ {
+ uint rn, rd, shifterOperand;
+ // ADDS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrReg();
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc155()
+ {
+ uint rn, rd, shifterOperand;
+ // ADDS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorImmed();
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc156()
+ {
+ uint rn, rd, shifterOperand;
+ // ADDS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorReg();
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc157()
+ {
+ uint rn, rd;
+ // ADC rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterLslImmed() + carry;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc158()
+ {
+ uint rn, rd;
+ // ADC rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterLslReg() + carry;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc159()
+ {
+ uint rn, rd;
+ // ADC rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterLsrImmed() + carry;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc160()
+ {
+ uint rn, rd;
+ // ADC rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterLsrReg() + carry;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc161()
+ {
+ uint rn, rd;
+ // ADC rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterAsrImmed() + carry;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc162()
+ {
+ uint rn, rd;
+ // ADC rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterAsrReg() + carry;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc163()
+ {
+ uint rn, rd;
+ // ADC rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterRorImmed() + carry;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc164()
+ {
+ uint rn, rd;
+ // ADC rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn + BarrelShifterRorReg() + carry;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc165()
+ {
+ uint rn, rd, shifterOperand;
+ // ADCS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslImmed();
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc166()
+ {
+ uint rn, rd, shifterOperand;
+ // ADCS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslReg();
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc167()
+ {
+ uint rn, rd, shifterOperand;
+ // ADCS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrImmed();
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc168()
+ {
+ uint rn, rd, shifterOperand;
+ // ADCS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrReg();
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc169()
+ {
+ uint rn, rd, shifterOperand;
+ // ADCS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrImmed();
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc170()
+ {
+ uint rn, rd, shifterOperand;
+ // ADCS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrReg();
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc171()
+ {
+ uint rn, rd, shifterOperand;
+ // ADCS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorImmed();
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc172()
+ {
+ uint rn, rd, shifterOperand;
+ // ADCS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorReg();
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc173()
+ {
+ uint rn, rd;
+ // SBC rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterLslImmed() - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc174()
+ {
+ uint rn, rd;
+ // SBC rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterLslReg() - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc175()
+ {
+ uint rn, rd;
+ // SBC rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterLsrImmed() - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc176()
+ {
+ uint rn, rd;
+ // SBC rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterLsrReg() - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc177()
+ {
+ uint rn, rd;
+ // SBC rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterAsrImmed() - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc178()
+ {
+ uint rn, rd;
+ // SBC rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterAsrReg() - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc179()
+ {
+ uint rn, rd;
+ // SBC rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterRorImmed() - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc180()
+ {
+ uint rn, rd;
+ // SBC rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn - BarrelShifterRorReg() - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc181()
+ {
+ uint rn, rd, shifterOperand;
+ // SBCS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslImmed();
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc182()
+ {
+ uint rn, rd, shifterOperand;
+ // SBCS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslReg();
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc183()
+ {
+ uint rn, rd, shifterOperand;
+ // SBCS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrImmed();
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc184()
+ {
+ uint rn, rd, shifterOperand;
+ // SBCS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrReg();
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc185()
+ {
+ uint rn, rd, shifterOperand;
+ // SBCS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrImmed();
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc186()
+ {
+ uint rn, rd, shifterOperand;
+ // SBCS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrReg();
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc187()
+ {
+ uint rn, rd, shifterOperand;
+ // SBCS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorImmed();
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc188()
+ {
+ uint rn, rd, shifterOperand;
+ // SBCS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorReg();
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc189()
+ {
+ uint rn, rd;
+ // RSC rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLslImmed() - rn - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc190()
+ {
+ uint rn, rd;
+ // RSC rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLslReg() - rn - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc191()
+ {
+ uint rn, rd;
+ // RSC rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLsrImmed() - rn - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc192()
+ {
+ uint rn, rd;
+ // RSC rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLsrReg() - rn - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc193()
+ {
+ uint rn, rd;
+ // RSC rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterAsrImmed() - rn - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc194()
+ {
+ uint rn, rd;
+ // RSC rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterAsrReg() - rn - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc195()
+ {
+ uint rn, rd;
+ // RSC rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterRorImmed() - rn - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc196()
+ {
+ uint rn, rd;
+ // RSC rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterRorReg() - rn - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc197()
+ {
+ uint rn, rd, shifterOperand;
+ // RSCS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslImmed();
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc198()
+ {
+ uint rn, rd, shifterOperand;
+ // RSCS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLslReg();
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc199()
+ {
+ uint rn, rd, shifterOperand;
+ // RSCS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrImmed();
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc200()
+ {
+ uint rn, rd, shifterOperand;
+ // RSCS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterLsrReg();
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc201()
+ {
+ uint rn, rd, shifterOperand;
+ // RSCS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrImmed();
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc202()
+ {
+ uint rn, rd, shifterOperand;
+ // RSCS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterAsrReg();
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc203()
+ {
+ uint rn, rd, shifterOperand;
+ // RSCS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorImmed();
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc204()
+ {
+ uint rn, rd, shifterOperand;
+ // RSCS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ shifterOperand = BarrelShifterRorReg();
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc205()
+ {
+ uint rn, rd, rm;
+ // SWP rd, rm, [rn]
+ {
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+ rm = this.curInstruction & 0xF;
+ uint tmp = this.memory.ReadU32(registers[rn]);
+ this.memory.WriteU32(registers[rn], registers[rm]);
+ registers[rd] = tmp;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ }
+ private void DispatchFunc206()
+ {
+ uint rn, rd, rm;
+ // SWPB rd, rm, [rn]
+ {
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+ rm = this.curInstruction & 0xF;
+
+ byte tmp = this.memory.ReadU8(registers[rn]);
+ this.memory.WriteU8(registers[rn], (byte)(registers[rm] & 0xFF));
+ registers[rd] = tmp;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ }
+ private void DispatchFunc207()
+ {
+ uint rd;
+ // MRS rd, cpsr
+ rd = (this.curInstruction >> 12) & 0xF;
+ this.PackFlags();
+ registers[rd] = this.parent.CPSR;
+ }
+ private void DispatchFunc208()
+ {
+ uint rd;
+ // MRS rd, spsr
+ rd = (this.curInstruction >> 12) & 0xF;
+ if (this.parent.SPSRExists) registers[rd] = this.parent.SPSR;
+ }
+ private void DispatchFunc209()
+ {
+ uint rm;
+ // MSR cpsr, rm
+ {
+ rm = registers[this.curInstruction & 0xF];
+ bool userMode = (this.parent.CPSR & 0x1F) == Arm7Processor.USR;
+
+ this.PackFlags();
+
+ uint tmpCPSR = this.parent.CPSR;
+
+ if ((this.curInstruction & (1 << 16)) == 1 << 16 && !userMode)
+ {
+ tmpCPSR &= 0xFFFFFF00;
+ tmpCPSR |= rm & 0x000000FF;
+ }
+ if ((this.curInstruction & (1 << 17)) == 1 << 17 && !userMode)
+ {
+ tmpCPSR &= 0xFFFF00FF;
+ tmpCPSR |= rm & 0x0000FF00;
+ }
+ if ((this.curInstruction & (1 << 18)) == 1 << 18 && !userMode)
+ {
+ tmpCPSR &= 0xFF00FFFF;
+ tmpCPSR |= rm & 0x00FF0000;
+ }
+ if ((this.curInstruction & (1 << 19)) == 1 << 19)
+ {
+ tmpCPSR &= 0x00FFFFFF;
+ tmpCPSR |= rm & 0xFF000000;
+ }
+
+ this.parent.WriteCpsr(tmpCPSR);
+
+ this.UnpackFlags();
+
+ // Check for branch back to Thumb Mode
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbMode = true;
+ return;
+ }
+ }
+ }
+ private void DispatchFunc210()
+ {
+ uint rm;
+ // MSR spsr, rm
+ if (this.parent.SPSRExists)
+ {
+ rm = registers[this.curInstruction & 0xF];
+ if ((this.curInstruction & (1 << 16)) == 1 << 16)
+ {
+ this.parent.SPSR &= 0xFFFFFF00;
+ this.parent.SPSR |= rm & 0x000000FF;
+ }
+ if ((this.curInstruction & (1 << 17)) == 1 << 17)
+ {
+ this.parent.SPSR &= 0xFFFF00FF;
+ this.parent.SPSR |= rm & 0x0000FF00;
+ }
+ if ((this.curInstruction & (1 << 18)) == 1 << 18)
+ {
+ this.parent.SPSR &= 0xFF00FFFF;
+ this.parent.SPSR |= rm & 0x00FF0000;
+ }
+ if ((this.curInstruction & (1 << 19)) == 1 << 19)
+ {
+ this.parent.SPSR &= 0x00FFFFFF;
+ this.parent.SPSR |= rm & 0xFF000000;
+ }
+ }
+ }
+ private void DispatchFunc211()
+ {
+ // MSR cpsr, immed
+ {
+ uint immed = this.curInstruction & 0xFF;
+ int rotateAmount = (int)(((this.curInstruction >> 8) & 0xF) * 2);
+
+ immed = (immed >> rotateAmount) | (immed << (32 - rotateAmount));
+
+ bool userMode = (this.parent.CPSR & 0x1F) == Arm7Processor.USR;
+
+ this.PackFlags();
+
+ uint tmpCPSR = this.parent.CPSR;
+
+ if ((this.curInstruction & (1 << 16)) == 1 << 16 && !userMode)
+ {
+ tmpCPSR &= 0xFFFFFF00;
+ tmpCPSR |= immed & 0x000000FF;
+ }
+ if ((this.curInstruction & (1 << 17)) == 1 << 17 && !userMode)
+ {
+ tmpCPSR &= 0xFFFF00FF;
+ tmpCPSR |= immed & 0x0000FF00;
+ }
+ if ((this.curInstruction & (1 << 18)) == 1 << 18 && !userMode)
+ {
+ tmpCPSR &= 0xFF00FFFF;
+ tmpCPSR |= immed & 0x00FF0000;
+ }
+ if ((this.curInstruction & (1 << 19)) == 1 << 19)
+ {
+ tmpCPSR &= 0x00FFFFFF;
+ tmpCPSR |= immed & 0xFF000000;
+ }
+
+ this.parent.WriteCpsr(tmpCPSR);
+
+ this.UnpackFlags();
+
+ // Check for branch back to Thumb Mode
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbMode = true;
+ return;
+ }
+ }
+ }
+ private void DispatchFunc212()
+ {
+ // MSR spsr, immed
+ if (this.parent.SPSRExists)
+ {
+ uint immed = this.curInstruction & 0xFF;
+ int rotateAmount = (int)(((this.curInstruction >> 8) & 0xF) * 2);
+
+ immed = (immed >> rotateAmount) | (immed << (32 - rotateAmount));
+
+ if ((this.curInstruction & (1 << 16)) == 1 << 16)
+ {
+ this.parent.SPSR &= 0xFFFFFF00;
+ this.parent.SPSR |= immed & 0x000000FF;
+ }
+ if ((this.curInstruction & (1 << 17)) == 1 << 17)
+ {
+ this.parent.SPSR &= 0xFFFF00FF;
+ this.parent.SPSR |= immed & 0x0000FF00;
+ }
+ if ((this.curInstruction & (1 << 18)) == 1 << 18)
+ {
+ this.parent.SPSR &= 0xFF00FFFF;
+ this.parent.SPSR |= immed & 0x00FF0000;
+ }
+ if ((this.curInstruction & (1 << 19)) == 1 << 19)
+ {
+ this.parent.SPSR &= 0x00FFFFFF;
+ this.parent.SPSR |= immed & 0xFF000000;
+ }
+ }
+ }
+ private void DispatchFunc213()
+ {
+ uint rm;
+ // BX rm
+ rm = this.curInstruction & 0xf;
+
+ this.PackFlags();
+
+ this.parent.CPSR &= ~Arm7Processor.T_MASK;
+ this.parent.CPSR |= (registers[rm] & 1) << Arm7Processor.T_BIT;
+
+ registers[15] = registers[rm] & (~1U);
+
+ this.UnpackFlags();
+
+ // Check for branch back to Thumb Mode
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) == Arm7Processor.T_MASK)
+ {
+ this.thumbMode = true;
+ return;
+ }
+
+ this.FlushQueue();
+ }
+ private void DispatchFunc214()
+ {
+ uint rn, alu;
+ // TSTS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn & BarrelShifterLslImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ }
+ private void DispatchFunc215()
+ {
+ uint rn, alu;
+ // TSTS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn & BarrelShifterLslReg();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ }
+ private void DispatchFunc216()
+ {
+ uint rn, alu;
+ // TSTS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn & BarrelShifterLsrImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ }
+ private void DispatchFunc217()
+ {
+ uint rn, alu;
+ // TSTS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn & BarrelShifterLsrReg();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ }
+ private void DispatchFunc218()
+ {
+ uint rn, alu;
+ // TSTS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn & BarrelShifterAsrImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ }
+ private void DispatchFunc219()
+ {
+ uint rn, alu;
+ // TSTS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn & BarrelShifterAsrReg();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ }
+ private void DispatchFunc220()
+ {
+ uint rn, alu;
+ // TSTS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn & BarrelShifterRorImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ }
+ private void DispatchFunc221()
+ {
+ uint rn, rd, alu;
+ // TSTS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = rn & BarrelShifterRorReg();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ }
+ private void DispatchFunc222()
+ {
+ uint rn, alu;
+ // TEQS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn ^ BarrelShifterLslImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ }
+ private void DispatchFunc223()
+ {
+ uint rn, alu;
+ // TEQS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn ^ BarrelShifterLslReg();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ }
+ private void DispatchFunc224()
+ {
+ uint rn, alu;
+ // TEQS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn ^ BarrelShifterLsrImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ }
+ private void DispatchFunc225()
+ {
+ uint rn, alu;
+ // TEQS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn ^ BarrelShifterLsrReg();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ }
+ private void DispatchFunc226()
+ {
+ uint rn, alu;
+ // TEQS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn ^ BarrelShifterAsrImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ }
+ private void DispatchFunc227()
+ {
+ uint rn, alu;
+ // TEQS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn ^ BarrelShifterAsrReg();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ }
+ private void DispatchFunc228()
+ {
+ uint rn, alu;
+ // TEQS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn ^ BarrelShifterRorImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ }
+ private void DispatchFunc229()
+ {
+ uint rn, rd, alu;
+ // TEQS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = rn ^ BarrelShifterRorReg();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ }
+ private void DispatchFunc230()
+ {
+ uint rn, shifterOperand, alu;
+ // CMP rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterLslImmed();
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ }
+ private void DispatchFunc231()
+ {
+ uint rn, shifterOperand, alu;
+ // CMP rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterLslReg();
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ }
+ private void DispatchFunc232()
+ {
+ uint rn, shifterOperand, alu;
+ // CMP rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterLsrImmed();
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ }
+ private void DispatchFunc233()
+ {
+ uint rn, shifterOperand, alu;
+ // CMP rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterLsrReg();
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ }
+ private void DispatchFunc234()
+ {
+ uint rn, shifterOperand, alu;
+ // CMP rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterAsrImmed();
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ }
+ private void DispatchFunc235()
+ {
+ uint rn, shifterOperand, alu;
+ // CMP rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterAsrReg();
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ }
+ private void DispatchFunc236()
+ {
+ uint rn, shifterOperand, alu;
+ // CMP rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterRorImmed();
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ }
+ private void DispatchFunc237()
+ {
+ uint rn, shifterOperand, alu;
+ // CMP rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterRorReg();
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ }
+ private void DispatchFunc238()
+ {
+ uint rn, shifterOperand, alu;
+ // CMN rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterLslImmed();
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ }
+ private void DispatchFunc239()
+ {
+ uint rn, shifterOperand, alu;
+ // CMN rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterLslReg();
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ }
+ private void DispatchFunc240()
+ {
+ uint rn, shifterOperand, alu;
+ // CMN rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterLsrImmed();
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ }
+ private void DispatchFunc241()
+ {
+ uint rn, shifterOperand, alu;
+ // CMN rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterLsrReg();
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ }
+ private void DispatchFunc242()
+ {
+ uint rn, shifterOperand, alu;
+ // CMN rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterAsrImmed();
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ }
+ private void DispatchFunc243()
+ {
+ uint rn, shifterOperand, alu;
+ // CMN rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterAsrReg();
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ }
+ private void DispatchFunc244()
+ {
+ uint rn, shifterOperand, alu;
+ // CMN rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterRorImmed();
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ }
+ private void DispatchFunc245()
+ {
+ uint rn, shifterOperand, alu;
+ // CMN rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterRorReg();
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ }
+ private void DispatchFunc246()
+ {
+ uint rn, rd;
+ // ORR rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterLslImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc247()
+ {
+ uint rn, rd;
+ // ORR rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterLslReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc248()
+ {
+ uint rn, rd;
+ // ORR rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterLsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc249()
+ {
+ uint rn, rd;
+ // ORR rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterLsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc250()
+ {
+ uint rn, rd;
+ // ORR rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterAsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc251()
+ {
+ uint rn, rd;
+ // ORR rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterAsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc252()
+ {
+ uint rn, rd;
+ // ORR rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterRorImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc253()
+ {
+ uint rn, rd;
+ // ORR rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterRorReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc254()
+ {
+ uint rn, rd;
+ // ORRS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterLslImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc255()
+ {
+ uint rn, rd;
+ // ORRS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterLslReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc256()
+ {
+ uint rn, rd;
+ // ORRS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterLsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc257()
+ {
+ uint rn, rd;
+ // ORRS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterLsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc258()
+ {
+ uint rn, rd;
+ // ORRS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterAsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc259()
+ {
+ uint rn, rd;
+ // ORRS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterAsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc260()
+ {
+ uint rn, rd;
+ // ORRS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterRorImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc261()
+ {
+ uint rn, rd;
+ // ORRS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn | BarrelShifterRorReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc262()
+ {
+ uint rd;
+ // MOV rd, rm lsl immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLslImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc263()
+ {
+ uint rd;
+ // MOV rd, rm lsl rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLslReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc264()
+ {
+ uint rd;
+ // MOV rd, rm lsr immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc265()
+ {
+ uint rd;
+ // MOV rd, rm lsr rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc266()
+ {
+ uint rd;
+ // MOV rd, rm asr immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterAsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc267()
+ {
+ uint rd;
+ // MOV rd, rm asr rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterAsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc268()
+ {
+ uint rd;
+ // MOV rd, rm ror immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterRorImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc269()
+ {
+ uint rd;
+ // MOV rd, rm ror rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterRorReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc270()
+ {
+ uint rd;
+ // MOVS rd, rm lsl immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLslImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc271()
+ {
+ uint rd;
+ // MOVS rd, rm lsl rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLslReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc272()
+ {
+ uint rd;
+ // MOVS rd, rm lsr immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc273()
+ {
+ uint rd;
+ // MOVS rd, rn, rm lsr rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterLsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc274()
+ {
+ uint rd;
+ // MOVS rd, rn, rm asr immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterAsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc275()
+ {
+ uint rd;
+ // MOVS rd, rn, rm asr rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterAsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc276()
+ {
+ uint rd;
+ // MOVS rd, rn, rm ror immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterRorImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc277()
+ {
+ uint rd;
+ // MOVS rd, rn, rm ror rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterRorReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc278()
+ {
+ uint rn, rd;
+ // BIC rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterLslImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc279()
+ {
+ uint rn, rd;
+ // BIC rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterLslReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc280()
+ {
+ uint rn, rd;
+ // BIC rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterLsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc281()
+ {
+ uint rn, rd;
+ // BIC rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterLsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc282()
+ {
+ uint rn, rd;
+ // BIC rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterAsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc283()
+ {
+ uint rn, rd;
+ // BIC rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterAsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc284()
+ {
+ uint rn, rd;
+ // BIC rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterRorImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc285()
+ {
+ uint rn, rd;
+ // BIC rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterRorReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc286()
+ {
+ uint rn, rd;
+ // BICS rd, rn, rm lsl immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterLslImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc287()
+ {
+ uint rn, rd;
+ // BICS rd, rn, rm lsl rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterLslReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc288()
+ {
+ uint rn, rd;
+ // BICS rd, rn, rm lsr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterLsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc289()
+ {
+ uint rn, rd;
+ // BICS rd, rn, rm lsr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterLsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc290()
+ {
+ uint rn, rd;
+ // BICS rd, rn, rm asr immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterAsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc291()
+ {
+ uint rn, rd;
+ // BICS rd, rn, rm asr rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterAsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc292()
+ {
+ uint rn, rd;
+ // BICS rd, rn, rm ror immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterRorImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc293()
+ {
+ uint rn, rd;
+ // BICS rd, rn, rm ror rs
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = rn & ~BarrelShifterRorReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc294()
+ {
+ uint rd;
+ // MVN rd, rm lsl immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterLslImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc295()
+ {
+ uint rd;
+ // MVN rd, rm lsl rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterLslReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc296()
+ {
+ uint rd;
+ // MVN rd, rm lsr immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterLsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc297()
+ {
+ uint rd;
+ // MVN rd, rm lsr rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterLsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc298()
+ {
+ uint rd;
+ // MVN rd, rm asr immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterAsrImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc299()
+ {
+ uint rd;
+ // MVN rd, rm asr rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterAsrReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc300()
+ {
+ uint rd;
+ // MVN rd, rm ror immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterRorImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc301()
+ {
+ uint rd;
+ // MVN rd, rm ror rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterRorReg();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc302()
+ {
+ uint rd;
+ // MVNS rd, rm lsl immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterLslImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc303()
+ {
+ uint rd;
+ // MVNS rd, rm lsl rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterLslReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc304()
+ {
+ uint rd;
+ // MVNS rd, rm lsr immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterLsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc305()
+ {
+ uint rd;
+ // MVNS rd, rn, rm lsr rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterLsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc306()
+ {
+ uint rd;
+ // MVNS rd, rn, rm asr immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterAsrImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc307()
+ {
+ uint rd;
+ // MVNS rd, rn, rm asr rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterAsrReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc308()
+ {
+ uint rd;
+ // MVNS rd, rn, rm ror immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterRorImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc309()
+ {
+ uint rd;
+ // MVNS rd, rn, rm ror rs
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterRorReg();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc310()
+ {
+ uint rn, rd;
+ // AND rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn & BarrelShifterImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc311()
+ {
+ uint rn, rd;
+ // ANDS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn & BarrelShifterImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc312()
+ {
+ uint rn, rd;
+ // EOR rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn ^ BarrelShifterImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc313()
+ {
+ uint rn, rd;
+ // EORS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn ^ BarrelShifterImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc314()
+ {
+ uint rn, rd;
+ // SUB rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn - BarrelShifterImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc315()
+ {
+ uint rn, rd, shifterOperand;
+ // SUBS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterImmed();
+ registers[rd] = rn - shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc316()
+ {
+ uint rn, rd;
+ // RSB rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = BarrelShifterImmed() - rn;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc317()
+ {
+ uint rn, rd, shifterOperand;
+ // RSBS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterImmed();
+ registers[rd] = shifterOperand - rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc318()
+ {
+ uint rn, rd;
+ // ADD rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn + BarrelShifterImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc319()
+ {
+ uint rn, rd, shifterOperand;
+ // ADDS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterImmed();
+ registers[rd] = rn + shifterOperand;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc320()
+ {
+ uint rn, rd;
+ // ADC rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn + BarrelShifterImmed() + carry;
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc321()
+ {
+ uint rn, rd, shifterOperand;
+ // ADCS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterImmed();
+ registers[rd] = rn + shifterOperand + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc322()
+ {
+ uint rn, rd;
+ // SBC rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn - BarrelShifterImmed() - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc323()
+ {
+ uint rn, rd, shifterOperand;
+ // SBCS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterImmed();
+ registers[rd] = rn - shifterOperand - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc324()
+ {
+ uint rn, rd;
+ // RSC rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = BarrelShifterImmed() - rn - (1U - carry);
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc325()
+ {
+ uint rn, rd, shifterOperand;
+ // RSCS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterImmed();
+ registers[rd] = shifterOperand - rn - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(shifterOperand, rn, registers[rd]);
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc326()
+ {
+ uint rn, alu;
+ // TSTS rn, immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn & BarrelShifterImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ }
+ private void DispatchFunc327()
+ {
+ uint rn, alu;
+ // TEQS rn, immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ alu = rn ^ BarrelShifterImmed();
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+ }
+ private void DispatchFunc328()
+ {
+ uint rn, shifterOperand, alu;
+ // CMP rn, immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterImmed();
+ alu = rn - shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(rn, shifterOperand, alu);
+ }
+ private void DispatchFunc329()
+ {
+ uint rn, shifterOperand, alu;
+ // CMN rn, immed
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ shifterOperand = BarrelShifterImmed();
+ alu = rn + shifterOperand;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(rn, shifterOperand, alu);
+ }
+ private void DispatchFunc330()
+ {
+ uint rn, rd;
+ // ORR rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn | BarrelShifterImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc331()
+ {
+ uint rn, rd;
+ // ORRS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn | BarrelShifterImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc332()
+ {
+ uint rd;
+ // MOV rd, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc333()
+ {
+ uint rd;
+ // MOVS rd, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = BarrelShifterImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc334()
+ {
+ uint rn, rd;
+ // BIC rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn & ~BarrelShifterImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc335()
+ {
+ uint rn, rd;
+ // BICS rd, rn, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+ rn = registers[(this.curInstruction >> 16) & 0xF];
+
+ registers[rd] = rn & ~BarrelShifterImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc336()
+ {
+ uint rd;
+ // MVN rd, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterImmed();
+
+ if (rd == 15)
+ {
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc337()
+ {
+ uint rd;
+ // MVNS rd, immed
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = ~BarrelShifterImmed();
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ carry = this.shifterCarry;
+
+ if (rd == 15)
+ {
+ this.DataProcessingWriteToR15();
+ }
+ }
+ private void DispatchFunc338()
+ {
+ uint rn, rd, offset, alu;
+ // STR rd, rn, -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ }
+ private void DispatchFunc339()
+ {
+ uint rn, rd, offset, alu;
+ // STRT rd, rn, -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ }
+ private void DispatchFunc340()
+ {
+ uint rn, rd, offset, alu;
+ // STRB rd, rn, -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ }
+ private void DispatchFunc341()
+ {
+ uint rn, rd, offset, alu;
+ // STRBT rd, rn, -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ }
+ private void DispatchFunc342()
+ {
+ uint rn, rd, alu;
+ // STR rd, rn, immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.curInstruction & 0xFFF;
+ }
+ private void DispatchFunc343()
+ {
+ uint rn, rd, alu;
+ // STRT rd, rn, immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.curInstruction & 0xFFF;
+ }
+ private void DispatchFunc344()
+ {
+ uint rn, rd, alu;
+ // STRB rd, rn, immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.curInstruction & 0xFFF;
+ }
+ private void DispatchFunc345()
+ {
+ uint rn, rd, alu;
+ // STRBT rd, rn, immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.curInstruction & 0xFFF;
+ }
+ private void DispatchFunc346()
+ {
+ uint rn, rd, offset, alu;
+ // STR rd, [rn, -immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + offset, alu);
+ }
+ private void DispatchFunc347()
+ {
+ uint rn, rd, offset, alu;
+ // STR rd, [rn, -immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU32(registers[rn], alu);
+ }
+ private void DispatchFunc348()
+ {
+ uint rn, rd, offset, alu;
+ // STRB rd, [rn, -immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + offset, (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc349()
+ {
+ uint rn, rd, offset, alu;
+ // STRB rd, [rn, -immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc350()
+ {
+ uint rn, rd, alu;
+ // STR rd, [rn, immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + (this.curInstruction & 0xFFF), alu);
+ }
+ private void DispatchFunc351()
+ {
+ uint rn, rd, alu;
+ // STRT rd, [rn, immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.curInstruction & 0xFFF;
+ this.memory.WriteU32(registers[rn], alu);
+ }
+ private void DispatchFunc352()
+ {
+ uint rn, rd, alu;
+ // STRB rd, [rn, immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + (this.curInstruction & 0xFFF), (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc353()
+ {
+ uint rn, rd, alu;
+ // STRB rd, [rn, immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.curInstruction & 0xFFF;
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc354()
+ {
+ uint rn, rd, offset;
+ // LDR rd, rn, -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc355()
+ {
+ uint rn, rd, offset;
+ // LDRT rd, rn, -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc356()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, rn, -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc357()
+ {
+ uint rn, rd, offset;
+ // LDRBT rd, rn, -immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc358()
+ {
+ uint rn, rd;
+ // LDR rd, rn, immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += this.curInstruction & 0xFFF;
+ }
+ private void DispatchFunc359()
+ {
+ uint rn, rd;
+ // LDRT rd, rn, immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += this.curInstruction & 0xFFF;
+ }
+ private void DispatchFunc360()
+ {
+ uint rn, rd;
+ // LDRB rd, rn, immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += this.curInstruction & 0xFFF;
+ }
+ private void DispatchFunc361()
+ {
+ uint rn, rd;
+ // LDRBT rd, rn, immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += this.curInstruction & 0xFFF;
+ }
+ private void DispatchFunc362()
+ {
+ uint rn, rd, offset;
+ // LDR rd, [rn, -immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc363()
+ {
+ uint rn, rd, offset;
+ // LDR rd, [rn, -immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc364()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, [rn, -immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc365()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, [rn, -immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.curInstruction & 0xFFF;
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc366()
+ {
+ uint rn, rd;
+ // LDR rd, [rn, immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + (this.curInstruction & 0xFFF));
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc367()
+ {
+ uint rn, rd;
+ // LDR rd, [rn, immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.curInstruction & 0xFFF;
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc368()
+ {
+ uint rn, rd;
+ // LDRB rd, [rn, immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + (this.curInstruction & 0xFFF));
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc369()
+ {
+ uint rn, rd;
+ // LDRB rd, [rn, immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.curInstruction & 0xFFF;
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc370()
+ {
+ uint rn, rd, offset, alu;
+ // STR rd, rn, -rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ }
+ private void DispatchFunc371()
+ {
+ uint rn, rd, offset, alu;
+ // STR rd, rn, -rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ }
+ private void DispatchFunc372()
+ {
+ uint rn, rd, offset, alu;
+ // STR rd, rn, -rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ }
+ private void DispatchFunc373()
+ {
+ uint rn, rd, offset, alu;
+ // STR rd, rn, -rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ }
+ private void DispatchFunc374()
+ {
+ uint rn, rd, offset, alu;
+ // STRT rd, rn, -rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ }
+ private void DispatchFunc375()
+ {
+ uint rn, rd, offset, alu;
+ // STRT rd, rn, -rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ }
+ private void DispatchFunc376()
+ {
+ uint rn, rd, offset, alu;
+ // STRT rd, rn, -rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ }
+ private void DispatchFunc377()
+ {
+ uint rn, rd, offset, alu;
+ // STRT rd, rn, -rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += offset;
+ }
+ private void DispatchFunc378()
+ {
+ uint rn, rd, offset, alu;
+ // STRB rd, rn, -rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ }
+ private void DispatchFunc379()
+ {
+ uint rn, rd, offset, alu;
+ // STRB rd, rn, -rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ }
+ private void DispatchFunc380()
+ {
+ uint rn, rd, offset, alu;
+ // STRB rd, rn, -rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ }
+ private void DispatchFunc381()
+ {
+ uint rn, rd, offset, alu;
+ // STRB rd, rn, -rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ }
+ private void DispatchFunc382()
+ {
+ uint rn, rd, offset, alu;
+ // STRBT rd, rn, -rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ }
+ private void DispatchFunc383()
+ {
+ uint rn, rd, offset, alu;
+ // STRBT rd, rn, -rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ }
+ private void DispatchFunc384()
+ {
+ uint rn, rd, offset, alu;
+ // STRBT rd, rn, -rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ }
+ private void DispatchFunc385()
+ {
+ uint rn, rd, offset, alu;
+ // STRBT rd, rn, -rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += offset;
+ }
+ private void DispatchFunc386()
+ {
+ uint rn, rd, alu;
+ // STR rd, rn, rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.BarrelShifterLslImmed();
+ }
+ private void DispatchFunc387()
+ {
+ uint rn, rd, alu;
+ // STR rd, rn, rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.BarrelShifterLsrImmed();
+ }
+ private void DispatchFunc388()
+ {
+ uint rn, rd, alu;
+ // STR rd, rn, rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.BarrelShifterAsrImmed();
+ }
+ private void DispatchFunc389()
+ {
+ uint rn, rd, alu;
+ // STR rd, rn, rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.BarrelShifterRorImmed();
+ }
+ private void DispatchFunc390()
+ {
+ uint rn, rd, alu;
+ // STRT rd, rn, rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.BarrelShifterLslImmed();
+ }
+ private void DispatchFunc391()
+ {
+ uint rn, rd, alu;
+ // STRT rd, rn, rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.BarrelShifterLsrImmed();
+ }
+ private void DispatchFunc392()
+ {
+ uint rn, rd, alu;
+ // STRT rd, rn, rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.BarrelShifterAsrImmed();
+ }
+ private void DispatchFunc393()
+ {
+ uint rn, rd, alu;
+ // STRT rd, rn, rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn], alu);
+ registers[rn] += this.BarrelShifterRorImmed();
+ }
+ private void DispatchFunc394()
+ {
+ uint rn, rd, alu;
+ // STRB rd, rn, rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.BarrelShifterLslImmed();
+ }
+ private void DispatchFunc395()
+ {
+ uint rn, rd, alu;
+ // STRB rd, rn, rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.BarrelShifterLsrImmed();
+ }
+ private void DispatchFunc396()
+ {
+ uint rn, rd, alu;
+ // STRB rd, rn, rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.BarrelShifterAsrImmed();
+ }
+ private void DispatchFunc397()
+ {
+ uint rn, rd, alu;
+ // STRB rd, rn, rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.BarrelShifterRorImmed();
+ }
+ private void DispatchFunc398()
+ {
+ uint rn, rd, alu;
+ // STRBT rd, rn, rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.BarrelShifterLslImmed();
+ }
+ private void DispatchFunc399()
+ {
+ uint rn, rd, alu;
+ // STRBT rd, rn, rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.BarrelShifterLsrImmed();
+ }
+ private void DispatchFunc400()
+ {
+ uint rn, rd, alu;
+ // STRBT rd, rn, rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.BarrelShifterAsrImmed();
+ }
+ private void DispatchFunc401()
+ {
+ uint rn, rd, alu;
+ // STRBT rd, rn, rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ registers[rn] += this.BarrelShifterRorImmed();
+ }
+ private void DispatchFunc402()
+ {
+ uint rn, rd, offset, alu;
+ // STR rd, [rn, -rm lsl immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + offset, alu);
+ }
+ private void DispatchFunc403()
+ {
+ uint rn, rd, offset, alu;
+ // STR rd, [rn, -rm lsr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + offset, alu);
+ }
+ private void DispatchFunc404()
+ {
+ uint rn, rd, offset, alu;
+ // STR rd, [rn, -rm asr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + offset, alu);
+ }
+ private void DispatchFunc405()
+ {
+ uint rn, rd, offset, alu;
+ // STR rd, [rn, -rm ror immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + offset, alu);
+ }
+ private void DispatchFunc406()
+ {
+ uint rn, rd, offset, alu;
+ // STR rd, [rn, -rm lsl immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU32(registers[rn], alu);
+ }
+ private void DispatchFunc407()
+ {
+ uint rn, rd, offset, alu;
+ // STR rd, [rn, -rm lsr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU32(registers[rn], alu);
+ }
+ private void DispatchFunc408()
+ {
+ uint rn, rd, offset, alu;
+ // STR rd, [rn, -rm asr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU32(registers[rn], alu);
+ }
+ private void DispatchFunc409()
+ {
+ uint rn, rd, offset, alu;
+ // STR rd, [rn, -rm ror immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU32(registers[rn], alu);
+ }
+ private void DispatchFunc410()
+ {
+ uint rn, rd, offset, alu;
+ // STRB rd, [rn, -rm lsl immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + offset, (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc411()
+ {
+ uint rn, rd, offset, alu;
+ // STRB rd, [rn, -rm lsr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + offset, (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc412()
+ {
+ uint rn, rd, offset, alu;
+ // STRB rd, [rn, -rm asr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + offset, (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc413()
+ {
+ uint rn, rd, offset, alu;
+ // STRB rd, [rn, -rm ror immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + offset, (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc414()
+ {
+ uint rn, rd, offset, alu;
+ // STRB rd, [rn, -rm lsl immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc415()
+ {
+ uint rn, rd, offset, alu;
+ // STRB rd, [rn, -rm lsr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc416()
+ {
+ uint rn, rd, offset, alu;
+ // STRB rd, [rn, -rm asr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc417()
+ {
+ uint rn, rd, offset, alu;
+ // STRB rd, [rn, -rm ror immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += offset;
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc418()
+ {
+ uint rn, rd, alu;
+ // STR rd, [rn, rm lsl immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + this.BarrelShifterLslImmed(), alu);
+ }
+ private void DispatchFunc419()
+ {
+ uint rn, rd, alu;
+ // STR rd, [rn, rm lsr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + this.BarrelShifterLsrImmed(), alu);
+ }
+ private void DispatchFunc420()
+ {
+ uint rn, rd, alu;
+ // STR rd, [rn, rm asr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + this.BarrelShifterAsrImmed(), alu);
+ }
+ private void DispatchFunc421()
+ {
+ uint rn, rd, alu;
+ // STR rd, [rn, rm ror immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU32(registers[rn] + this.BarrelShifterRorImmed(), alu);
+ }
+ private void DispatchFunc422()
+ {
+ uint rn, rd, alu;
+ // STR rd, [rn, rm lsl immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.BarrelShifterLslImmed();
+ this.memory.WriteU32(registers[rn], alu);
+ }
+ private void DispatchFunc423()
+ {
+ uint rn, rd, alu;
+ // STR rd, [rn, rm lsr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.BarrelShifterLsrImmed();
+ this.memory.WriteU32(registers[rn], alu);
+ }
+ private void DispatchFunc424()
+ {
+ uint rn, rd, alu;
+ // STR rd, [rn, rm asr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.BarrelShifterAsrImmed();
+ this.memory.WriteU32(registers[rn], alu);
+ }
+ private void DispatchFunc425()
+ {
+ uint rn, rd, alu;
+ // STR rd, [rn, rm ror immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.BarrelShifterRorImmed();
+ this.memory.WriteU32(registers[rn], alu);
+ }
+ private void DispatchFunc426()
+ {
+ uint rn, rd, alu;
+ // STRB rd, [rn, rm lsl immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + this.BarrelShifterLslImmed(), (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc427()
+ {
+ uint rn, rd, alu;
+ // STRB rd, [rn, rm lsr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + this.BarrelShifterLsrImmed(), (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc428()
+ {
+ uint rn, rd, alu;
+ // STRB rd, [rn, rm asr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + this.BarrelShifterAsrImmed(), (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc429()
+ {
+ uint rn, rd, alu;
+ // STRB rd, [rn, rm ror immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ this.memory.WriteU8(registers[rn] + this.BarrelShifterRorImmed(), (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc430()
+ {
+ uint rn, rd, alu;
+ // STRB rd, [rn, rm lsl immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.BarrelShifterLslImmed();
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc431()
+ {
+ uint rn, rd, alu;
+ // STRB rd, [rn, rm lsr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.BarrelShifterLsrImmed();
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc432()
+ {
+ uint rn, rd, alu;
+ // STRB rd, [rn, rm asr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.BarrelShifterAsrImmed();
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc433()
+ {
+ uint rn, rd, alu;
+ // STRB rd, [rn, rm ror immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ alu = registers[rd];
+ if (rd == 15) alu += 4;
+
+ registers[rn] += this.BarrelShifterRorImmed();
+ this.memory.WriteU8(registers[rn], (byte)(alu & 0xFF));
+ }
+ private void DispatchFunc434()
+ {
+ uint rn, rd, offset;
+ // LDR rd, rn, -rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc435()
+ {
+ uint rn, rd, offset;
+ // LDR rd, rn, -rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc436()
+ {
+ uint rn, rd, offset;
+ // LDR rd, rn, -rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc437()
+ {
+ uint rn, rd, offset;
+ // LDR rd, rn, -rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc438()
+ {
+ uint rn, rd, offset;
+ // LDRT rd, rn, -rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc439()
+ {
+ uint rn, rd, offset;
+ // LDRT rd, rn, -rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc440()
+ {
+ uint rn, rd, offset;
+ // LDRT rd, rn, -rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc441()
+ {
+ uint rn, rd, offset;
+ // LDRT rd, rn, -rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc442()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, rn, -rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc443()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, rn, -rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc444()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, rn, -rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc445()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, rn, -rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc446()
+ {
+ uint rn, rd, offset;
+ // LDRBT rd, rn, -rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc447()
+ {
+ uint rn, rd, offset;
+ // LDRBT rd, rn, -rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc448()
+ {
+ uint rn, rd, offset;
+ // LDRBT rd, rn, -rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc449()
+ {
+ uint rn, rd, offset;
+ // LDRBT rd, rn, -rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc450()
+ {
+ uint rn, rd, offset;
+ // LDR rd, rn, rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc451()
+ {
+ uint rn, rd, offset;
+ // LDR rd, rn, rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc452()
+ {
+ uint rn, rd, offset;
+ // LDR rd, rn, rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc453()
+ {
+ uint rn, rd, offset;
+ // LDR rd, rn, rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc454()
+ {
+ uint rn, rd, offset;
+ // LDRT rd, rn, rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc455()
+ {
+ uint rn, rd, offset;
+ // LDRT rd, rn, rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc456()
+ {
+ uint rn, rd, offset;
+ // LDRT rd, rn, rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc457()
+ {
+ uint rn, rd, offset;
+ // LDRT rd, rn, rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc458()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, rn, rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc459()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, rn, rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc460()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, rn, rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc461()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, rn, rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc462()
+ {
+ uint rn, rd, offset;
+ // LDRBT rd, rn, rm lsl immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc463()
+ {
+ uint rn, rd, offset;
+ // LDRBT rd, rn, rm lsr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc464()
+ {
+ uint rn, rd, offset;
+ // LDRBT rd, rn, rm asr immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc465()
+ {
+ uint rn, rd, offset;
+ // LDRBT rd, rn, rm ror immed
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+
+ if (rn != rd)
+ registers[rn] += offset;
+ }
+ private void DispatchFunc466()
+ {
+ uint rn, rd, offset;
+ // LDR rd, [rn, -rm lsl immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc467()
+ {
+ uint rn, rd, offset;
+ // LDR rd, [rn, -rm lsr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc468()
+ {
+ uint rn, rd, offset;
+ // LDR rd, [rn, -rm asr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc469()
+ {
+ uint rn, rd, offset;
+ // LDR rd, [rn, -rm ror immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc470()
+ {
+ uint rn, rd, offset;
+ // LDR rd, [rn, -rm lsl immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc471()
+ {
+ uint rn, rd, offset;
+ // LDR rd, [rn, -rm lsr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc472()
+ {
+ uint rn, rd, offset;
+ // LDR rd, [rn, -rm asr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc473()
+ {
+ uint rn, rd, offset;
+ // LDR rd, [rn, -rm ror immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc474()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, [rn, -rm lsl immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc475()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, [rn, -rm lsr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc476()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, [rn, -rm asr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc477()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, [rn, -rm ror immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + offset);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc478()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, [rn, -rm lsl immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLslImmed();
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc479()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, [rn, -rm lsr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterLsrImmed();
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc480()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, [rn, -rm asr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterAsrImmed();
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc481()
+ {
+ uint rn, rd, offset;
+ // LDRB rd, [rn, -rm ror immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ offset = this.BarrelShifterRorImmed();
+ offset = (uint)-offset;
+
+ registers[rn] += offset;
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc482()
+ {
+ uint rn, rd;
+ // LDR rd, [rn, rm lsl immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + this.BarrelShifterLslImmed());
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc483()
+ {
+ uint rn, rd;
+ // LDR rd, [rn, rm lsr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + this.BarrelShifterLsrImmed());
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc484()
+ {
+ uint rn, rd;
+ // LDR rd, [rn, rm asr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + this.BarrelShifterAsrImmed());
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc485()
+ {
+ uint rn, rd;
+ // LDR rd, [rn, rm ror immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU32(registers[rn] + this.BarrelShifterRorImmed());
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc486()
+ {
+ uint rn, rd;
+ // LDR rd, [rn, rm lsl immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.BarrelShifterLslImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc487()
+ {
+ uint rn, rd;
+ // LDR rd, [rn, rm lsr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.BarrelShifterLsrImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc488()
+ {
+ uint rn, rd;
+ // LDR rd, [rn, rm asr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.BarrelShifterAsrImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc489()
+ {
+ uint rn, rd;
+ // LDR rd, [rn, rm ror immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.BarrelShifterRorImmed();
+ registers[rd] = this.memory.ReadU32(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc490()
+ {
+ uint rn, rd;
+ // LDRB rd, [rn, rm lsl immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + this.BarrelShifterLslImmed());
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc491()
+ {
+ uint rn, rd;
+ // LDRB rd, [rn, rm lsr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + this.BarrelShifterLsrImmed());
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc492()
+ {
+ uint rn, rd;
+ // LDRB rd, [rn, rm asr immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + this.BarrelShifterAsrImmed());
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc493()
+ {
+ uint rn, rd;
+ // LDRB rd, [rn, rm ror immed]
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rd] = this.memory.ReadU8(registers[rn] + this.BarrelShifterRorImmed());
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc494()
+ {
+ uint rn, rd;
+ // LDRB rd, [rn, rm lsl immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.BarrelShifterLslImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc495()
+ {
+ uint rn, rd;
+ // LDRB rd, [rn, rm lsr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.BarrelShifterLsrImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc496()
+ {
+ uint rn, rd;
+ // LDRB rd, [rn, rm asr immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.BarrelShifterAsrImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc497()
+ {
+ uint rn, rd;
+ // LDRB rd, [rn, rm ror immed]!
+ rn = (this.curInstruction >> 16) & 0xF;
+ rd = (this.curInstruction >> 12) & 0xF;
+
+ registers[rn] += this.BarrelShifterRorImmed();
+ registers[rd] = this.memory.ReadU8(registers[rn]);
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~3U;
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc498()
+ {
+ {
+ uint branchOffset = this.curInstruction & 0x00FFFFFF;
+ if (branchOffset >> 23 == 1) branchOffset |= 0xFF000000;
+
+ this.registers[15] += branchOffset << 2;
+
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc499()
+ {
+ {
+ uint branchOffset = this.curInstruction & 0x00FFFFFF;
+ if (branchOffset >> 23 == 1) branchOffset |= 0xFF000000;
+
+ this.registers[14] = this.registers[15] - 4U;
+ this.registers[15] += branchOffset << 2;
+
+ this.FlushQueue();
+ }
+ }
+ private void DispatchFunc500()
+ {
+ this.registers[15] -= 4U;
+ this.parent.EnterException(Arm7Processor.SVC, 0x8, false, false);
+ }
+ private void DefaultDispatchFunc() { this.NormalOps[(curInstruction >> 25) & 0x7](); }
+ private ExecuteInstructionDelegate[] fastDispatch = null;
+ private void InitializeDispatchFunc()
+ {
+ this.fastDispatch = new ExecuteInstructionDelegate[] {
+DispatchFunc0,DispatchFunc1,DispatchFunc2,DispatchFunc3,DispatchFunc4,DispatchFunc5,DispatchFunc6,DispatchFunc7,DispatchFunc0,DispatchFunc17,DispatchFunc2,DispatchFunc29,DispatchFunc4,DispatchFunc16,DispatchFunc6,DispatchFunc16,DispatchFunc8,DispatchFunc9,DispatchFunc10,DispatchFunc11,DispatchFunc12
+,DispatchFunc13,DispatchFunc14,DispatchFunc15,DispatchFunc8,DispatchFunc18,DispatchFunc10,DispatchFunc45,DispatchFunc12,DispatchFunc61,DispatchFunc14,DispatchFunc77,DispatchFunc93,DispatchFunc94,DispatchFunc95,DispatchFunc96,DispatchFunc97,DispatchFunc98,DispatchFunc99,DispatchFunc100,DispatchFunc93
+,DispatchFunc19,DispatchFunc95,DispatchFunc30,DispatchFunc97,DispatchFunc16,DispatchFunc99,DispatchFunc16,DispatchFunc101,DispatchFunc102,DispatchFunc103,DispatchFunc104,DispatchFunc105,DispatchFunc106,DispatchFunc107,DispatchFunc108,DispatchFunc101,DispatchFunc20,DispatchFunc103,DispatchFunc46,DispatchFunc105
+,DispatchFunc62,DispatchFunc107,DispatchFunc78,DispatchFunc109,DispatchFunc110,DispatchFunc111,DispatchFunc112,DispatchFunc113,DispatchFunc114,DispatchFunc115,DispatchFunc116,DispatchFunc109,DefaultDispatchFunc,DispatchFunc111,DispatchFunc31,DispatchFunc113,DispatchFunc16,DispatchFunc115,DispatchFunc16,DispatchFunc117
+,DispatchFunc118,DispatchFunc119,DispatchFunc120,DispatchFunc121,DispatchFunc122,DispatchFunc123,DispatchFunc124,DispatchFunc117,DefaultDispatchFunc,DispatchFunc119,DispatchFunc47,DispatchFunc121,DispatchFunc63,DispatchFunc123,DispatchFunc79,DispatchFunc125,DispatchFunc126,DispatchFunc127,DispatchFunc128,DispatchFunc129
+,DispatchFunc130,DispatchFunc131,DispatchFunc132,DispatchFunc125,DefaultDispatchFunc,DispatchFunc127,DispatchFunc32,DispatchFunc129,DispatchFunc16,DispatchFunc131,DispatchFunc16,DispatchFunc133,DispatchFunc134,DispatchFunc135,DispatchFunc136,DispatchFunc137,DispatchFunc138,DispatchFunc139,DispatchFunc140,DispatchFunc133
+,DefaultDispatchFunc,DispatchFunc135,DispatchFunc48,DispatchFunc137,DispatchFunc64,DispatchFunc139,DispatchFunc80,DispatchFunc141,DispatchFunc142,DispatchFunc143,DispatchFunc144,DispatchFunc145,DispatchFunc146,DispatchFunc147,DispatchFunc148,DispatchFunc141,DispatchFunc21,DispatchFunc143,DispatchFunc33,DispatchFunc145
+,DispatchFunc16,DispatchFunc147,DispatchFunc16,DispatchFunc149,DispatchFunc150,DispatchFunc151,DispatchFunc152,DispatchFunc153,DispatchFunc154,DispatchFunc155,DispatchFunc156,DispatchFunc149,DispatchFunc22,DispatchFunc151,DispatchFunc49,DispatchFunc153,DispatchFunc65,DispatchFunc155,DispatchFunc81,DispatchFunc157
+,DispatchFunc158,DispatchFunc159,DispatchFunc160,DispatchFunc161,DispatchFunc162,DispatchFunc163,DispatchFunc164,DispatchFunc157,DispatchFunc23,DispatchFunc159,DispatchFunc34,DispatchFunc161,DispatchFunc16,DispatchFunc163,DispatchFunc16,DispatchFunc165,DispatchFunc166,DispatchFunc167,DispatchFunc168,DispatchFunc169
+,DispatchFunc170,DispatchFunc171,DispatchFunc172,DispatchFunc165,DispatchFunc24,DispatchFunc167,DispatchFunc50,DispatchFunc169,DispatchFunc66,DispatchFunc171,DispatchFunc82,DispatchFunc173,DispatchFunc174,DispatchFunc175,DispatchFunc176,DispatchFunc177,DispatchFunc178,DispatchFunc179,DispatchFunc180,DispatchFunc173
+,DispatchFunc25,DispatchFunc175,DispatchFunc35,DispatchFunc177,DispatchFunc16,DispatchFunc179,DispatchFunc16,DispatchFunc181,DispatchFunc182,DispatchFunc183,DispatchFunc184,DispatchFunc185,DispatchFunc186,DispatchFunc187,DispatchFunc188,DispatchFunc181,DispatchFunc26,DispatchFunc183,DispatchFunc51,DispatchFunc185
+,DispatchFunc67,DispatchFunc187,DispatchFunc83,DispatchFunc189,DispatchFunc190,DispatchFunc191,DispatchFunc192,DispatchFunc193,DispatchFunc194,DispatchFunc195,DispatchFunc196,DispatchFunc189,DispatchFunc27,DispatchFunc191,DispatchFunc36,DispatchFunc193,DispatchFunc16,DispatchFunc195,DispatchFunc16,DispatchFunc197
+,DispatchFunc198,DispatchFunc199,DispatchFunc200,DispatchFunc201,DispatchFunc202,DispatchFunc203,DispatchFunc204,DispatchFunc197,DispatchFunc28,DispatchFunc199,DispatchFunc52,DispatchFunc201,DispatchFunc68,DispatchFunc203,DispatchFunc84,DispatchFunc207,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DispatchFunc205,DefaultDispatchFunc,DispatchFunc37,DefaultDispatchFunc,DispatchFunc16,DefaultDispatchFunc,DispatchFunc16,DispatchFunc214,DispatchFunc215,DispatchFunc216,DispatchFunc217,DispatchFunc218,DispatchFunc219,DispatchFunc220,DispatchFunc221,DispatchFunc214
+,DefaultDispatchFunc,DispatchFunc216,DispatchFunc53,DispatchFunc218,DispatchFunc69,DispatchFunc220,DispatchFunc85,DispatchFunc209,DispatchFunc213,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DispatchFunc38,DefaultDispatchFunc
+,DispatchFunc16,DefaultDispatchFunc,DispatchFunc16,DispatchFunc222,DispatchFunc223,DispatchFunc224,DispatchFunc225,DispatchFunc226,DispatchFunc227,DispatchFunc228,DispatchFunc229,DispatchFunc222,DefaultDispatchFunc,DispatchFunc224,DispatchFunc54,DispatchFunc226,DispatchFunc70,DispatchFunc228,DispatchFunc86,DispatchFunc208
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DispatchFunc206,DefaultDispatchFunc,DispatchFunc39,DefaultDispatchFunc,DispatchFunc16,DefaultDispatchFunc,DispatchFunc16,DispatchFunc230,DispatchFunc231,DispatchFunc232,DispatchFunc233,DispatchFunc234
+,DispatchFunc235,DispatchFunc236,DispatchFunc237,DispatchFunc230,DefaultDispatchFunc,DispatchFunc232,DispatchFunc55,DispatchFunc234,DispatchFunc71,DispatchFunc236,DispatchFunc87,DispatchFunc210,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DispatchFunc40,DefaultDispatchFunc,DispatchFunc16,DefaultDispatchFunc,DispatchFunc16,DispatchFunc238,DispatchFunc239,DispatchFunc240,DispatchFunc241,DispatchFunc242,DispatchFunc243,DispatchFunc244,DispatchFunc245,DispatchFunc238,DefaultDispatchFunc,DispatchFunc240,DispatchFunc56,DispatchFunc242
+,DispatchFunc72,DispatchFunc244,DispatchFunc88,DispatchFunc246,DispatchFunc247,DispatchFunc248,DispatchFunc249,DispatchFunc250,DispatchFunc251,DispatchFunc252,DispatchFunc253,DispatchFunc246,DefaultDispatchFunc,DispatchFunc248,DispatchFunc41,DispatchFunc250,DispatchFunc16,DispatchFunc252,DispatchFunc16,DispatchFunc254
+,DispatchFunc255,DispatchFunc256,DispatchFunc257,DispatchFunc258,DispatchFunc259,DispatchFunc260,DispatchFunc261,DispatchFunc254,DefaultDispatchFunc,DispatchFunc256,DispatchFunc57,DispatchFunc258,DispatchFunc73,DispatchFunc260,DispatchFunc89,DispatchFunc262,DispatchFunc263,DispatchFunc264,DispatchFunc265,DispatchFunc266
+,DispatchFunc267,DispatchFunc268,DispatchFunc269,DispatchFunc262,DefaultDispatchFunc,DispatchFunc264,DispatchFunc42,DispatchFunc266,DispatchFunc16,DispatchFunc268,DispatchFunc16,DispatchFunc270,DispatchFunc271,DispatchFunc272,DispatchFunc273,DispatchFunc274,DispatchFunc275,DispatchFunc276,DispatchFunc277,DispatchFunc270
+,DefaultDispatchFunc,DispatchFunc272,DispatchFunc58,DispatchFunc274,DispatchFunc74,DispatchFunc276,DispatchFunc90,DispatchFunc278,DispatchFunc279,DispatchFunc280,DispatchFunc281,DispatchFunc282,DispatchFunc283,DispatchFunc284,DispatchFunc285,DispatchFunc278,DefaultDispatchFunc,DispatchFunc280,DispatchFunc43,DispatchFunc282
+,DispatchFunc16,DispatchFunc284,DispatchFunc16,DispatchFunc286,DispatchFunc287,DispatchFunc288,DispatchFunc289,DispatchFunc290,DispatchFunc291,DispatchFunc292,DispatchFunc293,DispatchFunc286,DefaultDispatchFunc,DispatchFunc288,DispatchFunc59,DispatchFunc290,DispatchFunc75,DispatchFunc292,DispatchFunc91,DispatchFunc294
+,DispatchFunc295,DispatchFunc296,DispatchFunc297,DispatchFunc298,DispatchFunc299,DispatchFunc300,DispatchFunc301,DispatchFunc294,DefaultDispatchFunc,DispatchFunc296,DispatchFunc44,DispatchFunc298,DispatchFunc16,DispatchFunc300,DispatchFunc16,DispatchFunc302,DispatchFunc303,DispatchFunc304,DispatchFunc305,DispatchFunc306
+,DispatchFunc307,DispatchFunc308,DispatchFunc309,DispatchFunc302,DefaultDispatchFunc,DispatchFunc304,DispatchFunc60,DispatchFunc306,DispatchFunc76,DispatchFunc308,DispatchFunc92,DispatchFunc310,DispatchFunc310,DispatchFunc310,DispatchFunc310,DispatchFunc310,DispatchFunc310,DispatchFunc310,DispatchFunc310,DispatchFunc310
+,DispatchFunc310,DispatchFunc310,DispatchFunc310,DispatchFunc310,DispatchFunc310,DispatchFunc310,DispatchFunc310,DispatchFunc311,DispatchFunc311,DispatchFunc311,DispatchFunc311,DispatchFunc311,DispatchFunc311,DispatchFunc311,DispatchFunc311,DispatchFunc311,DispatchFunc311,DispatchFunc311,DispatchFunc311,DispatchFunc311
+,DispatchFunc311,DispatchFunc311,DispatchFunc311,DispatchFunc312,DispatchFunc312,DispatchFunc312,DispatchFunc312,DispatchFunc312,DispatchFunc312,DispatchFunc312,DispatchFunc312,DispatchFunc312,DispatchFunc312,DispatchFunc312,DispatchFunc312,DispatchFunc312,DispatchFunc312,DispatchFunc312,DispatchFunc312,DispatchFunc313
+,DispatchFunc313,DispatchFunc313,DispatchFunc313,DispatchFunc313,DispatchFunc313,DispatchFunc313,DispatchFunc313,DispatchFunc313,DispatchFunc313,DispatchFunc313,DispatchFunc313,DispatchFunc313,DispatchFunc313,DispatchFunc313,DispatchFunc313,DispatchFunc314,DispatchFunc314,DispatchFunc314,DispatchFunc314,DispatchFunc314
+,DispatchFunc314,DispatchFunc314,DispatchFunc314,DispatchFunc314,DispatchFunc314,DispatchFunc314,DispatchFunc314,DispatchFunc314,DispatchFunc314,DispatchFunc314,DispatchFunc314,DispatchFunc315,DispatchFunc315,DispatchFunc315,DispatchFunc315,DispatchFunc315,DispatchFunc315,DispatchFunc315,DispatchFunc315,DispatchFunc315
+,DispatchFunc315,DispatchFunc315,DispatchFunc315,DispatchFunc315,DispatchFunc315,DispatchFunc315,DispatchFunc315,DispatchFunc316,DispatchFunc316,DispatchFunc316,DispatchFunc316,DispatchFunc316,DispatchFunc316,DispatchFunc316,DispatchFunc316,DispatchFunc316,DispatchFunc316,DispatchFunc316,DispatchFunc316,DispatchFunc316
+,DispatchFunc316,DispatchFunc316,DispatchFunc316,DispatchFunc317,DispatchFunc317,DispatchFunc317,DispatchFunc317,DispatchFunc317,DispatchFunc317,DispatchFunc317,DispatchFunc317,DispatchFunc317,DispatchFunc317,DispatchFunc317,DispatchFunc317,DispatchFunc317,DispatchFunc317,DispatchFunc317,DispatchFunc317,DispatchFunc318
+,DispatchFunc318,DispatchFunc318,DispatchFunc318,DispatchFunc318,DispatchFunc318,DispatchFunc318,DispatchFunc318,DispatchFunc318,DispatchFunc318,DispatchFunc318,DispatchFunc318,DispatchFunc318,DispatchFunc318,DispatchFunc318,DispatchFunc318,DispatchFunc319,DispatchFunc319,DispatchFunc319,DispatchFunc319,DispatchFunc319
+,DispatchFunc319,DispatchFunc319,DispatchFunc319,DispatchFunc319,DispatchFunc319,DispatchFunc319,DispatchFunc319,DispatchFunc319,DispatchFunc319,DispatchFunc319,DispatchFunc319,DispatchFunc320,DispatchFunc320,DispatchFunc320,DispatchFunc320,DispatchFunc320,DispatchFunc320,DispatchFunc320,DispatchFunc320,DispatchFunc320
+,DispatchFunc320,DispatchFunc320,DispatchFunc320,DispatchFunc320,DispatchFunc320,DispatchFunc320,DispatchFunc320,DispatchFunc321,DispatchFunc321,DispatchFunc321,DispatchFunc321,DispatchFunc321,DispatchFunc321,DispatchFunc321,DispatchFunc321,DispatchFunc321,DispatchFunc321,DispatchFunc321,DispatchFunc321,DispatchFunc321
+,DispatchFunc321,DispatchFunc321,DispatchFunc321,DispatchFunc322,DispatchFunc322,DispatchFunc322,DispatchFunc322,DispatchFunc322,DispatchFunc322,DispatchFunc322,DispatchFunc322,DispatchFunc322,DispatchFunc322,DispatchFunc322,DispatchFunc322,DispatchFunc322,DispatchFunc322,DispatchFunc322,DispatchFunc322,DispatchFunc323
+,DispatchFunc323,DispatchFunc323,DispatchFunc323,DispatchFunc323,DispatchFunc323,DispatchFunc323,DispatchFunc323,DispatchFunc323,DispatchFunc323,DispatchFunc323,DispatchFunc323,DispatchFunc323,DispatchFunc323,DispatchFunc323,DispatchFunc323,DispatchFunc324,DispatchFunc324,DispatchFunc324,DispatchFunc324,DispatchFunc324
+,DispatchFunc324,DispatchFunc324,DispatchFunc324,DispatchFunc324,DispatchFunc324,DispatchFunc324,DispatchFunc324,DispatchFunc324,DispatchFunc324,DispatchFunc324,DispatchFunc324,DispatchFunc325,DispatchFunc325,DispatchFunc325,DispatchFunc325,DispatchFunc325,DispatchFunc325,DispatchFunc325,DispatchFunc325,DispatchFunc325
+,DispatchFunc325,DispatchFunc325,DispatchFunc325,DispatchFunc325,DispatchFunc325,DispatchFunc325,DispatchFunc325,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DispatchFunc326,DispatchFunc326,DispatchFunc326,DispatchFunc326,DispatchFunc326,DispatchFunc326,DispatchFunc326,DispatchFunc326,DispatchFunc326,DispatchFunc326,DispatchFunc326,DispatchFunc326,DispatchFunc326,DispatchFunc326,DispatchFunc326,DispatchFunc326,DispatchFunc211
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DispatchFunc327,DispatchFunc327,DispatchFunc327,DispatchFunc327,DispatchFunc327
+,DispatchFunc327,DispatchFunc327,DispatchFunc327,DispatchFunc327,DispatchFunc327,DispatchFunc327,DispatchFunc327,DispatchFunc327,DispatchFunc327,DispatchFunc327,DispatchFunc327,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DispatchFunc328,DispatchFunc328,DispatchFunc328,DispatchFunc328,DispatchFunc328,DispatchFunc328,DispatchFunc328,DispatchFunc328,DispatchFunc328,DispatchFunc328,DispatchFunc328,DispatchFunc328,DispatchFunc328
+,DispatchFunc328,DispatchFunc328,DispatchFunc328,DispatchFunc212,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DispatchFunc329
+,DispatchFunc329,DispatchFunc329,DispatchFunc329,DispatchFunc329,DispatchFunc329,DispatchFunc329,DispatchFunc329,DispatchFunc329,DispatchFunc329,DispatchFunc329,DispatchFunc329,DispatchFunc329,DispatchFunc329,DispatchFunc329,DispatchFunc329,DispatchFunc330,DispatchFunc330,DispatchFunc330,DispatchFunc330,DispatchFunc330
+,DispatchFunc330,DispatchFunc330,DispatchFunc330,DispatchFunc330,DispatchFunc330,DispatchFunc330,DispatchFunc330,DispatchFunc330,DispatchFunc330,DispatchFunc330,DispatchFunc330,DispatchFunc331,DispatchFunc331,DispatchFunc331,DispatchFunc331,DispatchFunc331,DispatchFunc331,DispatchFunc331,DispatchFunc331,DispatchFunc331
+,DispatchFunc331,DispatchFunc331,DispatchFunc331,DispatchFunc331,DispatchFunc331,DispatchFunc331,DispatchFunc331,DispatchFunc332,DispatchFunc332,DispatchFunc332,DispatchFunc332,DispatchFunc332,DispatchFunc332,DispatchFunc332,DispatchFunc332,DispatchFunc332,DispatchFunc332,DispatchFunc332,DispatchFunc332,DispatchFunc332
+,DispatchFunc332,DispatchFunc332,DispatchFunc332,DispatchFunc333,DispatchFunc333,DispatchFunc333,DispatchFunc333,DispatchFunc333,DispatchFunc333,DispatchFunc333,DispatchFunc333,DispatchFunc333,DispatchFunc333,DispatchFunc333,DispatchFunc333,DispatchFunc333,DispatchFunc333,DispatchFunc333,DispatchFunc333,DispatchFunc334
+,DispatchFunc334,DispatchFunc334,DispatchFunc334,DispatchFunc334,DispatchFunc334,DispatchFunc334,DispatchFunc334,DispatchFunc334,DispatchFunc334,DispatchFunc334,DispatchFunc334,DispatchFunc334,DispatchFunc334,DispatchFunc334,DispatchFunc334,DispatchFunc335,DispatchFunc335,DispatchFunc335,DispatchFunc335,DispatchFunc335
+,DispatchFunc335,DispatchFunc335,DispatchFunc335,DispatchFunc335,DispatchFunc335,DispatchFunc335,DispatchFunc335,DispatchFunc335,DispatchFunc335,DispatchFunc335,DispatchFunc335,DispatchFunc336,DispatchFunc336,DispatchFunc336,DispatchFunc336,DispatchFunc336,DispatchFunc336,DispatchFunc336,DispatchFunc336,DispatchFunc336
+,DispatchFunc336,DispatchFunc336,DispatchFunc336,DispatchFunc336,DispatchFunc336,DispatchFunc336,DispatchFunc336,DispatchFunc337,DispatchFunc337,DispatchFunc337,DispatchFunc337,DispatchFunc337,DispatchFunc337,DispatchFunc337,DispatchFunc337,DispatchFunc337,DispatchFunc337,DispatchFunc337,DispatchFunc337,DispatchFunc337
+,DispatchFunc337,DispatchFunc337,DispatchFunc337,DispatchFunc338,DispatchFunc338,DispatchFunc338,DispatchFunc338,DispatchFunc338,DispatchFunc338,DispatchFunc338,DispatchFunc338,DispatchFunc338,DispatchFunc338,DispatchFunc338,DispatchFunc338,DispatchFunc338,DispatchFunc338,DispatchFunc338,DispatchFunc338,DispatchFunc354
+,DispatchFunc354,DispatchFunc354,DispatchFunc354,DispatchFunc354,DispatchFunc354,DispatchFunc354,DispatchFunc354,DispatchFunc354,DispatchFunc354,DispatchFunc354,DispatchFunc354,DispatchFunc354,DispatchFunc354,DispatchFunc354,DispatchFunc354,DispatchFunc339,DispatchFunc339,DispatchFunc339,DispatchFunc339,DispatchFunc339
+,DispatchFunc339,DispatchFunc339,DispatchFunc339,DispatchFunc339,DispatchFunc339,DispatchFunc339,DispatchFunc339,DispatchFunc339,DispatchFunc339,DispatchFunc339,DispatchFunc339,DispatchFunc355,DispatchFunc355,DispatchFunc355,DispatchFunc355,DispatchFunc355,DispatchFunc355,DispatchFunc355,DispatchFunc355,DispatchFunc355
+,DispatchFunc355,DispatchFunc355,DispatchFunc355,DispatchFunc355,DispatchFunc355,DispatchFunc355,DispatchFunc355,DispatchFunc340,DispatchFunc340,DispatchFunc340,DispatchFunc340,DispatchFunc340,DispatchFunc340,DispatchFunc340,DispatchFunc340,DispatchFunc340,DispatchFunc340,DispatchFunc340,DispatchFunc340,DispatchFunc340
+,DispatchFunc340,DispatchFunc340,DispatchFunc340,DispatchFunc356,DispatchFunc356,DispatchFunc356,DispatchFunc356,DispatchFunc356,DispatchFunc356,DispatchFunc356,DispatchFunc356,DispatchFunc356,DispatchFunc356,DispatchFunc356,DispatchFunc356,DispatchFunc356,DispatchFunc356,DispatchFunc356,DispatchFunc356,DispatchFunc341
+,DispatchFunc341,DispatchFunc341,DispatchFunc341,DispatchFunc341,DispatchFunc341,DispatchFunc341,DispatchFunc341,DispatchFunc341,DispatchFunc341,DispatchFunc341,DispatchFunc341,DispatchFunc341,DispatchFunc341,DispatchFunc341,DispatchFunc341,DispatchFunc357,DispatchFunc357,DispatchFunc357,DispatchFunc357,DispatchFunc357
+,DispatchFunc357,DispatchFunc357,DispatchFunc357,DispatchFunc357,DispatchFunc357,DispatchFunc357,DispatchFunc357,DispatchFunc357,DispatchFunc357,DispatchFunc357,DispatchFunc357,DispatchFunc342,DispatchFunc342,DispatchFunc342,DispatchFunc342,DispatchFunc342,DispatchFunc342,DispatchFunc342,DispatchFunc342,DispatchFunc342
+,DispatchFunc342,DispatchFunc342,DispatchFunc342,DispatchFunc342,DispatchFunc342,DispatchFunc342,DispatchFunc342,DispatchFunc358,DispatchFunc358,DispatchFunc358,DispatchFunc358,DispatchFunc358,DispatchFunc358,DispatchFunc358,DispatchFunc358,DispatchFunc358,DispatchFunc358,DispatchFunc358,DispatchFunc358,DispatchFunc358
+,DispatchFunc358,DispatchFunc358,DispatchFunc358,DispatchFunc343,DispatchFunc343,DispatchFunc343,DispatchFunc343,DispatchFunc343,DispatchFunc343,DispatchFunc343,DispatchFunc343,DispatchFunc343,DispatchFunc343,DispatchFunc343,DispatchFunc343,DispatchFunc343,DispatchFunc343,DispatchFunc343,DispatchFunc343,DispatchFunc359
+,DispatchFunc359,DispatchFunc359,DispatchFunc359,DispatchFunc359,DispatchFunc359,DispatchFunc359,DispatchFunc359,DispatchFunc359,DispatchFunc359,DispatchFunc359,DispatchFunc359,DispatchFunc359,DispatchFunc359,DispatchFunc359,DispatchFunc359,DispatchFunc344,DispatchFunc344,DispatchFunc344,DispatchFunc344,DispatchFunc344
+,DispatchFunc344,DispatchFunc344,DispatchFunc344,DispatchFunc344,DispatchFunc344,DispatchFunc344,DispatchFunc344,DispatchFunc344,DispatchFunc344,DispatchFunc344,DispatchFunc344,DispatchFunc360,DispatchFunc360,DispatchFunc360,DispatchFunc360,DispatchFunc360,DispatchFunc360,DispatchFunc360,DispatchFunc360,DispatchFunc360
+,DispatchFunc360,DispatchFunc360,DispatchFunc360,DispatchFunc360,DispatchFunc360,DispatchFunc360,DispatchFunc360,DispatchFunc345,DispatchFunc345,DispatchFunc345,DispatchFunc345,DispatchFunc345,DispatchFunc345,DispatchFunc345,DispatchFunc345,DispatchFunc345,DispatchFunc345,DispatchFunc345,DispatchFunc345,DispatchFunc345
+,DispatchFunc345,DispatchFunc345,DispatchFunc345,DispatchFunc361,DispatchFunc361,DispatchFunc361,DispatchFunc361,DispatchFunc361,DispatchFunc361,DispatchFunc361,DispatchFunc361,DispatchFunc361,DispatchFunc361,DispatchFunc361,DispatchFunc361,DispatchFunc361,DispatchFunc361,DispatchFunc361,DispatchFunc361,DispatchFunc346
+,DispatchFunc346,DispatchFunc346,DispatchFunc346,DispatchFunc346,DispatchFunc346,DispatchFunc346,DispatchFunc346,DispatchFunc346,DispatchFunc346,DispatchFunc346,DispatchFunc346,DispatchFunc346,DispatchFunc346,DispatchFunc346,DispatchFunc346,DispatchFunc362,DispatchFunc362,DispatchFunc362,DispatchFunc362,DispatchFunc362
+,DispatchFunc362,DispatchFunc362,DispatchFunc362,DispatchFunc362,DispatchFunc362,DispatchFunc362,DispatchFunc362,DispatchFunc362,DispatchFunc362,DispatchFunc362,DispatchFunc362,DispatchFunc347,DispatchFunc347,DispatchFunc347,DispatchFunc347,DispatchFunc347,DispatchFunc347,DispatchFunc347,DispatchFunc347,DispatchFunc347
+,DispatchFunc347,DispatchFunc347,DispatchFunc347,DispatchFunc347,DispatchFunc347,DispatchFunc347,DispatchFunc347,DispatchFunc363,DispatchFunc363,DispatchFunc363,DispatchFunc363,DispatchFunc363,DispatchFunc363,DispatchFunc363,DispatchFunc363,DispatchFunc363,DispatchFunc363,DispatchFunc363,DispatchFunc363,DispatchFunc363
+,DispatchFunc363,DispatchFunc363,DispatchFunc363,DispatchFunc348,DispatchFunc348,DispatchFunc348,DispatchFunc348,DispatchFunc348,DispatchFunc348,DispatchFunc348,DispatchFunc348,DispatchFunc348,DispatchFunc348,DispatchFunc348,DispatchFunc348,DispatchFunc348,DispatchFunc348,DispatchFunc348,DispatchFunc348,DispatchFunc364
+,DispatchFunc364,DispatchFunc364,DispatchFunc364,DispatchFunc364,DispatchFunc364,DispatchFunc364,DispatchFunc364,DispatchFunc364,DispatchFunc364,DispatchFunc364,DispatchFunc364,DispatchFunc364,DispatchFunc364,DispatchFunc364,DispatchFunc364,DispatchFunc349,DispatchFunc349,DispatchFunc349,DispatchFunc349,DispatchFunc349
+,DispatchFunc349,DispatchFunc349,DispatchFunc349,DispatchFunc349,DispatchFunc349,DispatchFunc349,DispatchFunc349,DispatchFunc349,DispatchFunc349,DispatchFunc349,DispatchFunc349,DispatchFunc365,DispatchFunc365,DispatchFunc365,DispatchFunc365,DispatchFunc365,DispatchFunc365,DispatchFunc365,DispatchFunc365,DispatchFunc365
+,DispatchFunc365,DispatchFunc365,DispatchFunc365,DispatchFunc365,DispatchFunc365,DispatchFunc365,DispatchFunc365,DispatchFunc350,DispatchFunc350,DispatchFunc350,DispatchFunc350,DispatchFunc350,DispatchFunc350,DispatchFunc350,DispatchFunc350,DispatchFunc350,DispatchFunc350,DispatchFunc350,DispatchFunc350,DispatchFunc350
+,DispatchFunc350,DispatchFunc350,DispatchFunc350,DispatchFunc366,DispatchFunc366,DispatchFunc366,DispatchFunc366,DispatchFunc366,DispatchFunc366,DispatchFunc366,DispatchFunc366,DispatchFunc366,DispatchFunc366,DispatchFunc366,DispatchFunc366,DispatchFunc366,DispatchFunc366,DispatchFunc366,DispatchFunc366,DispatchFunc351
+,DispatchFunc351,DispatchFunc351,DispatchFunc351,DispatchFunc351,DispatchFunc351,DispatchFunc351,DispatchFunc351,DispatchFunc351,DispatchFunc351,DispatchFunc351,DispatchFunc351,DispatchFunc351,DispatchFunc351,DispatchFunc351,DispatchFunc351,DispatchFunc367,DispatchFunc367,DispatchFunc367,DispatchFunc367,DispatchFunc367
+,DispatchFunc367,DispatchFunc367,DispatchFunc367,DispatchFunc367,DispatchFunc367,DispatchFunc367,DispatchFunc367,DispatchFunc367,DispatchFunc367,DispatchFunc367,DispatchFunc367,DispatchFunc352,DispatchFunc352,DispatchFunc352,DispatchFunc352,DispatchFunc352,DispatchFunc352,DispatchFunc352,DispatchFunc352,DispatchFunc352
+,DispatchFunc352,DispatchFunc352,DispatchFunc352,DispatchFunc352,DispatchFunc352,DispatchFunc352,DispatchFunc352,DispatchFunc368,DispatchFunc368,DispatchFunc368,DispatchFunc368,DispatchFunc368,DispatchFunc368,DispatchFunc368,DispatchFunc368,DispatchFunc368,DispatchFunc368,DispatchFunc368,DispatchFunc368,DispatchFunc368
+,DispatchFunc368,DispatchFunc368,DispatchFunc368,DispatchFunc353,DispatchFunc353,DispatchFunc353,DispatchFunc353,DispatchFunc353,DispatchFunc353,DispatchFunc353,DispatchFunc353,DispatchFunc353,DispatchFunc353,DispatchFunc353,DispatchFunc353,DispatchFunc353,DispatchFunc353,DispatchFunc353,DispatchFunc353,DispatchFunc369
+,DispatchFunc369,DispatchFunc369,DispatchFunc369,DispatchFunc369,DispatchFunc369,DispatchFunc369,DispatchFunc369,DispatchFunc369,DispatchFunc369,DispatchFunc369,DispatchFunc369,DispatchFunc369,DispatchFunc369,DispatchFunc369,DispatchFunc369,DispatchFunc370,DefaultDispatchFunc,DispatchFunc371,DefaultDispatchFunc,DispatchFunc372
+,DefaultDispatchFunc,DispatchFunc373,DefaultDispatchFunc,DispatchFunc370,DefaultDispatchFunc,DispatchFunc371,DefaultDispatchFunc,DispatchFunc372,DefaultDispatchFunc,DispatchFunc373,DefaultDispatchFunc,DispatchFunc434,DefaultDispatchFunc,DispatchFunc435,DefaultDispatchFunc,DispatchFunc436,DefaultDispatchFunc,DispatchFunc437,DefaultDispatchFunc,DispatchFunc434
+,DefaultDispatchFunc,DispatchFunc435,DefaultDispatchFunc,DispatchFunc436,DefaultDispatchFunc,DispatchFunc437,DefaultDispatchFunc,DispatchFunc374,DefaultDispatchFunc,DispatchFunc375,DefaultDispatchFunc,DispatchFunc376,DefaultDispatchFunc,DispatchFunc377,DefaultDispatchFunc,DispatchFunc374,DefaultDispatchFunc,DispatchFunc375,DefaultDispatchFunc,DispatchFunc376
+,DefaultDispatchFunc,DispatchFunc377,DefaultDispatchFunc,DispatchFunc438,DefaultDispatchFunc,DispatchFunc439,DefaultDispatchFunc,DispatchFunc440,DefaultDispatchFunc,DispatchFunc441,DefaultDispatchFunc,DispatchFunc438,DefaultDispatchFunc,DispatchFunc439,DefaultDispatchFunc,DispatchFunc440,DefaultDispatchFunc,DispatchFunc441,DefaultDispatchFunc,DispatchFunc378
+,DefaultDispatchFunc,DispatchFunc379,DefaultDispatchFunc,DispatchFunc380,DefaultDispatchFunc,DispatchFunc381,DefaultDispatchFunc,DispatchFunc378,DefaultDispatchFunc,DispatchFunc379,DefaultDispatchFunc,DispatchFunc380,DefaultDispatchFunc,DispatchFunc381,DefaultDispatchFunc,DispatchFunc442,DefaultDispatchFunc,DispatchFunc443,DefaultDispatchFunc,DispatchFunc444
+,DefaultDispatchFunc,DispatchFunc445,DefaultDispatchFunc,DispatchFunc442,DefaultDispatchFunc,DispatchFunc443,DefaultDispatchFunc,DispatchFunc444,DefaultDispatchFunc,DispatchFunc445,DefaultDispatchFunc,DispatchFunc382,DefaultDispatchFunc,DispatchFunc383,DefaultDispatchFunc,DispatchFunc384,DefaultDispatchFunc,DispatchFunc385,DefaultDispatchFunc,DispatchFunc382
+,DefaultDispatchFunc,DispatchFunc383,DefaultDispatchFunc,DispatchFunc384,DefaultDispatchFunc,DispatchFunc385,DefaultDispatchFunc,DispatchFunc446,DefaultDispatchFunc,DispatchFunc447,DefaultDispatchFunc,DispatchFunc448,DefaultDispatchFunc,DispatchFunc449,DefaultDispatchFunc,DispatchFunc446,DefaultDispatchFunc,DispatchFunc447,DefaultDispatchFunc,DispatchFunc448
+,DefaultDispatchFunc,DispatchFunc449,DefaultDispatchFunc,DispatchFunc386,DefaultDispatchFunc,DispatchFunc387,DefaultDispatchFunc,DispatchFunc388,DefaultDispatchFunc,DispatchFunc389,DefaultDispatchFunc,DispatchFunc386,DefaultDispatchFunc,DispatchFunc387,DefaultDispatchFunc,DispatchFunc388,DefaultDispatchFunc,DispatchFunc389,DefaultDispatchFunc,DispatchFunc450
+,DefaultDispatchFunc,DispatchFunc451,DefaultDispatchFunc,DispatchFunc452,DefaultDispatchFunc,DispatchFunc453,DefaultDispatchFunc,DispatchFunc450,DefaultDispatchFunc,DispatchFunc451,DefaultDispatchFunc,DispatchFunc452,DefaultDispatchFunc,DispatchFunc453,DefaultDispatchFunc,DispatchFunc390,DefaultDispatchFunc,DispatchFunc390,DefaultDispatchFunc,DispatchFunc391
+,DefaultDispatchFunc,DispatchFunc391,DefaultDispatchFunc,DispatchFunc392,DefaultDispatchFunc,DispatchFunc392,DefaultDispatchFunc,DispatchFunc393,DefaultDispatchFunc,DispatchFunc393,DefaultDispatchFunc,DispatchFunc454,DefaultDispatchFunc,DispatchFunc455,DefaultDispatchFunc,DispatchFunc456,DefaultDispatchFunc,DispatchFunc457,DefaultDispatchFunc,DispatchFunc454
+,DefaultDispatchFunc,DispatchFunc455,DefaultDispatchFunc,DispatchFunc456,DefaultDispatchFunc,DispatchFunc457,DefaultDispatchFunc,DispatchFunc394,DefaultDispatchFunc,DispatchFunc395,DefaultDispatchFunc,DispatchFunc396,DefaultDispatchFunc,DispatchFunc397,DefaultDispatchFunc,DispatchFunc394,DefaultDispatchFunc,DispatchFunc395,DefaultDispatchFunc,DispatchFunc396
+,DefaultDispatchFunc,DispatchFunc397,DefaultDispatchFunc,DispatchFunc458,DefaultDispatchFunc,DispatchFunc459,DefaultDispatchFunc,DispatchFunc460,DefaultDispatchFunc,DispatchFunc461,DefaultDispatchFunc,DispatchFunc458,DefaultDispatchFunc,DispatchFunc459,DefaultDispatchFunc,DispatchFunc460,DefaultDispatchFunc,DispatchFunc461,DefaultDispatchFunc,DispatchFunc398
+,DefaultDispatchFunc,DispatchFunc399,DefaultDispatchFunc,DispatchFunc400,DefaultDispatchFunc,DispatchFunc401,DefaultDispatchFunc,DispatchFunc398,DefaultDispatchFunc,DispatchFunc399,DefaultDispatchFunc,DispatchFunc400,DefaultDispatchFunc,DispatchFunc401,DefaultDispatchFunc,DispatchFunc462,DefaultDispatchFunc,DispatchFunc463,DefaultDispatchFunc,DispatchFunc464
+,DefaultDispatchFunc,DispatchFunc465,DefaultDispatchFunc,DispatchFunc462,DefaultDispatchFunc,DispatchFunc463,DefaultDispatchFunc,DispatchFunc464,DefaultDispatchFunc,DispatchFunc465,DefaultDispatchFunc,DispatchFunc402,DefaultDispatchFunc,DispatchFunc403,DefaultDispatchFunc,DispatchFunc404,DefaultDispatchFunc,DispatchFunc405,DefaultDispatchFunc,DispatchFunc402
+,DefaultDispatchFunc,DispatchFunc403,DefaultDispatchFunc,DispatchFunc404,DefaultDispatchFunc,DispatchFunc405,DefaultDispatchFunc,DispatchFunc466,DefaultDispatchFunc,DispatchFunc467,DefaultDispatchFunc,DispatchFunc468,DefaultDispatchFunc,DispatchFunc469,DefaultDispatchFunc,DispatchFunc466,DefaultDispatchFunc,DispatchFunc467,DefaultDispatchFunc,DispatchFunc468
+,DefaultDispatchFunc,DispatchFunc469,DefaultDispatchFunc,DispatchFunc406,DefaultDispatchFunc,DispatchFunc407,DefaultDispatchFunc,DispatchFunc408,DefaultDispatchFunc,DispatchFunc409,DefaultDispatchFunc,DispatchFunc406,DefaultDispatchFunc,DispatchFunc407,DefaultDispatchFunc,DispatchFunc408,DefaultDispatchFunc,DispatchFunc409,DefaultDispatchFunc,DispatchFunc470
+,DefaultDispatchFunc,DispatchFunc471,DefaultDispatchFunc,DispatchFunc472,DefaultDispatchFunc,DispatchFunc473,DefaultDispatchFunc,DispatchFunc470,DefaultDispatchFunc,DispatchFunc471,DefaultDispatchFunc,DispatchFunc472,DefaultDispatchFunc,DispatchFunc473,DefaultDispatchFunc,DispatchFunc410,DefaultDispatchFunc,DispatchFunc411,DefaultDispatchFunc,DispatchFunc412
+,DefaultDispatchFunc,DispatchFunc413,DefaultDispatchFunc,DispatchFunc410,DefaultDispatchFunc,DispatchFunc411,DefaultDispatchFunc,DispatchFunc412,DefaultDispatchFunc,DispatchFunc413,DefaultDispatchFunc,DispatchFunc474,DefaultDispatchFunc,DispatchFunc475,DefaultDispatchFunc,DispatchFunc476,DefaultDispatchFunc,DispatchFunc477,DefaultDispatchFunc,DispatchFunc474
+,DefaultDispatchFunc,DispatchFunc475,DefaultDispatchFunc,DispatchFunc476,DefaultDispatchFunc,DispatchFunc477,DefaultDispatchFunc,DispatchFunc414,DefaultDispatchFunc,DispatchFunc415,DefaultDispatchFunc,DispatchFunc416,DefaultDispatchFunc,DispatchFunc417,DefaultDispatchFunc,DispatchFunc414,DefaultDispatchFunc,DispatchFunc415,DefaultDispatchFunc,DispatchFunc416
+,DefaultDispatchFunc,DispatchFunc417,DefaultDispatchFunc,DispatchFunc478,DefaultDispatchFunc,DispatchFunc479,DefaultDispatchFunc,DispatchFunc480,DefaultDispatchFunc,DispatchFunc481,DefaultDispatchFunc,DispatchFunc478,DefaultDispatchFunc,DispatchFunc479,DefaultDispatchFunc,DispatchFunc480,DefaultDispatchFunc,DispatchFunc481,DefaultDispatchFunc,DispatchFunc418
+,DefaultDispatchFunc,DispatchFunc419,DefaultDispatchFunc,DispatchFunc420,DefaultDispatchFunc,DispatchFunc421,DefaultDispatchFunc,DispatchFunc418,DefaultDispatchFunc,DispatchFunc419,DefaultDispatchFunc,DispatchFunc420,DefaultDispatchFunc,DispatchFunc421,DefaultDispatchFunc,DispatchFunc482,DefaultDispatchFunc,DispatchFunc483,DefaultDispatchFunc,DispatchFunc484
+,DefaultDispatchFunc,DispatchFunc485,DefaultDispatchFunc,DispatchFunc482,DefaultDispatchFunc,DispatchFunc483,DefaultDispatchFunc,DispatchFunc484,DefaultDispatchFunc,DispatchFunc485,DefaultDispatchFunc,DispatchFunc422,DefaultDispatchFunc,DispatchFunc423,DefaultDispatchFunc,DispatchFunc424,DefaultDispatchFunc,DispatchFunc425,DefaultDispatchFunc,DispatchFunc422
+,DefaultDispatchFunc,DispatchFunc423,DefaultDispatchFunc,DispatchFunc424,DefaultDispatchFunc,DispatchFunc425,DefaultDispatchFunc,DispatchFunc486,DefaultDispatchFunc,DispatchFunc487,DefaultDispatchFunc,DispatchFunc488,DefaultDispatchFunc,DispatchFunc489,DefaultDispatchFunc,DispatchFunc486,DefaultDispatchFunc,DispatchFunc487,DefaultDispatchFunc,DispatchFunc488
+,DefaultDispatchFunc,DispatchFunc489,DefaultDispatchFunc,DispatchFunc426,DefaultDispatchFunc,DispatchFunc427,DefaultDispatchFunc,DispatchFunc428,DefaultDispatchFunc,DispatchFunc429,DefaultDispatchFunc,DispatchFunc426,DefaultDispatchFunc,DispatchFunc427,DefaultDispatchFunc,DispatchFunc428,DefaultDispatchFunc,DispatchFunc429,DefaultDispatchFunc,DispatchFunc490
+,DefaultDispatchFunc,DispatchFunc491,DefaultDispatchFunc,DispatchFunc492,DefaultDispatchFunc,DispatchFunc493,DefaultDispatchFunc,DispatchFunc490,DefaultDispatchFunc,DispatchFunc491,DefaultDispatchFunc,DispatchFunc492,DefaultDispatchFunc,DispatchFunc493,DefaultDispatchFunc,DispatchFunc430,DefaultDispatchFunc,DispatchFunc431,DefaultDispatchFunc,DispatchFunc432
+,DefaultDispatchFunc,DispatchFunc433,DefaultDispatchFunc,DispatchFunc430,DefaultDispatchFunc,DispatchFunc431,DefaultDispatchFunc,DispatchFunc432,DefaultDispatchFunc,DispatchFunc433,DefaultDispatchFunc,DispatchFunc494,DefaultDispatchFunc,DispatchFunc495,DefaultDispatchFunc,DispatchFunc496,DefaultDispatchFunc,DispatchFunc497,DefaultDispatchFunc,DispatchFunc494
+,DefaultDispatchFunc,DispatchFunc495,DefaultDispatchFunc,DispatchFunc496,DefaultDispatchFunc,DispatchFunc497,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DispatchFunc498
+,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498
+,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498
+,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498
+,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498
+,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498
+,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498
+,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498
+,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498
+,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498
+,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498
+,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498
+,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498
+,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc498,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499
+,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499
+,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499
+,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499
+,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499
+,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499
+,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499
+,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499
+,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499
+,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499
+,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499
+,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499
+,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499
+,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DispatchFunc499,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc
+,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DefaultDispatchFunc,DispatchFunc500
+,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500
+,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500
+,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500
+,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500
+,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500
+,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500
+,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500
+,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500
+,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500
+,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500
+,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500
+,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500,DispatchFunc500
+};
+ }
+ #endregion Delegate Dispatcher
+ }
+}
diff --git a/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/GbaManager.cs b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/GbaManager.cs
new file mode 100644
index 0000000000..f7236b5aeb
--- /dev/null
+++ b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/GbaManager.cs
@@ -0,0 +1,482 @@
+//#define ARM_DEBUG
+
+namespace GarboDev
+{
+ using System;
+ using System.IO;
+ using System.Threading;
+ using System.Timers;
+ using System.Windows.Forms;
+ using System.Collections.Generic;
+
+ using BizHawk.Emulation;
+ using BizHawk;
+
+ public class GbaManager : IEmulator, ISoundProvider, IVideoProvider
+ {
+ public const int cpuFreq = 16 * 1024 * 1024;
+
+ private int framesRendered;
+
+ private Arm7Processor arm7 = null;
+ private Memory memory = null;
+ private VideoManager videoManager = null;
+ private SoundManager soundManager = null;
+
+ private bool skipBios = false;
+
+ public delegate void CpuUpdateDelegate(Arm7Processor processor, Memory memory);
+ private event CpuUpdateDelegate onCpuUpdate = null;
+
+ public Arm7Processor Arm7
+ {
+ get { return this.arm7; }
+ }
+
+ public VideoManager VideoManager
+ {
+ get { return this.videoManager; }
+ }
+
+ public SoundManager SoundManager
+ {
+ get { return this.soundManager; }
+ }
+
+ public Memory Memory
+ {
+ get { return this.memory; }
+ }
+
+ public Dictionary Breakpoints
+ {
+ get { return this.arm7.Breakpoints; }
+ }
+
+ public ushort KeyState
+ {
+ get
+ {
+ if (this.memory != null)
+ {
+ return this.memory.KeyState;
+ }
+
+ return 0x3FF;
+ }
+
+ set
+ {
+ this.arm7.KeyState = value;
+ }
+ }
+
+ public int FramesRendered
+ {
+ get { return this.framesRendered; }
+ set { this.framesRendered = value; }
+ }
+
+ public event CpuUpdateDelegate OnCpuUpdate
+ {
+ add
+ {
+ this.onCpuUpdate += value;
+ this.onCpuUpdate(this.arm7, this.memory);
+ }
+ remove
+ {
+ this.onCpuUpdate -= value;
+ }
+ }
+
+ public bool SkipBios
+ {
+ get { return this.skipBios; }
+ set { this.skipBios = value; }
+ }
+
+ public GbaManager(CoreComm comm)
+ {
+ _corecomm = comm;
+
+ this.memory = new Memory();
+ this.arm7 = new Arm7Processor(this.memory);
+ this.videoManager = new VideoManager(this);
+ this.videoManager.Memory = this.memory;
+ this.soundManager = new SoundManager(this.memory, 44100);
+
+ this.framesRendered = 0;
+ Renderer renderer = new Renderer();
+ renderer.Initialize(null);
+ VideoManager.Renderer = renderer;
+
+ videoManager.Presenter = delegate(uint[] data)
+ {
+ Buffer.BlockCopy(data, 0, this.vbuf, 0, 240 * 160 * 4);
+ };
+ }
+
+ public void Load(byte[] rom, byte[] bios)
+ {
+ LoadBios(bios);
+ LoadRom(rom);
+ }
+
+ public void Reset()
+ {
+ //this.Halt();
+
+ this.arm7.Reset(this.skipBios);
+ this.memory.Reset();
+ this.videoManager.Reset();
+ }
+
+ public void AudioMixerStereo(short[] buffer, int length)
+ {
+ // even = left, odd = right
+ if (this.soundManager.SamplesMixed > Math.Max(500, length))
+ {
+ this.soundManager.GetSamples(buffer, length);
+ }
+ }
+
+ public void LoadState(BinaryReader state)
+ {
+ }
+
+ public void SaveState(BinaryWriter state)
+ {
+ state.Write("GARB");
+ }
+
+ public void LoadBios(byte[] biosRom)
+ {
+ this.memory.LoadBios(biosRom);
+
+ if (this.onCpuUpdate != null)
+ {
+ this.onCpuUpdate(this.arm7, this.memory);
+ }
+ }
+
+ public void LoadRom(byte[] cartRom)
+ {
+ //this.Halt();
+
+ /*
+ byte[] logo = new byte[]
+ {
+ 0x24,0xff,0xae,0x51,0x69,0x9a,0xa2,0x21,
+ 0x3d,0x84,0x82,0x0a,0x84,0xe4,0x09,0xad,
+ 0x11,0x24,0x8b,0x98,0xc0,0x81,0x7f,0x21,
+ 0xa3,0x52,0xbe,0x19,0x93,0x09,0xce,0x20,
+ 0x10,0x46,0x4a,0x4a,0xf8,0x27,0x31,0xec,
+ 0x58,0xc7,0xe8,0x33,0x82,0xe3,0xce,0xbf,
+ 0x85,0xf4,0xdf,0x94,0xce,0x4b,0x09,0xc1,
+ 0x94,0x56,0x8a,0xc0,0x13,0x72,0xa7,0xfc,
+ 0x9f,0x84,0x4d,0x73,0xa3,0xca,0x9a,0x61,
+ 0x58,0x97,0xa3,0x27,0xfc,0x03,0x98,0x76,
+ 0x23,0x1d,0xc7,0x61,0x03,0x04,0xae,0x56,
+ 0xbf,0x38,0x84,0x00,0x40,0xa7,0x0e,0xfd,
+ 0xff,0x52,0xfe,0x03,0x6f,0x95,0x30,0xf1,
+ 0x97,0xfb,0xc0,0x85,0x60,0xd6,0x80,0x25,
+ 0xa9,0x63,0xbe,0x03,0x01,0x4e,0x38,0xe2,
+ 0xf9,0xa2,0x34,0xff,0xbb,0x3e,0x03,0x44,
+ 0x78,0x00,0x90,0xcb,0x88,0x11,0x3a,0x94,
+ 0x65,0xc0,0x7c,0x63,0x87,0xf0,0x3c,0xaf,
+ 0xd6,0x25,0xe4,0x8b,0x38,0x0a,0xac,0x72,
+ 0x21,0xd4,0xf8,0x07
+ };
+
+ Array.Copy(logo, 0, cartRom, 4, logo.Length);
+ cartRom[0xB2] = 0x96;
+ cartRom[0xBD] = 0;
+ for (int i = 0xA0; i <= 0xBC; i++) cartRom[0xBD] = (byte)(cartRom[0xBD] - cartRom[i]);
+ cartRom[0xBD] = (byte)((cartRom[0xBD] - 0x19) & 0xFF);
+ */
+ this.memory.LoadCartridge(cartRom);
+
+ this.Reset();
+
+ if (this.onCpuUpdate != null)
+ {
+ this.onCpuUpdate(this.arm7, this.memory);
+ }
+ }
+
+ public void Step()
+ {
+ //this.Halt();
+
+ this.arm7.Step();
+
+ if (this.onCpuUpdate != null)
+ {
+ this.onCpuUpdate(this.arm7, this.memory);
+ }
+ }
+
+ public void StepScanline()
+ {
+ //this.Halt();
+
+ this.arm7.Execute(960);
+ this.videoManager.RenderLine();
+ this.videoManager.EnterHBlank(this.arm7);
+ this.arm7.Execute(272);
+ this.videoManager.LeaveHBlank(this.arm7);
+
+ if (this.onCpuUpdate != null)
+ {
+ this.onCpuUpdate(this.arm7, this.memory);
+ }
+ }
+
+ void UpdateInputState()
+ {
+ ushort ret = 0;
+ if (_controller["Up"]) ret |= 64;
+ if (_controller["Down"]) ret |= 128;
+ if (_controller["Left"]) ret |= 32;
+ if (_controller["Right"]) ret |= 16;
+ if (_controller["Select"]) ret |= 4;
+ if (_controller["Start"]) ret |= 8;
+ if (_controller["B"]) ret |= 2;
+ if (_controller["A"]) ret |= 1;
+ if (_controller["L"]) ret |= 512;
+ if (_controller["R"]) ret |= 256;
+ ret ^= 0x3ff;
+ KeyState = ret;
+ }
+
+ private void StepFrame()
+ {
+ UpdateInputState();
+ if (_controller["Power"])
+ Reset();
+
+ int vramCycles = 0;
+ bool inHblank = false;
+
+ //HighPerformanceTimer profileTimer = new HighPerformanceTimer();
+
+ while (true)
+ {
+
+
+ const int cycleStep = 123;
+
+
+ if (vramCycles <= 0)
+ {
+ if (inHblank)
+ {
+ vramCycles += 960;
+ bool HitVBlank = this.videoManager.LeaveHBlank(this.arm7);
+ inHblank = false;
+ if (HitVBlank)
+ break;
+ }
+ else
+ {
+ vramCycles += 272;
+ this.videoManager.RenderLine();
+ this.videoManager.EnterHBlank(this.arm7);
+ inHblank = true;
+ }
+ }
+
+ this.arm7.Execute(cycleStep);
+#if ARM_DEBUG
+ if (this.arm7.BreakpointHit)
+ {
+ this.waitingToHalt = true;
+ Monitor.Wait(this);
+ }
+#endif
+ vramCycles -= cycleStep;
+ this.arm7.FireIrq();
+ }
+
+
+ }
+
+ IVideoProvider IEmulator.VideoProvider
+ {
+ get { return this; }
+ }
+
+ ISoundProvider IEmulator.SoundProvider
+ {
+ get { return this; }
+ }
+
+ ISyncSoundProvider IEmulator.SyncSoundProvider
+ {
+ get { return new FakeSyncSound(this, 735); }
+ }
+
+ bool IEmulator.StartAsyncSound()
+ {
+ return false;
+ }
+
+ void IEmulator.EndAsyncSound()
+ {
+
+ }
+
+ ControllerDefinition IEmulator.ControllerDefinition
+ {
+ get { return BizHawk.Emulation.Consoles.Nintendo.GBA.GBA.GBAController; }
+ }
+
+ IController _controller;
+
+ IController IEmulator.Controller
+ {
+ get { return _controller; }
+ set { _controller = value; }
+ }
+
+ void IEmulator.FrameAdvance(bool render, bool rendersound)
+ {
+ StepFrame();
+ }
+
+ int IEmulator.Frame
+ {
+ get { return 0; }
+ }
+
+ int IEmulator.LagCount
+ {
+ get
+ {
+ return 0;
+ }
+ set
+ {
+
+ }
+ }
+
+ bool IEmulator.IsLagFrame
+ {
+ get { return false; }
+ }
+
+ string IEmulator.SystemId
+ {
+ get { return "GBA"; }
+ }
+
+ bool IEmulator.DeterministicEmulation
+ {
+ get { return true; }
+ }
+
+ byte[] IEmulator.ReadSaveRam()
+ {
+ return new byte[0];
+ }
+
+ void IEmulator.StoreSaveRam(byte[] data)
+ {
+
+ }
+
+ void IEmulator.ClearSaveRam()
+ {
+
+ }
+
+ bool IEmulator.SaveRamModified
+ {
+ get
+ {
+ return false;
+ }
+ set
+ {
+
+ }
+ }
+
+ void IEmulator.ResetFrameCounter()
+ {
+
+ }
+
+ void IEmulator.SaveStateText(TextWriter writer)
+ {
+
+ }
+
+ void IEmulator.LoadStateText(TextReader reader)
+ {
+
+ }
+
+ void IEmulator.SaveStateBinary(BinaryWriter writer)
+ {
+
+ }
+
+ void IEmulator.LoadStateBinary(BinaryReader reader)
+ {
+
+ }
+
+ byte[] IEmulator.SaveStateBinary()
+ {
+ return new byte[16];
+ }
+
+ CoreComm _corecomm;
+
+ CoreComm IEmulator.CoreComm
+ {
+ get { return _corecomm; }
+ }
+
+ IList IEmulator.MemoryDomains
+ {
+ get { return new List(); }
+ }
+
+ MemoryDomain IEmulator.MainMemory
+ {
+ get { return null; }
+ }
+
+ void IDisposable.Dispose()
+ {
+
+ }
+
+ void ISoundProvider.GetSamples(short[] samples)
+ {
+ AudioMixerStereo(samples, samples.Length);
+ }
+
+ void ISoundProvider.DiscardSamples()
+ {
+
+ }
+
+ int ISoundProvider.MaxVolume
+ {
+ get;
+ set;
+ }
+
+ int[] vbuf = new int[240 * 160];
+ int[] IVideoProvider.GetVideoBuffer() { return vbuf; }
+ int IVideoProvider.VirtualWidth { get { return 240; } }
+ int IVideoProvider.BufferWidth { get { return 240; } }
+ int IVideoProvider.BufferHeight { get { return 160; } }
+ int IVideoProvider.BackgroundColor { get { return unchecked((int)0xff000000); } }
+ }
+}
diff --git a/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/IRenderer.cs b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/IRenderer.cs
new file mode 100644
index 0000000000..20fce17447
--- /dev/null
+++ b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/IRenderer.cs
@@ -0,0 +1,13 @@
+namespace GarboDev
+{
+ using System;
+
+ public interface IRenderer
+ {
+ Memory Memory { set; }
+ void Initialize(object data);
+ void Reset();
+ void RenderLine(int line);
+ uint[] ShowFrame();
+ }
+}
diff --git a/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/Memory.cs b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/Memory.cs
new file mode 100644
index 0000000000..23101aff05
--- /dev/null
+++ b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/Memory.cs
@@ -0,0 +1,1981 @@
+namespace GarboDev
+{
+ using System;
+ using System.Collections.Generic;
+
+ public class Memory
+ {
+ public const uint REG_BASE = 0x4000000;
+ public const uint PAL_BASE = 0x5000000;
+ public const uint VRAM_BASE = 0x6000000;
+ public const uint OAM_BASE = 0x7000000;
+
+ public const uint DISPCNT = 0x0;
+ public const uint DISPSTAT = 0x4;
+ public const uint VCOUNT = 0x6;
+
+ public const uint BG0CNT = 0x8;
+ public const uint BG1CNT = 0xA;
+ public const uint BG2CNT = 0xC;
+ public const uint BG3CNT = 0xE;
+
+ public const uint BG0HOFS = 0x10;
+ public const uint BG0VOFS = 0x12;
+ public const uint BG1HOFS = 0x14;
+ public const uint BG1VOFS = 0x16;
+ public const uint BG2HOFS = 0x18;
+ public const uint BG2VOFS = 0x1A;
+ public const uint BG3HOFS = 0x1C;
+ public const uint BG3VOFS = 0x1E;
+
+ public const uint BG2PA = 0x20;
+ public const uint BG2PB = 0x22;
+ public const uint BG2PC = 0x24;
+ public const uint BG2PD = 0x26;
+ public const uint BG2X_L = 0x28;
+ public const uint BG2X_H = 0x2A;
+ public const uint BG2Y_L = 0x2C;
+ public const uint BG2Y_H = 0x2E;
+ public const uint BG3PA = 0x30;
+ public const uint BG3PB = 0x32;
+ public const uint BG3PC = 0x34;
+ public const uint BG3PD = 0x36;
+ public const uint BG3X_L = 0x38;
+ public const uint BG3X_H = 0x3A;
+ public const uint BG3Y_L = 0x3C;
+ public const uint BG3Y_H = 0x3E;
+
+ public const uint WIN0H = 0x40;
+ public const uint WIN1H = 0x42;
+ public const uint WIN0V = 0x44;
+ public const uint WIN1V = 0x46;
+ public const uint WININ = 0x48;
+ public const uint WINOUT = 0x4A;
+
+ public const uint BLDCNT = 0x50;
+ public const uint BLDALPHA = 0x52;
+ public const uint BLDY = 0x54;
+
+ public const uint SOUNDCNT_L = 0x80;
+ public const uint SOUNDCNT_H = 0x82;
+ public const uint SOUNDCNT_X = 0x84;
+
+ public const uint FIFO_A_L = 0xA0;
+ public const uint FIFO_A_H = 0xA2;
+ public const uint FIFO_B_L = 0xA4;
+ public const uint FIFO_B_H = 0xA6;
+
+ public const uint DMA0SAD = 0xB0;
+ public const uint DMA0DAD = 0xB4;
+ public const uint DMA0CNT_L = 0xB8;
+ public const uint DMA0CNT_H = 0xBA;
+ public const uint DMA1SAD = 0xBC;
+ public const uint DMA1DAD = 0xC0;
+ public const uint DMA1CNT_L = 0xC4;
+ public const uint DMA1CNT_H = 0xC6;
+ public const uint DMA2SAD = 0xC8;
+ public const uint DMA2DAD = 0xCC;
+ public const uint DMA2CNT_L = 0xD0;
+ public const uint DMA2CNT_H = 0xD2;
+ public const uint DMA3SAD = 0xD4;
+ public const uint DMA3DAD = 0xD8;
+ public const uint DMA3CNT_L = 0xDC;
+ public const uint DMA3CNT_H = 0xDE;
+
+ public const uint TM0D = 0x100;
+ public const uint TM0CNT = 0x102;
+ public const uint TM1D = 0x104;
+ public const uint TM1CNT = 0x106;
+ public const uint TM2D = 0x108;
+ public const uint TM2CNT = 0x10A;
+ public const uint TM3D = 0x10C;
+ public const uint TM3CNT = 0x10E;
+
+ public const uint KEYINPUT = 0x130;
+ public const uint KEYCNT = 0x132;
+ public const uint IE = 0x200;
+ public const uint IF = 0x202;
+ public const uint IME = 0x208;
+
+ public const uint HALTCNT = 0x300;
+
+ private const uint biosRamMask = 0x3FFF;
+ private const uint ewRamMask = 0x3FFFF;
+ private const uint iwRamMask = 0x7FFF;
+ private const uint ioRegMask = 0x4FF;
+ private const uint vRamMask = 0x1FFFF;
+ private const uint palRamMask = 0x3FF;
+ private const uint oamRamMask = 0x3FF;
+ private const uint sRamMask = 0xFFFF;
+
+ private byte[] biosRam = new byte[Memory.biosRamMask + 1];
+ private byte[] ewRam = new byte[Memory.ewRamMask + 1];
+ private byte[] iwRam = new byte[Memory.iwRamMask + 1];
+ private byte[] ioReg = new byte[Memory.ioRegMask + 1];
+ private byte[] vRam = new byte[Memory.vRamMask + 1];
+ private byte[] palRam = new byte[Memory.palRamMask + 1];
+ private byte[] oamRam = new byte[Memory.oamRamMask + 1];
+ private byte[] sRam = new byte[Memory.sRamMask + 1];
+
+ public byte[] VideoRam
+ {
+ get
+ {
+ return this.vRam;
+ }
+ }
+
+ public byte[] PaletteRam
+ {
+ get
+ {
+ return this.palRam;
+ }
+ }
+
+ public byte[] OamRam
+ {
+ get
+ {
+ return this.oamRam;
+ }
+ }
+
+ public byte[] IORam
+ {
+ get
+ {
+ return this.ioReg;
+ }
+ }
+
+ private ushort keyState = 0x3FF;
+
+ public ushort KeyState
+ {
+ get { return this.keyState; }
+ set { this.keyState = value; }
+ }
+
+ private Arm7Processor processor = null;
+ public Arm7Processor Processor
+ {
+ get { return this.processor; }
+ set { this.processor = value; }
+ }
+
+ private SoundManager soundManager = null;
+ public SoundManager SoundManager
+ {
+ get { return this.soundManager; }
+ set { this.soundManager = value; }
+ }
+
+ private byte[] romBank1 = null;
+ private byte[] romBank2 = null;
+ private uint romBank1Mask = 0;
+ private uint romBank2Mask = 0;
+
+ private int[] bankSTimes = new int[0x10];
+ private int[] bankNTimes = new int[0x10];
+
+ private int waitCycles = 0;
+
+ public int WaitCycles
+ {
+ get { int tmp = this.waitCycles; this.waitCycles = 0; return tmp; }
+ }
+
+ private bool inUnreadable = false;
+
+ private delegate byte ReadU8Delegate(uint address);
+ private delegate void WriteU8Delegate(uint address, byte value);
+ private delegate ushort ReadU16Delegate(uint address);
+ private delegate void WriteU16Delegate(uint address, ushort value);
+ private delegate uint ReadU32Delegate(uint address);
+ private delegate void WriteU32Delegate(uint address, uint value);
+
+ private ReadU8Delegate[] ReadU8Funcs = null;
+ private WriteU8Delegate[] WriteU8Funcs = null;
+ private ReadU16Delegate[] ReadU16Funcs = null;
+ private WriteU16Delegate[] WriteU16Funcs = null;
+ private ReadU32Delegate[] ReadU32Funcs = null;
+ private WriteU32Delegate[] WriteU32Funcs = null;
+
+ private uint[,] dmaRegs = new uint[4, 4];
+ private uint[] timerCnt = new uint[4];
+ private int[] bgx = new int[2], bgy = new int[2];
+
+ public uint[] TimerCnt
+ {
+ get { return this.timerCnt; }
+ }
+
+ public int[] Bgx
+ {
+ get { return this.bgx; }
+ }
+
+ public int[] Bgy
+ {
+ get { return this.bgy; }
+ }
+
+ public Memory()
+ {
+ this.ReadU8Funcs = new ReadU8Delegate[]
+ {
+ this.ReadBiosRam8,
+ this.ReadNop8,
+ this.ReadEwRam8,
+ this.ReadIwRam8,
+ this.ReadIO8,
+ this.ReadPalRam8,
+ this.ReadVRam8,
+ this.ReadOamRam8,
+ this.ReadNop8,
+ this.ReadNop8,
+ this.ReadNop8,
+ this.ReadNop8,
+ this.ReadNop8,
+ this.ReadNop8,
+ this.ReadSRam8,
+ this.ReadNop8
+ };
+
+ this.WriteU8Funcs = new WriteU8Delegate[]
+ {
+ this.WriteNop8,
+ this.WriteNop8,
+ this.WriteEwRam8,
+ this.WriteIwRam8,
+ this.WriteIO8,
+ this.WritePalRam8,
+ this.WriteVRam8,
+ this.WriteOamRam8,
+ this.WriteNop8,
+ this.WriteNop8,
+ this.WriteNop8,
+ this.WriteNop8,
+ this.WriteNop8,
+ this.WriteNop8,
+ this.WriteSRam8,
+ this.WriteNop8
+ };
+
+ this.ReadU16Funcs = new ReadU16Delegate[]
+ {
+ this.ReadBiosRam16,
+ this.ReadNop16,
+ this.ReadEwRam16,
+ this.ReadIwRam16,
+ this.ReadIO16,
+ this.ReadPalRam16,
+ this.ReadVRam16,
+ this.ReadOamRam16,
+ this.ReadNop16,
+ this.ReadNop16,
+ this.ReadNop16,
+ this.ReadNop16,
+ this.ReadNop16,
+ this.ReadNop16,
+ this.ReadSRam16,
+ this.ReadNop16
+ };
+
+ this.WriteU16Funcs = new WriteU16Delegate[]
+ {
+ this.WriteNop16,
+ this.WriteNop16,
+ this.WriteEwRam16,
+ this.WriteIwRam16,
+ this.WriteIO16,
+ this.WritePalRam16,
+ this.WriteVRam16,
+ this.WriteOamRam16,
+ this.WriteNop16,
+ this.WriteNop16,
+ this.WriteNop16,
+ this.WriteNop16,
+ this.WriteNop16,
+ this.WriteNop16,
+ this.WriteSRam16,
+ this.WriteNop16
+ };
+
+ this.ReadU32Funcs = new ReadU32Delegate[]
+ {
+ this.ReadBiosRam32,
+ this.ReadNop32,
+ this.ReadEwRam32,
+ this.ReadIwRam32,
+ this.ReadIO32,
+ this.ReadPalRam32,
+ this.ReadVRam32,
+ this.ReadOamRam32,
+ this.ReadNop32,
+ this.ReadNop32,
+ this.ReadNop32,
+ this.ReadNop32,
+ this.ReadNop32,
+ this.ReadNop32,
+ this.ReadSRam32,
+ this.ReadNop32
+ };
+
+ this.WriteU32Funcs = new WriteU32Delegate[]
+ {
+ this.WriteNop32,
+ this.WriteNop32,
+ this.WriteEwRam32,
+ this.WriteIwRam32,
+ this.WriteIO32,
+ this.WritePalRam32,
+ this.WriteVRam32,
+ this.WriteOamRam32,
+ this.WriteNop32,
+ this.WriteNop32,
+ this.WriteNop32,
+ this.WriteNop32,
+ this.WriteNop32,
+ this.WriteNop32,
+ this.WriteSRam32,
+ this.WriteNop32
+ };
+ }
+
+ public void Reset()
+ {
+ Array.Clear(this.ewRam, 0, this.ewRam.Length);
+ Array.Clear(this.iwRam, 0, this.iwRam.Length);
+ Array.Clear(this.ioReg, 0, this.ioReg.Length);
+ Array.Clear(this.vRam, 0, this.vRam.Length);
+ Array.Clear(this.palRam, 0, this.palRam.Length);
+ Array.Clear(this.oamRam, 0, this.oamRam.Length);
+ Array.Clear(this.sRam, 0, this.sRam.Length);
+
+ Memory.WriteU16(this.ioReg, Memory.BG2PA, 0x0100);
+ Memory.WriteU16(this.ioReg, Memory.BG2PD, 0x0100);
+ Memory.WriteU16(this.ioReg, Memory.BG3PA, 0x0100);
+ Memory.WriteU16(this.ioReg, Memory.BG3PD, 0x0100);
+ }
+
+ public void HBlankDma()
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ if (((this.dmaRegs[i, 3] >> 12) & 0x3) == 2)
+ {
+ this.DmaTransfer(i);
+ }
+ }
+ }
+
+ public void VBlankDma()
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ if (((this.dmaRegs[i, 3] >> 12) & 0x3) == 1)
+ {
+ this.DmaTransfer(i);
+ }
+ }
+ }
+
+ public void FifoDma(int channel)
+ {
+ if (((this.dmaRegs[channel, 3] >> 12) & 0x3) == 0x3)
+ {
+ this.DmaTransfer(channel);
+ }
+ }
+
+ public void DmaTransfer(int channel)
+ {
+ // Check if DMA is enabled
+ if ((this.dmaRegs[channel, 3] & (1 << 15)) != 0)
+ {
+ bool wideTransfer = (this.dmaRegs[channel, 3] & (1 << 10)) != 0;
+
+ uint srcDirection = 0, destDirection = 0;
+ bool reload = false;
+
+ switch ((this.dmaRegs[channel, 3] >> 5) & 0x3)
+ {
+ case 0: destDirection = 1; break;
+ case 1: destDirection = 0xFFFFFFFF; break;
+ case 2: destDirection = 0; break;
+ case 3: destDirection = 1; reload = true; break;
+ }
+
+ switch ((this.dmaRegs[channel, 3] >> 7) & 0x3)
+ {
+ case 0: srcDirection = 1; break;
+ case 1: srcDirection = 0xFFFFFFFF; break;
+ case 2: srcDirection = 0; break;
+ case 3: if (channel == 3)
+ {
+ // TODO
+ return;
+ }
+ throw new Exception("Unhandled DMA mode.");
+ }
+
+ int numElements = (int)this.dmaRegs[channel, 2];
+ if (numElements == 0) numElements = 0x4000;
+
+ if (((this.dmaRegs[channel, 3] >> 12) & 0x3) == 0x3)
+ {
+ // Sound FIFO mode
+ wideTransfer = true;
+ destDirection = 0;
+ numElements = 4;
+ reload = false;
+ }
+
+ if (wideTransfer)
+ {
+ srcDirection *= 4;
+ destDirection *= 4;
+ while (numElements-- > 0)
+ {
+ this.WriteU32(this.dmaRegs[channel, 1], this.ReadU32(this.dmaRegs[channel, 0]));
+ this.dmaRegs[channel, 1] += destDirection;
+ this.dmaRegs[channel, 0] += srcDirection;
+ }
+ }
+ else
+ {
+ srcDirection *= 2;
+ destDirection *= 2;
+ while (numElements-- > 0)
+ {
+ this.WriteU16(this.dmaRegs[channel, 1], this.ReadU16(this.dmaRegs[channel, 0]));
+ this.dmaRegs[channel, 1] += destDirection;
+ this.dmaRegs[channel, 0] += srcDirection;
+ }
+ }
+
+ // If not a repeating DMA, then disable the DMA
+ if ((this.dmaRegs[channel, 3] & (1 << 9)) == 0)
+ {
+ this.dmaRegs[channel, 3] &= 0x7FFF;
+ }
+ else
+ {
+ // Reload dest and count
+ switch (channel)
+ {
+ case 0:
+ if (reload) this.dmaRegs[0, 1] = Memory.ReadU32(this.ioReg, Memory.DMA0DAD) & 0x07FFFFFF;
+ this.dmaRegs[0, 2] = Memory.ReadU16(this.ioReg, Memory.DMA0CNT_L);
+ break;
+ case 1:
+ if (reload) this.dmaRegs[1, 1] = Memory.ReadU32(this.ioReg, Memory.DMA1DAD) & 0x07FFFFFF;
+ this.dmaRegs[1, 2] = Memory.ReadU16(this.ioReg, Memory.DMA1CNT_L);
+ break;
+ case 2:
+ if (reload) this.dmaRegs[2, 1] = Memory.ReadU32(this.ioReg, Memory.DMA2DAD) & 0x07FFFFFF;
+ this.dmaRegs[2, 2] = Memory.ReadU16(this.ioReg, Memory.DMA2CNT_L);
+ break;
+ case 3:
+ if (reload) this.dmaRegs[3, 1] = Memory.ReadU32(this.ioReg, Memory.DMA3DAD) & 0x0FFFFFFF;
+ this.dmaRegs[3, 2] = Memory.ReadU16(this.ioReg, Memory.DMA3CNT_L);
+ break;
+ }
+ }
+
+ if ((this.dmaRegs[channel, 3] & (1 << 14)) != 0)
+ {
+ this.processor.RequestIrq(8 + channel);
+ }
+ }
+ }
+
+ public void WriteDmaControl(int channel)
+ {
+ switch (channel)
+ {
+ case 0:
+ if (((this.dmaRegs[0, 3] ^ Memory.ReadU16(this.ioReg, Memory.DMA0CNT_H)) & (1 << 15)) == 0) return;
+ this.dmaRegs[0, 0] = Memory.ReadU32(this.ioReg, Memory.DMA0SAD) & 0x07FFFFFF;
+ this.dmaRegs[0, 1] = Memory.ReadU32(this.ioReg, Memory.DMA0DAD) & 0x07FFFFFF;
+ this.dmaRegs[0, 2] = Memory.ReadU16(this.ioReg, Memory.DMA0CNT_L);
+ this.dmaRegs[0, 3] = Memory.ReadU16(this.ioReg, Memory.DMA0CNT_H);
+ break;
+ case 1:
+ if (((this.dmaRegs[1, 3] ^ Memory.ReadU16(this.ioReg, Memory.DMA1CNT_H)) & (1 << 15)) == 0) return;
+ this.dmaRegs[1, 0] = Memory.ReadU32(this.ioReg, Memory.DMA1SAD) & 0x0FFFFFFF;
+ this.dmaRegs[1, 1] = Memory.ReadU32(this.ioReg, Memory.DMA1DAD) & 0x07FFFFFF;
+ this.dmaRegs[1, 2] = Memory.ReadU16(this.ioReg, Memory.DMA1CNT_L);
+ this.dmaRegs[1, 3] = Memory.ReadU16(this.ioReg, Memory.DMA1CNT_H);
+ break;
+ case 2:
+ if (((this.dmaRegs[2, 3] ^ Memory.ReadU16(this.ioReg, Memory.DMA2CNT_H)) & (1 << 15)) == 0) return;
+ this.dmaRegs[2, 0] = Memory.ReadU32(this.ioReg, Memory.DMA2SAD) & 0x0FFFFFFF;
+ this.dmaRegs[2, 1] = Memory.ReadU32(this.ioReg, Memory.DMA2DAD) & 0x07FFFFFF;
+ this.dmaRegs[2, 2] = Memory.ReadU16(this.ioReg, Memory.DMA2CNT_L);
+ this.dmaRegs[2, 3] = Memory.ReadU16(this.ioReg, Memory.DMA2CNT_H);
+ break;
+ case 3:
+ if (((this.dmaRegs[3, 3] ^ Memory.ReadU16(this.ioReg, Memory.DMA3CNT_H)) & (1 << 15)) == 0) return;
+ this.dmaRegs[3, 0] = Memory.ReadU32(this.ioReg, Memory.DMA3SAD) & 0x0FFFFFFF;
+ this.dmaRegs[3, 1] = Memory.ReadU32(this.ioReg, Memory.DMA3DAD) & 0x0FFFFFFF;
+ this.dmaRegs[3, 2] = Memory.ReadU16(this.ioReg, Memory.DMA3CNT_L);
+ this.dmaRegs[3, 3] = Memory.ReadU16(this.ioReg, Memory.DMA3CNT_H);
+ break;
+ }
+
+ // Channel start timing
+ switch ((this.dmaRegs[channel, 3] >> 12) & 0x3)
+ {
+ case 0:
+ // Start immediately
+ this.DmaTransfer(channel);
+ break;
+ case 1:
+ case 2:
+ // Hblank and Vblank DMA's
+ break;
+ case 3:
+ // TODO (DMA sound)
+ return;
+ }
+ }
+
+ private void WriteTimerControl(int timer, ushort newCnt)
+ {
+ ushort control = Memory.ReadU16(this.ioReg, Memory.TM0CNT + (uint)(timer * 4));
+ uint count = Memory.ReadU16(this.ioReg, Memory.TM0D + (uint)(timer * 4));
+
+ if ((newCnt & (1 << 7)) != 0 && (control & (1 << 7)) == 0)
+ {
+ this.timerCnt[timer] = count << 10;
+ }
+ }
+
+ #region Read/Write Helpers
+ public static ushort ReadU16(byte[] array, uint position)
+ {
+ return (ushort)(array[position] | (array[position + 1] << 8));
+ }
+
+ public static uint ReadU32(byte[] array, uint position)
+ {
+ return (uint)(array[position] | (array[position + 1] << 8) |
+ (array[position + 2] << 16) | (array[position + 3] << 24));
+ }
+
+ public static void WriteU16(byte[] array, uint position, ushort value)
+ {
+ array[position] = (byte)(value & 0xff);
+ array[position + 1] = (byte)(value >> 8);
+ }
+
+ public static void WriteU32(byte[] array, uint position, uint value)
+ {
+ array[position] = (byte)(value & 0xff);
+ array[position + 1] = (byte)((value >> 8) & 0xff);
+ array[position + 2] = (byte)((value >> 16) & 0xff);
+ array[position + 3] = (byte)(value >> 24);
+ }
+ #endregion
+
+ #region Memory Reads
+ private uint ReadUnreadable()
+ {
+ if (this.inUnreadable)
+ {
+ return 0;
+ }
+
+ this.inUnreadable = true;
+
+ uint res;
+
+ if (this.processor.ArmState)
+ {
+ res = this.ReadU32(this.processor.Registers[15]);
+ }
+ else
+ {
+ ushort val = this.ReadU16(this.processor.Registers[15]);
+ res = (uint)(val | (val << 16));
+ }
+
+ this.inUnreadable = false;
+
+ return res;
+ }
+
+ private byte ReadNop8(uint address)
+ {
+ return (byte)(this.ReadUnreadable() & 0xFF);
+ }
+
+ private ushort ReadNop16(uint address)
+ {
+ return (ushort)(this.ReadUnreadable() & 0xFFFF);
+ }
+
+ private uint ReadNop32(uint address)
+ {
+ return this.ReadUnreadable();
+ }
+
+ private byte ReadBiosRam8(uint address)
+ {
+ this.waitCycles++;
+ if (this.processor.Registers[15] < 0x01000000)
+ {
+ return this.biosRam[address & Memory.biosRamMask];
+ }
+ return (byte)(this.ReadUnreadable() & 0xFF);
+ }
+
+ private ushort ReadBiosRam16(uint address)
+ {
+ this.waitCycles++;
+ if (this.processor.Registers[15] < 0x01000000)
+ {
+ return Memory.ReadU16(this.biosRam, address & Memory.biosRamMask);
+ }
+ return (ushort)(this.ReadUnreadable() & 0xFFFF);
+ }
+
+ private uint ReadBiosRam32(uint address)
+ {
+ this.waitCycles++;
+ if (this.processor.Registers[15] < 0x01000000)
+ {
+ return Memory.ReadU32(this.biosRam, address & Memory.biosRamMask);
+ }
+ return this.ReadUnreadable();
+ }
+
+ private byte ReadEwRam8(uint address)
+ {
+ this.waitCycles += 3;
+ return this.ewRam[address & Memory.ewRamMask];
+ }
+
+ private ushort ReadEwRam16(uint address)
+ {
+ this.waitCycles += 3;
+ return Memory.ReadU16(this.ewRam, address & Memory.ewRamMask);
+ }
+
+ private uint ReadEwRam32(uint address)
+ {
+ this.waitCycles += 6;
+ return Memory.ReadU32(this.ewRam, address & Memory.ewRamMask);
+ }
+
+ private byte ReadIwRam8(uint address)
+ {
+ this.waitCycles++;
+ return this.iwRam[address & Memory.iwRamMask];
+ }
+
+ private ushort ReadIwRam16(uint address)
+ {
+ this.waitCycles++;
+ return Memory.ReadU16(this.iwRam, address & Memory.iwRamMask);
+ }
+
+ private uint ReadIwRam32(uint address)
+ {
+ this.waitCycles++;
+ return Memory.ReadU32(this.iwRam, address & Memory.iwRamMask);
+ }
+
+ private byte ReadIO8(uint address)
+ {
+ this.waitCycles++;
+ address &= 0xFFFFFF;
+ if (address >= Memory.ioRegMask) return 0;
+
+ switch (address)
+ {
+ case KEYINPUT:
+ return (byte)(this.keyState & 0xFF);
+ case KEYINPUT + 1:
+ return (byte)(this.keyState >> 8);
+
+ case DMA0CNT_H:
+ return (byte)(this.dmaRegs[0, 3] & 0xFF);
+ case DMA0CNT_H + 1:
+ return (byte)(this.dmaRegs[0, 3] >> 8);
+ case DMA1CNT_H:
+ return (byte)(this.dmaRegs[1, 3] & 0xFF);
+ case DMA1CNT_H + 1:
+ return (byte)(this.dmaRegs[1, 3] >> 8);
+ case DMA2CNT_H:
+ return (byte)(this.dmaRegs[2, 3] & 0xFF);
+ case DMA2CNT_H + 1:
+ return (byte)(this.dmaRegs[2, 3] >> 8);
+ case DMA3CNT_H:
+ return (byte)(this.dmaRegs[3, 3] & 0xFF);
+ case DMA3CNT_H + 1:
+ return (byte)(this.dmaRegs[3, 3] >> 8);
+
+ case TM0D:
+ this.processor.UpdateTimers();
+ return (byte)((this.timerCnt[0] >> 10) & 0xFF);
+ case TM0D + 1:
+ this.processor.UpdateTimers();
+ return (byte)((this.timerCnt[0] >> 10) >> 8);
+ case TM1D:
+ this.processor.UpdateTimers();
+ return (byte)((this.timerCnt[1] >> 10) & 0xFF);
+ case TM1D + 1:
+ this.processor.UpdateTimers();
+ return (byte)((this.timerCnt[1] >> 10) >> 8);
+ case TM2D:
+ this.processor.UpdateTimers();
+ return (byte)((this.timerCnt[2] >> 10) & 0xFF);
+ case TM2D + 1:
+ this.processor.UpdateTimers();
+ return (byte)((this.timerCnt[2] >> 10) >> 8);
+ case TM3D:
+ this.processor.UpdateTimers();
+ return (byte)((this.timerCnt[3] >> 10) & 0xFF);
+ case TM3D + 1:
+ this.processor.UpdateTimers();
+ return (byte)((this.timerCnt[3] >> 10) >> 8);
+
+ default:
+ return this.ioReg[address];
+ }
+ }
+
+ private ushort ReadIO16(uint address)
+ {
+ this.waitCycles++;
+ address &= 0xFFFFFF;
+ if (address >= Memory.ioRegMask) return 0;
+
+ switch (address)
+ {
+ case KEYINPUT:
+ return this.keyState;
+
+ case DMA0CNT_H:
+ return (ushort)this.dmaRegs[0, 3];
+ case DMA1CNT_H:
+ return (ushort)this.dmaRegs[1, 3];
+ case DMA2CNT_H:
+ return (ushort)this.dmaRegs[2, 3];
+ case DMA3CNT_H:
+ return (ushort)this.dmaRegs[3, 3];
+
+ case TM0D:
+ this.processor.UpdateTimers();
+ return (ushort)((this.timerCnt[0] >> 10) & 0xFFFF);
+ case TM1D:
+ this.processor.UpdateTimers();
+ return (ushort)((this.timerCnt[1] >> 10) & 0xFFFF);
+ case TM2D:
+ this.processor.UpdateTimers();
+ return (ushort)((this.timerCnt[2] >> 10) & 0xFFFF);
+ case TM3D:
+ this.processor.UpdateTimers();
+ return (ushort)((this.timerCnt[3] >> 10) & 0xFFFF);
+
+ default:
+ return Memory.ReadU16(this.ioReg, address);
+ }
+ }
+
+ private uint ReadIO32(uint address)
+ {
+ this.waitCycles++;
+ address &= 0xFFFFFF;
+ if (address >= Memory.ioRegMask) return 0;
+
+ switch (address)
+ {
+ case KEYINPUT:
+ return this.keyState | ((uint)Memory.ReadU16(this.ioReg, address + 0x2) << 16);
+
+ case DMA0CNT_L:
+ return (uint)Memory.ReadU16(this.ioReg, address) | (this.dmaRegs[0, 3] << 16);
+ case DMA1CNT_L:
+ return (uint)Memory.ReadU16(this.ioReg, address) | (this.dmaRegs[1, 3] << 16);
+ case DMA2CNT_L:
+ return (uint)Memory.ReadU16(this.ioReg, address) | (this.dmaRegs[2, 3] << 16);
+ case DMA3CNT_L:
+ return (uint)Memory.ReadU16(this.ioReg, address) | (this.dmaRegs[3, 3] << 16);
+
+ case TM0D:
+ this.processor.UpdateTimers();
+ return (uint)(((this.timerCnt[0] >> 10) & 0xFFFF) | (uint)(Memory.ReadU16(this.ioReg, address + 2) << 16));
+ case TM1D:
+ this.processor.UpdateTimers();
+ return (uint)(((this.timerCnt[1] >> 10) & 0xFFFF) | (uint)(Memory.ReadU16(this.ioReg, address + 2) << 16));
+ case TM2D:
+ this.processor.UpdateTimers();
+ return (uint)(((this.timerCnt[2] >> 10) & 0xFFFF) | (uint)(Memory.ReadU16(this.ioReg, address + 2) << 16));
+ case TM3D:
+ this.processor.UpdateTimers();
+ return (uint)(((this.timerCnt[3] >> 10) & 0xFFFF) | (uint)(Memory.ReadU16(this.ioReg, address + 2) << 16));
+
+ default:
+ return Memory.ReadU32(this.ioReg, address);
+ }
+ }
+
+ private byte ReadPalRam8(uint address)
+ {
+ this.waitCycles++;
+ return this.palRam[address & Memory.palRamMask];
+ }
+
+ private ushort ReadPalRam16(uint address)
+ {
+ this.waitCycles++;
+ return Memory.ReadU16(this.palRam, address & Memory.palRamMask);
+ }
+
+ private uint ReadPalRam32(uint address)
+ {
+ this.waitCycles += 2;
+ return Memory.ReadU32(this.palRam, address & Memory.palRamMask);
+ }
+
+ private byte ReadVRam8(uint address)
+ {
+ this.waitCycles++;
+ address &= Memory.vRamMask;
+ if (address > 0x17FFF) address = 0x10000 + ((address - 0x17FFF) & 0x7FFF);
+ return this.vRam[address];
+ }
+
+ private ushort ReadVRam16(uint address)
+ {
+ this.waitCycles++;
+ address &= Memory.vRamMask;
+ if (address > 0x17FFF) address = 0x10000 + ((address - 0x17FFF) & 0x7FFF);
+ return Memory.ReadU16(this.vRam, address);
+ }
+
+ private uint ReadVRam32(uint address)
+ {
+ this.waitCycles += 2;
+ address &= Memory.vRamMask;
+ if (address > 0x17FFF) address = 0x10000 + ((address - 0x17FFF) & 0x7FFF);
+ return Memory.ReadU32(this.vRam, address & Memory.vRamMask);
+ }
+
+ private byte ReadOamRam8(uint address)
+ {
+ this.waitCycles++;
+ return this.oamRam[address & Memory.oamRamMask];
+ }
+
+ private ushort ReadOamRam16(uint address)
+ {
+ this.waitCycles++;
+ return Memory.ReadU16(this.oamRam, address & Memory.oamRamMask);
+ }
+
+ private uint ReadOamRam32(uint address)
+ {
+ this.waitCycles++;
+ return Memory.ReadU32(this.oamRam, address & Memory.oamRamMask);
+ }
+
+ private byte ReadRom1_8(uint address)
+ {
+ this.waitCycles += this.bankSTimes[(address >> 24) & 0xf];
+ return this.romBank1[address & this.romBank1Mask];
+ }
+
+ private ushort ReadRom1_16(uint address)
+ {
+ this.waitCycles += this.bankSTimes[(address >> 24) & 0xf];
+ return Memory.ReadU16(this.romBank1, address & this.romBank1Mask);
+ }
+
+ private uint ReadRom1_32(uint address)
+ {
+ this.waitCycles += this.bankSTimes[(address >> 24) & 0xf] * 2 + 1;
+ return Memory.ReadU32(this.romBank1, address & this.romBank1Mask);
+ }
+
+ private byte ReadRom2_8(uint address)
+ {
+ this.waitCycles += this.bankSTimes[(address >> 24) & 0xf];
+ return this.romBank2[address & this.romBank2Mask];
+ }
+
+ private ushort ReadRom2_16(uint address)
+ {
+ this.waitCycles += this.bankSTimes[(address >> 24) & 0xf];
+ return Memory.ReadU16(this.romBank2, address & this.romBank2Mask);
+ }
+
+ private uint ReadRom2_32(uint address)
+ {
+ this.waitCycles += this.bankSTimes[(address >> 24) & 0xf] * 2 + 1;
+ return Memory.ReadU32(this.romBank2, address & this.romBank2Mask);
+ }
+
+ private byte ReadSRam8(uint address)
+ {
+ return this.sRam[address & Memory.sRamMask];
+ }
+
+ private ushort ReadSRam16(uint address)
+ {
+ // TODO
+ return 0;
+ }
+
+ private uint ReadSRam32(uint address)
+ {
+ // TODO
+ return 0;
+ }
+ #endregion
+
+ #region Memory Writes
+ private void WriteNop8(uint address, byte value)
+ {
+ }
+
+ private void WriteNop16(uint address, ushort value)
+ {
+ }
+
+ private void WriteNop32(uint address, uint value)
+ {
+ }
+
+ private void WriteEwRam8(uint address, byte value)
+ {
+ this.waitCycles += 3;
+ this.ewRam[address & Memory.ewRamMask] = value;
+ }
+
+ private void WriteEwRam16(uint address, ushort value)
+ {
+ this.waitCycles += 3;
+ Memory.WriteU16(this.ewRam, address & Memory.ewRamMask, value);
+ }
+
+ private void WriteEwRam32(uint address, uint value)
+ {
+ this.waitCycles += 6;
+ Memory.WriteU32(this.ewRam, address & Memory.ewRamMask, value);
+ }
+
+ private void WriteIwRam8(uint address, byte value)
+ {
+ this.waitCycles++;
+ this.iwRam[address & Memory.iwRamMask] = value;
+ }
+
+ private void WriteIwRam16(uint address, ushort value)
+ {
+ this.waitCycles++;
+ Memory.WriteU16(this.iwRam, address & Memory.iwRamMask, value);
+ }
+
+ private void WriteIwRam32(uint address, uint value)
+ {
+ this.waitCycles++;
+ Memory.WriteU32(this.iwRam, address & Memory.iwRamMask, value);
+ }
+
+ private void WriteIO8(uint address, byte value)
+ {
+ this.waitCycles++;
+ address &= 0xFFFFFF;
+ if (address >= Memory.ioRegMask) return;
+
+ switch (address)
+ {
+ case BG2X_L:
+ case BG2X_L + 1:
+ case BG2X_L + 2:
+ case BG2X_L + 3:
+ {
+ this.ioReg[address] = value;
+ uint tmp = Memory.ReadU32(this.ioReg, BG2X_L);
+ if ((tmp & (1 << 27)) != 0) tmp |= 0xF0000000;
+ Memory.WriteU32(this.ioReg, BG2X_L, tmp);
+
+ this.bgx[0] = (int)tmp;
+ }
+ break;
+
+ case BG3X_L:
+ case BG3X_L + 1:
+ case BG3X_L + 2:
+ case BG3X_L + 3:
+ {
+ this.ioReg[address] = value;
+ uint tmp = Memory.ReadU32(this.ioReg, BG3X_L);
+ if ((tmp & (1 << 27)) != 0) tmp |= 0xF0000000;
+ Memory.WriteU32(this.ioReg, BG3X_L, tmp);
+
+ this.bgx[1] = (int)tmp;
+ }
+ break;
+
+ case BG2Y_L:
+ case BG2Y_L + 1:
+ case BG2Y_L + 2:
+ case BG2Y_L + 3:
+ {
+ this.ioReg[address] = value;
+ uint tmp = Memory.ReadU32(this.ioReg, BG2Y_L);
+ if ((tmp & (1 << 27)) != 0) tmp |= 0xF0000000;
+ Memory.WriteU32(this.ioReg, BG2Y_L, tmp);
+
+ this.bgy[0] = (int)tmp;
+ }
+ break;
+
+ case BG3Y_L:
+ case BG3Y_L + 1:
+ case BG3Y_L + 2:
+ case BG3Y_L + 3:
+ {
+ this.ioReg[address] = value;
+ uint tmp = Memory.ReadU32(this.ioReg, BG3Y_L);
+ if ((tmp & (1 << 27)) != 0) tmp |= 0xF0000000;
+ Memory.WriteU32(this.ioReg, BG3Y_L, tmp);
+
+ this.bgy[1] = (int)tmp;
+ }
+ break;
+
+ case DMA0CNT_H:
+ case DMA0CNT_H + 1:
+ this.ioReg[address] = value;
+ this.WriteDmaControl(0);
+ break;
+
+ case DMA1CNT_H:
+ case DMA1CNT_H + 1:
+ this.ioReg[address] = value;
+ this.WriteDmaControl(1);
+ break;
+
+ case DMA2CNT_H:
+ case DMA2CNT_H + 1:
+ this.ioReg[address] = value;
+ this.WriteDmaControl(2);
+ break;
+
+ case DMA3CNT_H:
+ case DMA3CNT_H + 1:
+ this.ioReg[address] = value;
+ this.WriteDmaControl(3);
+ break;
+
+ case TM0CNT:
+ case TM0CNT + 1:
+ {
+ ushort oldCnt = Memory.ReadU16(this.ioReg, TM0CNT);
+ this.ioReg[address] = value;
+ this.WriteTimerControl(0, oldCnt);
+ }
+ break;
+
+ case TM1CNT:
+ case TM1CNT + 1:
+ {
+ ushort oldCnt = Memory.ReadU16(this.ioReg, TM1CNT);
+ this.ioReg[address] = value;
+ this.WriteTimerControl(1, oldCnt);
+ }
+ break;
+
+ case TM2CNT:
+ case TM2CNT + 1:
+ {
+ ushort oldCnt = Memory.ReadU16(this.ioReg, TM2CNT);
+ this.ioReg[address] = value;
+ this.WriteTimerControl(2, oldCnt);
+ }
+ break;
+
+ case TM3CNT:
+ case TM3CNT + 1:
+ {
+ ushort oldCnt = Memory.ReadU16(this.ioReg, TM3CNT);
+ this.ioReg[address] = value;
+ this.WriteTimerControl(3, oldCnt);
+ }
+ break;
+
+ case FIFO_A_L:
+ case FIFO_A_L+1:
+ case FIFO_A_H:
+ case FIFO_A_H+1:
+ this.ioReg[address] = value;
+ this.soundManager.IncrementFifoA();
+ break;
+
+ case FIFO_B_L:
+ case FIFO_B_L + 1:
+ case FIFO_B_H:
+ case FIFO_B_H + 1:
+ this.ioReg[address] = value;
+ this.soundManager.IncrementFifoB();
+ break;
+
+ case IF:
+ case IF + 1:
+ this.ioReg[address] &= (byte)~value;
+ break;
+
+ case HALTCNT + 1:
+ this.ioReg[address] = value;
+ this.processor.Halt();
+ break;
+
+ default:
+ this.ioReg[address] = value;
+ break;
+ }
+ }
+
+ private void WriteIO16(uint address, ushort value)
+ {
+ this.waitCycles++;
+ address &= 0xFFFFFF;
+ if (address >= Memory.ioRegMask) return;
+
+ switch (address)
+ {
+ case BG2X_L:
+ case BG2X_L + 2:
+ {
+ Memory.WriteU16(this.ioReg, address, value);
+ uint tmp = Memory.ReadU32(this.ioReg, BG2X_L);
+ if ((tmp & (1 << 27)) != 0) tmp |= 0xF0000000;
+ Memory.WriteU32(this.ioReg, BG2X_L, tmp);
+
+ this.bgx[0] = (int)tmp;
+ }
+ break;
+
+ case BG3X_L:
+ case BG3X_L + 2:
+ {
+ Memory.WriteU16(this.ioReg, address, value);
+ uint tmp = Memory.ReadU32(this.ioReg, BG3X_L);
+ if ((tmp & (1 << 27)) != 0) tmp |= 0xF0000000;
+ Memory.WriteU32(this.ioReg, BG3X_L, tmp);
+
+ this.bgx[1] = (int)tmp;
+ }
+ break;
+
+ case BG2Y_L:
+ case BG2Y_L + 2:
+ {
+ Memory.WriteU16(this.ioReg, address, value);
+ uint tmp = Memory.ReadU32(this.ioReg, BG2Y_L);
+ if ((tmp & (1 << 27)) != 0) tmp |= 0xF0000000;
+ Memory.WriteU32(this.ioReg, BG2Y_L, tmp);
+
+ this.bgy[0] = (int)tmp;
+ }
+ break;
+
+ case BG3Y_L:
+ case BG3Y_L + 2:
+ {
+ Memory.WriteU16(this.ioReg, address, value);
+ uint tmp = Memory.ReadU32(this.ioReg, BG3Y_L);
+ if ((tmp & (1 << 27)) != 0) tmp |= 0xF0000000;
+ Memory.WriteU32(this.ioReg, BG3Y_L, tmp);
+
+ this.bgy[1] = (int)tmp;
+ }
+ break;
+
+ case DMA0CNT_H:
+ Memory.WriteU16(this.ioReg, address, value);
+ this.WriteDmaControl(0);
+ break;
+
+ case DMA1CNT_H:
+ Memory.WriteU16(this.ioReg, address, value);
+ this.WriteDmaControl(1);
+ break;
+
+ case DMA2CNT_H:
+ Memory.WriteU16(this.ioReg, address, value);
+ this.WriteDmaControl(2);
+ break;
+
+ case DMA3CNT_H:
+ Memory.WriteU16(this.ioReg, address, value);
+ this.WriteDmaControl(3);
+ break;
+
+ case TM0CNT:
+ {
+ ushort oldCnt = Memory.ReadU16(this.ioReg, TM0CNT);
+ Memory.WriteU16(this.ioReg, address, value);
+ this.WriteTimerControl(0, oldCnt);
+ }
+ break;
+
+ case TM1CNT:
+ {
+ ushort oldCnt = Memory.ReadU16(this.ioReg, TM1CNT);
+ Memory.WriteU16(this.ioReg, address, value);
+ this.WriteTimerControl(1, oldCnt);
+ }
+ break;
+
+ case TM2CNT:
+ {
+ ushort oldCnt = Memory.ReadU16(this.ioReg, TM2CNT);
+ Memory.WriteU16(this.ioReg, address, value);
+ this.WriteTimerControl(2, oldCnt);
+ }
+ break;
+
+ case TM3CNT:
+ {
+ ushort oldCnt = Memory.ReadU16(this.ioReg, TM3CNT);
+ Memory.WriteU16(this.ioReg, address, value);
+ this.WriteTimerControl(3, oldCnt);
+ }
+ break;
+
+ case FIFO_A_L:
+ case FIFO_A_H:
+ Memory.WriteU16(this.ioReg, address, value);
+ this.soundManager.IncrementFifoA();
+ break;
+
+ case FIFO_B_L:
+ case FIFO_B_H:
+ Memory.WriteU16(this.ioReg, address, value);
+ this.soundManager.IncrementFifoB();
+ break;
+
+ case SOUNDCNT_H:
+ Memory.WriteU16(this.ioReg, address, value);
+ if ((value & (1 << 11)) != 0)
+ {
+ this.soundManager.ResetFifoA();
+ }
+ if ((value & (1 << 15)) != 0)
+ {
+ this.soundManager.ResetFifoB();
+ }
+ break;
+
+ case IF:
+ {
+ ushort tmp = Memory.ReadU16(this.ioReg, address);
+ Memory.WriteU16(this.ioReg, address, (ushort)(tmp & (~value)));
+ }
+ break;
+
+ case HALTCNT:
+ Memory.WriteU16(this.ioReg, address, value);
+ this.processor.Halt();
+ break;
+
+ default:
+ Memory.WriteU16(this.ioReg, address, value);
+ break;
+ }
+ }
+
+ private void WriteIO32(uint address, uint value)
+ {
+ this.waitCycles++;
+ address &= 0xFFFFFF;
+ if (address >= Memory.ioRegMask) return;
+
+ switch (address)
+ {
+ case BG2X_L:
+ {
+ Memory.WriteU32(this.ioReg, address, value);
+ uint tmp = Memory.ReadU32(this.ioReg, BG2X_L);
+ if ((tmp & (1 << 27)) != 0) tmp |= 0xF0000000;
+ Memory.WriteU32(this.ioReg, BG2X_L, tmp);
+
+ this.bgx[0] = (int)tmp;
+ }
+ break;
+
+ case BG3X_L:
+ {
+ Memory.WriteU32(this.ioReg, address, value);
+ uint tmp = Memory.ReadU32(this.ioReg, BG3X_L);
+ if ((tmp & (1 << 27)) != 0) tmp |= 0xF0000000;
+ Memory.WriteU32(this.ioReg, BG3X_L, tmp);
+
+ this.bgx[1] = (int)tmp;
+ }
+ break;
+
+ case BG2Y_L:
+ {
+ Memory.WriteU32(this.ioReg, address, value);
+ uint tmp = Memory.ReadU32(this.ioReg, BG2Y_L);
+ if ((tmp & (1 << 27)) != 0) tmp |= 0xF0000000;
+ Memory.WriteU32(this.ioReg, BG2Y_L, tmp);
+
+ this.bgy[0] = (int)tmp;
+ }
+ break;
+
+ case BG3Y_L:
+ {
+ Memory.WriteU32(this.ioReg, address, value);
+ uint tmp = Memory.ReadU32(this.ioReg, BG3Y_L);
+ if ((tmp & (1 << 27)) != 0) tmp |= 0xF0000000;
+ Memory.WriteU32(this.ioReg, BG3Y_L, tmp);
+
+ this.bgy[1] = (int)tmp;
+ }
+ break;
+
+ case DMA0CNT_L:
+ Memory.WriteU32(this.ioReg, address, value);
+ this.WriteDmaControl(0);
+ break;
+
+ case DMA1CNT_L:
+ Memory.WriteU32(this.ioReg, address, value);
+ this.WriteDmaControl(1);
+ break;
+
+ case DMA2CNT_L:
+ Memory.WriteU32(this.ioReg, address, value);
+ this.WriteDmaControl(2);
+ break;
+
+ case DMA3CNT_L:
+ Memory.WriteU32(this.ioReg, address, value);
+ this.WriteDmaControl(3);
+ break;
+
+ case TM0D:
+ {
+ ushort oldCnt = Memory.ReadU16(this.ioReg, TM0CNT);
+ Memory.WriteU32(this.ioReg, address, value);
+ this.WriteTimerControl(0, oldCnt);
+ }
+ break;
+
+ case TM1D:
+ {
+ ushort oldCnt = Memory.ReadU16(this.ioReg, TM1CNT);
+ Memory.WriteU32(this.ioReg, address, value);
+ this.WriteTimerControl(1, oldCnt);
+ }
+ break;
+
+ case TM2D:
+ {
+ ushort oldCnt = Memory.ReadU16(this.ioReg, TM2CNT);
+ Memory.WriteU32(this.ioReg, address, value);
+ this.WriteTimerControl(2, oldCnt);
+ }
+ break;
+
+ case TM3D:
+ {
+ ushort oldCnt = Memory.ReadU16(this.ioReg, TM3CNT);
+ Memory.WriteU32(this.ioReg, address, value);
+ this.WriteTimerControl(3, oldCnt);
+ }
+ break;
+
+ case FIFO_A_L:
+ Memory.WriteU32(this.ioReg, address, value);
+ this.soundManager.IncrementFifoA();
+ break;
+
+ case FIFO_B_L:
+ Memory.WriteU32(this.ioReg, address, value);
+ this.soundManager.IncrementFifoB();
+ break;
+
+ case SOUNDCNT_L:
+ Memory.WriteU32(this.ioReg, address, value);
+ if (((value >> 16) & (1 << 11)) != 0)
+ {
+ this.soundManager.ResetFifoA();
+ }
+ if (((value >> 16) & (1 << 15)) != 0)
+ {
+ this.soundManager.ResetFifoB();
+ }
+ break;
+
+ case IE:
+ {
+ uint tmp = Memory.ReadU32(this.ioReg, address);
+ Memory.WriteU32(this.ioReg, address, (uint)((value & 0xFFFF) | (tmp & (~(value & 0xFFFF0000)))));
+ }
+ break;
+
+ case HALTCNT:
+ Memory.WriteU32(this.ioReg, address, value);
+ this.processor.Halt();
+ break;
+
+ default:
+ Memory.WriteU32(this.ioReg, address, value);
+ break;
+ }
+ }
+
+ private void WritePalRam8(uint address, byte value)
+ {
+ this.waitCycles++;
+ address &= Memory.palRamMask & ~1U;
+ this.palRam[address] = value;
+ this.palRam[address + 1] = value;
+ }
+
+ private void WritePalRam16(uint address, ushort value)
+ {
+ this.waitCycles++;
+ Memory.WriteU16(this.palRam, address & Memory.palRamMask, value);
+ }
+
+ private void WritePalRam32(uint address, uint value)
+ {
+ this.waitCycles += 2;
+ Memory.WriteU32(this.palRam, address & Memory.palRamMask, value);
+ }
+
+ private void WriteVRam8(uint address, byte value)
+ {
+ this.waitCycles++;
+ address &= Memory.vRamMask & ~1U;
+ if (address > 0x17FFF) address = 0x10000 + ((address - 0x17FFF) & 0x7FFF);
+ this.vRam[address] = value;
+ this.vRam[address + 1] = value;
+ }
+
+ private void WriteVRam16(uint address, ushort value)
+ {
+ this.waitCycles++;
+ address &= Memory.vRamMask;
+ if (address > 0x17FFF) address = 0x10000 + ((address - 0x17FFF) & 0x7FFF);
+ Memory.WriteU16(this.vRam, address, value);
+ }
+
+ private void WriteVRam32(uint address, uint value)
+ {
+ this.waitCycles += 2;
+ address &= Memory.vRamMask;
+ if (address > 0x17FFF) address = 0x10000 + ((address - 0x17FFF) & 0x7FFF);
+ Memory.WriteU32(this.vRam, address, value);
+ }
+
+ private void WriteOamRam8(uint address, byte value)
+ {
+ this.waitCycles++;
+ address &= Memory.oamRamMask & ~1U;
+
+ this.oamRam[address] = value;
+ this.oamRam[address + 1] = value;
+ }
+
+ private void WriteOamRam16(uint address, ushort value)
+ {
+ this.waitCycles++;
+ Memory.WriteU16(this.oamRam, address & Memory.oamRamMask, value);
+ }
+
+ private void WriteOamRam32(uint address, uint value)
+ {
+ this.waitCycles++;
+ Memory.WriteU32(this.oamRam, address & Memory.oamRamMask, value);
+ }
+
+ private void WriteSRam8(uint address, byte value)
+ {
+ this.sRam[address & Memory.sRamMask] = value;
+ }
+
+ private void WriteSRam16(uint address, ushort value)
+ {
+ // TODO
+ }
+
+ private void WriteSRam32(uint address, uint value)
+ {
+ // TODO
+ }
+
+ private enum EepromModes
+ {
+ Idle,
+ ReadData
+ }
+
+ private EepromModes eepromMode = EepromModes.Idle;
+ private byte[] eeprom = new byte[0xffff];
+ private byte[] eepromStore = new byte[0xff];
+ private int curEepromByte;
+ private int eepromReadAddress = -1;
+
+ private void WriteEeprom8(uint address, byte value)
+ {
+ // EEPROM writes must be done by DMA 3
+ if ((this.dmaRegs[3, 3] & (1 << 15)) == 0) return;
+ // 0 length eeprom writes are bad
+ if (this.dmaRegs[3, 2] == 0) return;
+
+ if (this.eepromMode != EepromModes.ReadData)
+ {
+ this.curEepromByte = 0;
+ this.eepromMode = EepromModes.ReadData;
+ this.eepromReadAddress = -1;
+
+ for (int i = 0; i < this.eepromStore.Length; i++) this.eepromStore[i] = 0;
+ }
+
+ this.eepromStore[this.curEepromByte >> 3] |= (byte)(value << (7 - (this.curEepromByte & 0x7)));
+ this.curEepromByte++;
+
+ if (this.curEepromByte == this.dmaRegs[3, 2])
+ {
+ if ((this.eepromStore[0] & 0x80) == 0) return;
+
+ if ((this.eepromStore[0] & 0x40) != 0)
+ {
+ // Read request
+ if (this.curEepromByte == 9)
+ {
+ this.eepromReadAddress = this.eepromStore[0] & 0x3F;
+ }
+ else
+ {
+ this.eepromReadAddress = ((this.eepromStore[0] & 0x3F) << 8) | this.eepromStore[1];
+ }
+
+ this.curEepromByte = 0;
+ }
+ else
+ {
+ // Write request
+ int eepromAddress, offset;
+ if (this.curEepromByte == 64 + 9)
+ {
+ eepromAddress = (int)(this.eepromStore[0] & 0x3F);
+ offset = 1;
+ }
+ else
+ {
+ eepromAddress = ((this.eepromStore[0] & 0x3F) << 8) | this.eepromStore[1];
+ offset = 2;
+ }
+
+ for (int i = 0; i < 8; i++)
+ {
+ this.eeprom[eepromAddress * 8 + i] = this.eepromStore[i + offset];
+ }
+
+ this.eepromMode = EepromModes.Idle;
+ }
+ }
+ }
+
+ private void WriteEeprom16(uint address, ushort value)
+ {
+ this.WriteEeprom8(address, (byte)(value & 0xff));
+ }
+
+ private void WriteEeprom32(uint address, uint value)
+ {
+ this.WriteEeprom8(address, (byte)(value & 0xff));
+ }
+
+ private byte ReadEeprom8(uint address)
+ {
+ if (this.eepromReadAddress == -1) return 1;
+
+ byte retval = 0;
+
+ if (this.curEepromByte >= 4)
+ {
+ retval = (byte)((this.eeprom[this.eepromReadAddress * 8 + ((this.curEepromByte - 4) / 8)] >> (7 - ((this.curEepromByte - 4) & 7))) & 1);
+ }
+
+ this.curEepromByte++;
+
+ if (this.curEepromByte == this.dmaRegs[3, 2])
+ {
+ this.eepromReadAddress = -1;
+ this.eepromMode = EepromModes.Idle;
+ }
+
+ return retval;
+ }
+
+ private ushort ReadEeprom16(uint address)
+ {
+ return (ushort)this.ReadEeprom8(address);
+ }
+
+ private uint ReadEeprom32(uint address)
+ {
+ return (uint)this.ReadEeprom8(address);
+ }
+ #endregion
+
+ #region Shader Renderer Vram Writes
+ private List vramUpdated = new List();
+ private List palUpdated = new List();
+ public const int VramBlockSize = 64;
+ public const int PalBlockSize = 32;
+ private bool[] vramHit = new bool[(Memory.vRamMask + 1) / VramBlockSize];
+ private bool[] palHit = new bool[(Memory.palRamMask + 1) / PalBlockSize];
+
+ public List VramUpdated
+ {
+ get
+ {
+ List old = this.vramUpdated;
+ for (int i = 0; i < old.Count; i++)
+ {
+ vramHit[old[i]] = false;
+ }
+ this.vramUpdated = new List();
+ return old;
+ }
+ }
+
+
+ public List PalUpdated
+ {
+ get
+ {
+ List old = this.palUpdated;
+ for (int i = 0; i < old.Count; i++)
+ {
+ palHit[old[i]] = false;
+ }
+ this.palUpdated = new List();
+ return old;
+ }
+ }
+
+ private void UpdatePal(uint address)
+ {
+ uint index = address / PalBlockSize;
+ if (!palHit[index])
+ {
+ palHit[index] = true;
+ this.palUpdated.Add(index);
+ }
+ }
+
+ private void UpdateVram(uint address)
+ {
+ uint index = address / VramBlockSize;
+ if (!vramHit[index])
+ {
+ vramHit[index] = true;
+ this.vramUpdated.Add(index);
+ }
+ }
+
+ private void ShaderWritePalRam8(uint address, byte value)
+ {
+ this.waitCycles++;
+ address &= Memory.palRamMask & ~1U;
+ this.palRam[address] = value;
+ this.palRam[address + 1] = value;
+
+ this.UpdatePal(address);
+ }
+
+ private void ShaderWritePalRam16(uint address, ushort value)
+ {
+ this.waitCycles++;
+ Memory.WriteU16(this.palRam, address & Memory.palRamMask, value);
+
+ this.UpdatePal(address & Memory.palRamMask);
+ }
+
+ private void ShaderWritePalRam32(uint address, uint value)
+ {
+ this.waitCycles += 2;
+ Memory.WriteU32(this.palRam, address & Memory.palRamMask, value);
+
+ this.UpdatePal(address & Memory.palRamMask);
+ }
+
+ private void ShaderWriteVRam8(uint address, byte value)
+ {
+ this.waitCycles++;
+ address &= Memory.vRamMask & ~1U;
+ if (address > 0x17FFF) address = 0x10000 + ((address - 0x17FFF) & 0x7FFF);
+ this.vRam[address] = value;
+ this.vRam[address + 1] = value;
+
+ this.UpdateVram(address);
+ }
+
+ private void ShaderWriteVRam16(uint address, ushort value)
+ {
+ this.waitCycles++;
+ address &= Memory.vRamMask;
+ if (address > 0x17FFF) address = 0x10000 + ((address - 0x17FFF) & 0x7FFF);
+ Memory.WriteU16(this.vRam, address, value);
+
+ this.UpdateVram(address);
+ }
+
+ private void ShaderWriteVRam32(uint address, uint value)
+ {
+ this.waitCycles += 2;
+ address &= Memory.vRamMask;
+ if (address > 0x17FFF) address = 0x10000 + ((address - 0x17FFF) & 0x7FFF);
+ Memory.WriteU32(this.vRam, address, value);
+
+ this.UpdateVram(address);
+ }
+
+ public void EnableVramUpdating()
+ {
+ this.WriteU8Funcs[0x5] = this.ShaderWritePalRam8;
+ this.WriteU16Funcs[0x5] = this.ShaderWritePalRam16;
+ this.WriteU32Funcs[0x5] = this.ShaderWritePalRam32;
+ this.WriteU8Funcs[0x6] = this.ShaderWriteVRam8;
+ this.WriteU16Funcs[0x6] = this.ShaderWriteVRam16;
+ this.WriteU32Funcs[0x6] = this.ShaderWriteVRam32;
+
+ for (uint i = 0; i < (Memory.vRamMask + 1) / Memory.VramBlockSize; i++)
+ {
+ this.vramUpdated.Add(i);
+ }
+
+ for (uint i = 0; i < (Memory.palRamMask + 1) / Memory.PalBlockSize; i++)
+ {
+ this.palUpdated.Add(i);
+ }
+ }
+ #endregion
+
+ public byte ReadU8(uint address)
+ {
+ uint bank = (address >> 24) & 0xf;
+ return this.ReadU8Funcs[bank](address);
+ }
+
+ public ushort ReadU16(uint address)
+ {
+ address &= ~1U;
+ uint bank = (address >> 24) & 0xf;
+ return this.ReadU16Funcs[bank](address);
+ }
+
+ public uint ReadU32(uint address)
+ {
+ int shiftAmt = (int)((address & 3U) << 3);
+ address &= ~3U;
+ uint bank = (address >> 24) & 0xf;
+ uint res = this.ReadU32Funcs[bank](address);
+ return (res >> shiftAmt) | (res << (32 - shiftAmt));
+ }
+
+ public uint ReadU32Aligned(uint address)
+ {
+ uint bank = (address >> 24) & 0xf;
+ return this.ReadU32Funcs[bank](address);
+ }
+
+ public ushort ReadU16Debug(uint address)
+ {
+ address &= ~1U;
+ uint bank = (address >> 24) & 0xf;
+ int oldWaitCycles = this.waitCycles;
+ ushort res = this.ReadU16Funcs[bank](address);
+ this.waitCycles = oldWaitCycles;
+ return res;
+ }
+
+ public uint ReadU32Debug(uint address)
+ {
+ int shiftAmt = (int)((address & 3U) << 3);
+ address &= ~3U;
+ uint bank = (address >> 24) & 0xf;
+ int oldWaitCycles = this.waitCycles;
+ uint res = this.ReadU32Funcs[bank](address);
+ this.waitCycles = oldWaitCycles;
+ return (res >> shiftAmt) | (res << (32 - shiftAmt));
+ }
+
+ public void WriteU8(uint address, byte value)
+ {
+ uint bank = (address >> 24) & 0xf;
+ this.WriteU8Funcs[bank](address, value);
+ }
+
+ public void WriteU16(uint address, ushort value)
+ {
+ address &= ~1U;
+ uint bank = (address >> 24) & 0xf;
+ this.WriteU16Funcs[bank](address, value);
+ }
+
+ public void WriteU32(uint address, uint value)
+ {
+ address &= ~3U;
+ uint bank = (address >> 24) & 0xf;
+ this.WriteU32Funcs[bank](address, value);
+ }
+
+ public void WriteU8Debug(uint address, byte value)
+ {
+ uint bank = (address >> 24) & 0xf;
+ int oldWaitCycles = this.waitCycles;
+ this.WriteU8Funcs[bank](address, value);
+ this.waitCycles = oldWaitCycles;
+ }
+
+ public void WriteU16Debug(uint address, ushort value)
+ {
+ address &= ~1U;
+ uint bank = (address >> 24) & 0xf;
+ int oldWaitCycles = this.waitCycles;
+ this.WriteU16Funcs[bank](address, value);
+ this.waitCycles = oldWaitCycles;
+ }
+
+ public void WriteU32Debug(uint address, uint value)
+ {
+ address &= ~3U;
+ uint bank = (address >> 24) & 0xf;
+ int oldWaitCycles = this.waitCycles;
+ this.WriteU32Funcs[bank](address, value);
+ this.waitCycles = oldWaitCycles;
+ }
+
+ public void LoadBios(byte[] biosRom)
+ {
+ Array.Copy(biosRom, this.biosRam, this.biosRam.Length);
+ }
+
+ public void LoadCartridge(byte[] cartRom)
+ {
+ this.ResetRomBank1();
+ this.ResetRomBank2();
+
+ // Set up the appropriate cart size
+ int cartSize = 1;
+ while (cartSize < cartRom.Length)
+ {
+ cartSize <<= 1;
+ }
+
+ if (cartSize != cartRom.Length)
+ {
+ throw new Exception("Unable to load non power of two carts");
+ }
+
+ // Split across bank 1 and 2 if cart is too big
+ if (cartSize > 1 << 24)
+ {
+ this.romBank1 = cartRom;
+ this.romBank1Mask = (1 << 24) - 1;
+
+ cartRom.CopyTo(this.romBank2, 1 << 24);
+ this.romBank2Mask = (1 << 24) - 1;
+ }
+ else
+ {
+ this.romBank1 = cartRom;
+ this.romBank1Mask = (uint)(cartSize - 1);
+ }
+
+ if (this.romBank1Mask != 0)
+ {
+ // TODO: Writes (i.e. eeprom, and other stuff)
+ this.ReadU8Funcs[0x8] = this.ReadRom1_8;
+ this.ReadU8Funcs[0xA] = this.ReadRom1_8;
+ this.ReadU8Funcs[0xC] = this.ReadRom1_8;
+ this.ReadU16Funcs[0x8] = this.ReadRom1_16;
+ this.ReadU16Funcs[0xA] = this.ReadRom1_16;
+ this.ReadU16Funcs[0xC] = this.ReadRom1_16;
+ this.ReadU32Funcs[0x8] = this.ReadRom1_32;
+ this.ReadU32Funcs[0xA] = this.ReadRom1_32;
+ this.ReadU32Funcs[0xC] = this.ReadRom1_32;
+ }
+
+ if (this.romBank2Mask != 0)
+ {
+ this.ReadU8Funcs[0x9] = this.ReadRom2_8;
+ this.ReadU8Funcs[0xB] = this.ReadRom2_8;
+ this.ReadU8Funcs[0xD] = this.ReadRom2_8;
+ this.ReadU16Funcs[0x9] = this.ReadRom2_16;
+ this.ReadU16Funcs[0xB] = this.ReadRom2_16;
+ this.ReadU16Funcs[0xD] = this.ReadRom2_16;
+ this.ReadU32Funcs[0x9] = this.ReadRom2_32;
+ this.ReadU32Funcs[0xB] = this.ReadRom2_32;
+ this.ReadU32Funcs[0xD] = this.ReadRom2_32;
+ }
+ }
+
+ private void ResetRomBank1()
+ {
+ this.romBank1 = null;
+ this.romBank1Mask = 0;
+
+ for (int i = 0; i < this.bankSTimes.Length; i++)
+ {
+ this.bankSTimes[i] = 2;
+ }
+
+ this.ReadU8Funcs[0x8] = this.ReadNop8;
+ this.ReadU8Funcs[0xA] = this.ReadNop8;
+ this.ReadU8Funcs[0xC] = this.ReadNop8;
+ this.ReadU16Funcs[0x8] = this.ReadNop16;
+ this.ReadU16Funcs[0xA] = this.ReadNop16;
+ this.ReadU16Funcs[0xC] = this.ReadNop16;
+ this.ReadU32Funcs[0x8] = this.ReadNop32;
+ this.ReadU32Funcs[0xA] = this.ReadNop32;
+ this.ReadU32Funcs[0xC] = this.ReadNop32;
+ }
+
+ private void ResetRomBank2()
+ {
+ this.romBank2 = null;
+ this.romBank2Mask = 0;
+
+ this.ReadU8Funcs[0x9] = this.ReadEeprom8;
+ this.ReadU8Funcs[0xB] = this.ReadEeprom8;
+ this.ReadU8Funcs[0xD] = this.ReadEeprom8;
+ this.ReadU16Funcs[0x9] = this.ReadEeprom16;
+ this.ReadU16Funcs[0xB] = this.ReadEeprom16;
+ this.ReadU16Funcs[0xD] = this.ReadEeprom16;
+ this.ReadU32Funcs[0x9] = this.ReadEeprom32;
+ this.ReadU32Funcs[0xB] = this.ReadEeprom32;
+ this.ReadU32Funcs[0xD] = this.ReadEeprom32;
+
+ this.WriteU8Funcs[0x9] = this.WriteEeprom8;
+ this.WriteU8Funcs[0xB] = this.WriteEeprom8;
+ this.WriteU8Funcs[0xD] = this.WriteEeprom8;
+ this.WriteU16Funcs[0x9] = this.WriteEeprom16;
+ this.WriteU16Funcs[0xB] = this.WriteEeprom16;
+ this.WriteU16Funcs[0xD] = this.WriteEeprom16;
+ this.WriteU32Funcs[0x9] = this.WriteEeprom32;
+ this.WriteU32Funcs[0xB] = this.WriteEeprom32;
+ this.WriteU32Funcs[0xD] = this.WriteEeprom32;
+ }
+ }
+}
diff --git a/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/Renderer.cs b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/Renderer.cs
new file mode 100644
index 0000000000..d323240619
--- /dev/null
+++ b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/Renderer.cs
@@ -0,0 +1,952 @@
+namespace GarboDev
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Text;
+
+ public partial class Renderer : IRenderer
+ {
+ private Memory memory;
+ private uint[] scanline = new uint[240];
+ private byte[] blend = new byte[240];
+ private byte[] windowCover = new byte[240];
+ private uint[] back = new uint[240 * 160];
+ //private uint[] front = new uint[240 * 160];
+ private const uint pitch = 240;
+
+ // Convenience variable as I use it everywhere, set once in RenderLine
+ private ushort dispCnt;
+
+ // Window helper variables
+ private byte win0x1, win0x2, win0y1, win0y2;
+ private byte win1x1, win1x2, win1y1, win1y2;
+ private byte win0Enabled, win1Enabled, winObjEnabled, winOutEnabled;
+ private bool winEnabled;
+
+ private byte blendSource, blendTarget;
+ private byte blendA, blendB, blendY;
+ private int blendType;
+
+ private int curLine = 0;
+
+ private static uint[] colorLUT;
+
+ static Renderer()
+ {
+ colorLUT = new uint[0x10000];
+ // Pre-calculate the color LUT
+ for (uint i = 0; i <= 0xFFFF; i++)
+ {
+ uint r = (i & 0x1FU);
+ uint g = (i & 0x3E0U) >> 5;
+ uint b = (i & 0x7C00U) >> 10;
+ r = (r << 3) | (r >> 2);
+ g = (g << 3) | (g >> 2);
+ b = (b << 3) | (b >> 2);
+ colorLUT[i] = (r << 16) | (g << 8) | b;
+ }
+ }
+
+ public Memory Memory
+ {
+ set { this.memory = value; }
+ }
+
+ public void Initialize(object data)
+ {
+ }
+
+ public void Reset()
+ {
+ }
+
+ public uint[] ShowFrame()
+ {
+ //Array.Copy(this.back, this.front, this.front.Length);
+
+ //return this.front;
+ return this.back;
+ }
+
+ public void RenderLine(int line)
+ {
+ this.curLine = line;
+
+ // Render the line
+ this.dispCnt = Memory.ReadU16(this.memory.IORam, Memory.DISPCNT);
+
+ if ((this.dispCnt & (1 << 7)) != 0)
+ {
+ uint bgColor = Renderer.GbaTo32((ushort)0x7FFF);
+ for (int i = 0; i < 240; i++) this.scanline[i] = bgColor;
+ }
+ else
+ {
+ this.winEnabled = false;
+
+ if ((this.dispCnt & (1 << 13)) != 0)
+ {
+ // Calculate window 0 information
+ ushort winy = Memory.ReadU16(this.memory.IORam, Memory.WIN0V);
+ this.win0y1 = (byte)(winy >> 8);
+ this.win0y2 = (byte)(winy & 0xff);
+ ushort winx = Memory.ReadU16(this.memory.IORam, Memory.WIN0H);
+ this.win0x1 = (byte)(winx >> 8);
+ this.win0x2 = (byte)(winx & 0xff);
+
+ if (this.win0x2 > 240 || this.win0x1 > this.win0x2)
+ {
+ this.win0x2 = 240;
+ }
+
+ if (this.win0y2 > 160 || this.win0y1 > this.win0y2)
+ {
+ this.win0y2 = 160;
+ }
+
+ this.win0Enabled = this.memory.IORam[Memory.WININ];
+ this.winEnabled = true;
+ }
+
+ if ((this.dispCnt & (1 << 14)) != 0)
+ {
+ // Calculate window 1 information
+ ushort winy = Memory.ReadU16(this.memory.IORam, Memory.WIN1V);
+ this.win1y1 = (byte)(winy >> 8);
+ this.win1y2 = (byte)(winy & 0xff);
+ ushort winx = Memory.ReadU16(this.memory.IORam, Memory.WIN1H);
+ this.win1x1 = (byte)(winx >> 8);
+ this.win1x2 = (byte)(winx & 0xff);
+
+ if (this.win1x2 > 240 || this.win1x1 > this.win1x2)
+ {
+ this.win1x2 = 240;
+ }
+
+ if (this.win1y2 > 160 || this.win1y1 > this.win1y2)
+ {
+ this.win1y2 = 160;
+ }
+
+ this.win1Enabled = this.memory.IORam[Memory.WININ + 1];
+ this.winEnabled = true;
+ }
+
+ if ((this.dispCnt & (1 << 15)) != 0 && (this.dispCnt & (1 << 12)) != 0)
+ {
+ // Object windows are enabled
+ this.winObjEnabled = this.memory.IORam[Memory.WINOUT + 1];
+ this.winEnabled = true;
+ }
+
+ if (this.winEnabled)
+ {
+ this.winOutEnabled = this.memory.IORam[Memory.WINOUT];
+ }
+
+ // Calculate blending information
+ ushort bldcnt = Memory.ReadU16(this.memory.IORam, Memory.BLDCNT);
+ this.blendType = (bldcnt >> 6) & 0x3;
+ this.blendSource = (byte)(bldcnt & 0x3F);
+ this.blendTarget = (byte)((bldcnt >> 8) & 0x3F);
+
+ ushort bldalpha = Memory.ReadU16(this.memory.IORam, Memory.BLDALPHA);
+ this.blendA = (byte)(bldalpha & 0x1F);
+ if (this.blendA > 0x10) this.blendA = 0x10;
+ this.blendB = (byte)((bldalpha >> 8) & 0x1F);
+ if (this.blendB > 0x10) this.blendB = 0x10;
+
+ this.blendY = (byte)(this.memory.IORam[Memory.BLDY] & 0x1F);
+ if (this.blendY > 0x10) this.blendY = 0x10;
+
+ switch (this.dispCnt & 0x7)
+ {
+ case 0: this.RenderMode0Line(); break;
+ case 1: this.RenderMode1Line(); break;
+ case 2: this.RenderMode2Line(); break;
+ case 3: this.RenderMode3Line(); break;
+ case 4: this.RenderMode4Line(); break;
+ case 5: this.RenderMode5Line(); break;
+ }
+ }
+
+ Array.Copy(this.scanline, 0, this.back, this.curLine * Renderer.pitch, Renderer.pitch);
+ }
+
+ private void DrawBackdrop()
+ {
+ byte[] palette = this.memory.PaletteRam;
+
+ // Initialize window coverage buffer if neccesary
+ if (this.winEnabled)
+ {
+ for (int i = 0; i < 240; i++)
+ {
+ this.windowCover[i] = this.winOutEnabled;
+ }
+
+ if ((this.dispCnt & (1 << 15)) != 0)
+ {
+ // Sprite window
+ this.DrawSpriteWindows();
+ }
+
+ if ((this.dispCnt & (1 << 14)) != 0)
+ {
+ // Window 1
+ if (this.curLine >= this.win1y1 && this.curLine < this.win1y2)
+ {
+ for (int i = this.win1x1; i < this.win1x2; i++)
+ {
+ this.windowCover[i] = this.win1Enabled;
+ }
+ }
+ }
+
+ if ((this.dispCnt & (1 << 13)) != 0)
+ {
+ // Window 0
+ if (this.curLine >= this.win0y1 && this.curLine < this.win0y2)
+ {
+ for (int i = this.win0x1; i < this.win0x2; i++)
+ {
+ this.windowCover[i] = this.win0Enabled;
+ }
+ }
+ }
+ }
+
+ // Draw backdrop first
+ uint bgColor = Renderer.GbaTo32((ushort)(palette[0] | (palette[1] << 8)));
+ uint modColor = bgColor;
+
+ if (this.blendType == 2 && (this.blendSource & (1 << 5)) != 0)
+ {
+ // Brightness increase
+ uint r = bgColor & 0xFF;
+ uint g = (bgColor >> 8) & 0xFF;
+ uint b = (bgColor >> 16) & 0xFF;
+ r = r + (((0xFF - r) * this.blendY) >> 4);
+ g = g + (((0xFF - g) * this.blendY) >> 4);
+ b = b + (((0xFF - b) * this.blendY) >> 4);
+ modColor = r | (g << 8) | (b << 16);
+ }
+ else if (this.blendType == 3 && (this.blendSource & (1 << 5)) != 0)
+ {
+ // Brightness decrease
+ uint r = bgColor & 0xFF;
+ uint g = (bgColor >> 8) & 0xFF;
+ uint b = (bgColor >> 16) & 0xFF;
+ r = r - ((r * this.blendY) >> 4);
+ g = g - ((g * this.blendY) >> 4);
+ b = b - ((b * this.blendY) >> 4);
+ modColor = r | (g << 8) | (b << 16);
+ }
+
+ if (this.winEnabled)
+ {
+ for (int i = 0; i < 240; i++)
+ {
+ if ((this.windowCover[i] & (1 << 5)) != 0)
+ {
+ this.scanline[i] = modColor;
+ }
+ else
+ {
+ this.scanline[i] = bgColor;
+ }
+ this.blend[i] = 1 << 5;
+ }
+ }
+ else
+ {
+ for (int i = 0; i < 240; i++)
+ {
+ this.scanline[i] = modColor;
+ this.blend[i] = 1 << 5;
+ }
+ }
+ }
+
+ private void RenderTextBg(int bg)
+ {
+ if (this.winEnabled)
+ {
+ switch (this.blendType)
+ {
+ case 0:
+ this.RenderTextBgWindow(bg);
+ break;
+ case 1:
+ if ((this.blendSource & (1 << bg)) != 0)
+ this.RenderTextBgWindowBlend(bg);
+ else
+ this.RenderTextBgWindow(bg);
+ break;
+ case 2:
+ if ((this.blendSource & (1 << bg)) != 0)
+ this.RenderTextBgWindowBrightInc(bg);
+ else
+ this.RenderTextBgWindow(bg);
+ break;
+ case 3:
+ if ((this.blendSource & (1 << bg)) != 0)
+ this.RenderTextBgWindowBrightDec(bg);
+ else
+ this.RenderTextBgWindow(bg);
+ break;
+ }
+ }
+ else
+ {
+ switch (this.blendType)
+ {
+ case 0:
+ this.RenderTextBgNormal(bg);
+ break;
+ case 1:
+ if ((this.blendSource & (1 << bg)) != 0)
+ this.RenderTextBgBlend(bg);
+ else
+ this.RenderTextBgNormal(bg);
+ break;
+ case 2:
+ if ((this.blendSource & (1 << bg)) != 0)
+ this.RenderTextBgBrightInc(bg);
+ else
+ this.RenderTextBgNormal(bg);
+ break;
+ case 3:
+ if ((this.blendSource & (1 << bg)) != 0)
+ this.RenderTextBgBrightDec(bg);
+ else
+ this.RenderTextBgNormal(bg);
+ break;
+ }
+ }
+ }
+
+ private void RenderRotScaleBg(int bg)
+ {
+ if (this.winEnabled)
+ {
+ switch (this.blendType)
+ {
+ case 0:
+ this.RenderRotScaleBgWindow(bg);
+ break;
+ case 1:
+ if ((this.blendSource & (1 << bg)) != 0)
+ this.RenderRotScaleBgWindowBlend(bg);
+ else
+ this.RenderRotScaleBgWindow(bg);
+ break;
+ case 2:
+ if ((this.blendSource & (1 << bg)) != 0)
+ this.RenderRotScaleBgWindowBrightInc(bg);
+ else
+ this.RenderRotScaleBgWindow(bg);
+ break;
+ case 3:
+ if ((this.blendSource & (1 << bg)) != 0)
+ this.RenderRotScaleBgWindowBrightDec(bg);
+ else
+ this.RenderRotScaleBgWindow(bg);
+ break;
+ }
+ }
+ else
+ {
+ switch (this.blendType)
+ {
+ case 0:
+ this.RenderRotScaleBgNormal(bg);
+ break;
+ case 1:
+ if ((this.blendSource & (1 << bg)) != 0)
+ this.RenderRotScaleBgBlend(bg);
+ else
+ this.RenderRotScaleBgNormal(bg);
+ break;
+ case 2:
+ if ((this.blendSource & (1 << bg)) != 0)
+ this.RenderRotScaleBgBrightInc(bg);
+ else
+ this.RenderRotScaleBgNormal(bg);
+ break;
+ case 3:
+ if ((this.blendSource & (1 << bg)) != 0)
+ this.RenderRotScaleBgBrightDec(bg);
+ else
+ this.RenderRotScaleBgNormal(bg);
+ break;
+ }
+ }
+ }
+
+ private void DrawSprites(int pri)
+ {
+ if (this.winEnabled)
+ {
+ switch (this.blendType)
+ {
+ case 0:
+ this.DrawSpritesWindow(pri);
+ break;
+ case 1:
+ if ((this.blendSource & (1 << 4)) != 0)
+ this.DrawSpritesWindowBlend(pri);
+ else
+ this.DrawSpritesWindow(pri);
+ break;
+ case 2:
+ if ((this.blendSource & (1 << 4)) != 0)
+ this.DrawSpritesWindowBrightInc(pri);
+ else
+ this.DrawSpritesWindow(pri);
+ break;
+ case 3:
+ if ((this.blendSource & (1 << 4)) != 0)
+ this.DrawSpritesWindowBrightDec(pri);
+ else
+ this.DrawSpritesWindow(pri);
+ break;
+ }
+ }
+ else
+ {
+ switch (this.blendType)
+ {
+ case 0:
+ this.DrawSpritesNormal(pri);
+ break;
+ case 1:
+ if ((this.blendSource & (1 << 4)) != 0)
+ this.DrawSpritesBlend(pri);
+ else
+ this.DrawSpritesNormal(pri);
+ break;
+ case 2:
+ if ((this.blendSource & (1 << 4)) != 0)
+ this.DrawSpritesBrightInc(pri);
+ else
+ this.DrawSpritesNormal(pri);
+ break;
+ case 3:
+ if ((this.blendSource & (1 << 4)) != 0)
+ this.DrawSpritesBrightDec(pri);
+ else
+ this.DrawSpritesNormal(pri);
+ break;
+ }
+ }
+ }
+
+ private void RenderMode0Line()
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ this.DrawBackdrop();
+
+ for (int pri = 3; pri >= 0; pri--)
+ {
+ for (int i = 3; i >= 0; i--)
+ {
+ if ((this.dispCnt & (1 << (8 + i))) != 0)
+ {
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)i);
+
+ if ((bgcnt & 0x3) == pri)
+ {
+ this.RenderTextBg(i);
+ }
+ }
+ }
+
+ this.DrawSprites(pri);
+ }
+ }
+
+ private void RenderMode1Line()
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ this.DrawBackdrop();
+
+ for (int pri = 3; pri >= 0; pri--)
+ {
+ if ((this.dispCnt & (1 << (8 + 2))) != 0)
+ {
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG2CNT);
+
+ if ((bgcnt & 0x3) == pri)
+ {
+ this.RenderRotScaleBg(2);
+ }
+ }
+
+ for (int i = 1; i >= 0; i--)
+ {
+ if ((this.dispCnt & (1 << (8 + i))) != 0)
+ {
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)i);
+
+ if ((bgcnt & 0x3) == pri)
+ {
+ this.RenderTextBg(i);
+ }
+ }
+ }
+
+ this.DrawSprites(pri);
+ }
+ }
+
+ private void RenderMode2Line()
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ this.DrawBackdrop();
+
+ for (int pri = 3; pri >= 0; pri--)
+ {
+ for (int i = 3; i >= 2; i--)
+ {
+ if ((this.dispCnt & (1 << (8 + i))) != 0)
+ {
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)i);
+
+ if ((bgcnt & 0x3) == pri)
+ {
+ this.RenderRotScaleBg(i);
+ }
+ }
+ }
+
+ this.DrawSprites(pri);
+ }
+ }
+
+ private void RenderMode3Line()
+ {
+ ushort bg2Cnt = Memory.ReadU16(this.memory.IORam, Memory.BG2CNT);
+
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ this.DrawBackdrop();
+
+ byte blendMaskType = (byte)(1 << 2);
+
+ int bgPri = bg2Cnt & 0x3;
+ for (int pri = 3; pri > bgPri; pri--)
+ {
+ this.DrawSprites(pri);
+ }
+
+ if ((this.dispCnt & (1 << 10)) != 0)
+ {
+ // Background enabled, render it
+ int x = this.memory.Bgx[0];
+ int y = this.memory.Bgy[0];
+
+ short dx = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PA);
+ short dy = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PC);
+
+ for (int i = 0; i < 240; i++)
+ {
+ int ax = ((int)x) >> 8;
+ int ay = ((int)y) >> 8;
+
+ if (ax >= 0 && ax < 240 && ay >= 0 && ay < 160)
+ {
+ int curIdx = ((ay * 240) + ax) * 2;
+ this.scanline[i] = Renderer.GbaTo32((ushort)(vram[curIdx] | (vram[curIdx + 1] << 8)));
+ this.blend[i] = blendMaskType;
+ }
+
+ x += dx;
+ y += dy;
+ }
+ }
+
+ for (int pri = bgPri; pri >= 0; pri--)
+ {
+ this.DrawSprites(pri);
+ }
+ }
+
+ private void RenderMode4Line()
+ {
+ ushort bg2Cnt = Memory.ReadU16(this.memory.IORam, Memory.BG2CNT);
+
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ this.DrawBackdrop();
+
+ byte blendMaskType = (byte)(1 << 2);
+
+ int bgPri = bg2Cnt & 0x3;
+ for (int pri = 3; pri > bgPri; pri--)
+ {
+ this.DrawSprites(pri);
+ }
+
+ if ((this.dispCnt & (1 << 10)) != 0)
+ {
+ // Background enabled, render it
+ int baseIdx = 0;
+ if ((this.dispCnt & (1 << 4)) == 1 << 4) baseIdx = 0xA000;
+
+ int x = this.memory.Bgx[0];
+ int y = this.memory.Bgy[0];
+
+ short dx = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PA);
+ short dy = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PC);
+
+ for (int i = 0; i < 240; i++)
+ {
+ int ax = ((int)x) >> 8;
+ int ay = ((int)y) >> 8;
+
+ if (ax >= 0 && ax < 240 && ay >= 0 && ay < 160)
+ {
+ int lookup = vram[baseIdx + (ay * 240) + ax];
+ if (lookup != 0)
+ {
+ this.scanline[i] = Renderer.GbaTo32((ushort)(palette[lookup * 2] | (palette[lookup * 2 + 1] << 8)));
+ this.blend[i] = blendMaskType;
+ }
+ }
+
+ x += dx;
+ y += dy;
+ }
+ }
+
+ for (int pri = bgPri; pri >= 0; pri--)
+ {
+ this.DrawSprites(pri);
+ }
+ }
+
+ private void RenderMode5Line()
+ {
+ ushort bg2Cnt = Memory.ReadU16(this.memory.IORam, Memory.BG2CNT);
+
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ this.DrawBackdrop();
+
+ byte blendMaskType = (byte)(1 << 2);
+
+ int bgPri = bg2Cnt & 0x3;
+ for (int pri = 3; pri > bgPri; pri--)
+ {
+ this.DrawSprites(pri);
+ }
+
+ if ((this.dispCnt & (1 << 10)) != 0)
+ {
+ // Background enabled, render it
+ int baseIdx = 0;
+ if ((this.dispCnt & (1 << 4)) == 1 << 4) baseIdx += 160 * 128 * 2;
+
+ int x = this.memory.Bgx[0];
+ int y = this.memory.Bgy[0];
+
+ short dx = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PA);
+ short dy = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PC);
+
+ for (int i = 0; i < 240; i++)
+ {
+ int ax = ((int)x) >> 8;
+ int ay = ((int)y) >> 8;
+
+ if (ax >= 0 && ax < 160 && ay >= 0 && ay < 128)
+ {
+ int curIdx = (int)(ay * 160 + ax) * 2;
+
+ this.scanline[i] = Renderer.GbaTo32((ushort)(vram[baseIdx + curIdx] | (vram[baseIdx + curIdx + 1] << 8)));
+ this.blend[i] = blendMaskType;
+ }
+
+ x += dx;
+ y += dy;
+ }
+ }
+
+ for (int pri = bgPri; pri >= 0; pri--)
+ {
+ this.DrawSprites(pri);
+ }
+ }
+
+ private void DrawSpriteWindows()
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ // OBJ must be enabled in this.dispCnt
+ if ((this.dispCnt & (1 << 12)) == 0) return;
+
+ for (int oamNum = 127; oamNum >= 0; oamNum--)
+ {
+ ushort attr0 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 0);
+
+ // Not an object window, so continue
+ if (((attr0 >> 10) & 3) != 2) continue;
+
+ ushort attr1 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 2);
+ ushort attr2 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 4);
+
+ int x = attr1 & 0x1FF;
+ int y = attr0 & 0xFF;
+
+ int width = -1, height = -1;
+ switch ((attr0 >> 14) & 3)
+ {
+ case 0:
+ // Square
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 8; height = 8; break;
+ case 1: width = 16; height = 16; break;
+ case 2: width = 32; height = 32; break;
+ case 3: width = 64; height = 64; break;
+ }
+ break;
+ case 1:
+ // Horizontal Rectangle
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 16; height = 8; break;
+ case 1: width = 32; height = 8; break;
+ case 2: width = 32; height = 16; break;
+ case 3: width = 64; height = 32; break;
+ }
+ break;
+ case 2:
+ // Vertical Rectangle
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 8; height = 16; break;
+ case 1: width = 8; height = 32; break;
+ case 2: width = 16; height = 32; break;
+ case 3: width = 32; height = 64; break;
+ }
+ break;
+ }
+
+ // Check double size flag here
+
+ int rwidth = width, rheight = height;
+ if ((attr0 & (1 << 8)) != 0)
+ {
+ // Rot-scale on
+ if ((attr0 & (1 << 9)) != 0)
+ {
+ rwidth *= 2;
+ rheight *= 2;
+ }
+ }
+ else
+ {
+ // Invalid sprite
+ if ((attr0 & (1 << 9)) != 0)
+ width = -1;
+ }
+
+ if (width == -1)
+ {
+ // Invalid sprite
+ continue;
+ }
+
+ // Y clipping
+ if (y > ((y + rheight) & 0xff))
+ {
+ if (this.curLine >= ((y + rheight) & 0xff) && !(y < this.curLine)) continue;
+ }
+ else
+ {
+ if (this.curLine < y || this.curLine >= ((y + rheight) & 0xff)) continue;
+ }
+
+ int scale = 1;
+ if ((attr0 & (1 << 13)) != 0) scale = 2;
+
+ int spritey = this.curLine - y;
+ if (spritey < 0) spritey += 256;
+
+ if ((attr0 & (1 << 8)) == 0)
+ {
+ if ((attr1 & (1 << 13)) != 0) spritey = (height - 1) - spritey;
+
+ int baseSprite;
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * (width / 8)) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * 0x20);
+ }
+
+ int baseInc = scale;
+ if ((attr1 & (1 << 12)) != 0)
+ {
+ baseSprite += ((width / 8) * scale) - scale;
+ baseInc = -baseInc;
+ }
+
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 8) + tx;
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ this.windowCover[i & 0x1ff] = this.winObjEnabled;
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 4) + (tx / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ this.windowCover[i & 0x1ff] = this.winObjEnabled;
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ }
+ else
+ {
+ int rotScaleParam = (attr1 >> 9) & 0x1F;
+
+ short dx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x6);
+ short dmx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0xE);
+ short dy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x16);
+ short dmy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x1E);
+
+ int cx = rwidth / 2;
+ int cy = rheight / 2;
+
+ int baseSprite = attr2 & 0x3FF;
+ int pitch;
+
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ pitch = (width / 8) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ pitch = 0x20;
+ }
+
+ short rx = (short)((dmx * (spritey - cy)) - (cx * dx) + (width << 7));
+ short ry = (short)((dmy * (spritey - cy)) - (cx * dy) + (height << 7));
+
+ // Draw a rot/scale sprite
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7);
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ this.windowCover[i & 0x1ff] = this.winObjEnabled;
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ this.windowCover[i & 0x1ff] = this.winObjEnabled;
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ }
+
+ public static uint GbaTo32(ushort color)
+ {
+ // more accurate, but slower :(
+ // return colorLUT[color];
+ return ((color & 0x1FU) << 19) | ((color & 0x3E0U) << 6) | ((color & 0x7C00U) >> 7);
+ }
+ }
+}
diff --git a/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/Renderers.cs b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/Renderers.cs
new file mode 100644
index 0000000000..a05b3b8634
--- /dev/null
+++ b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/Renderers.cs
@@ -0,0 +1,5939 @@
+namespace GarboDev
+{
+ partial class Renderer
+ {
+ #region Sprite Drawing
+ private void DrawSpritesNormal(int priority)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ // OBJ must be enabled in this.dispCnt
+ if ((this.dispCnt & (1 << 12)) == 0) return;
+
+ byte blendMaskType = (byte)(1 << 4);
+
+ for (int oamNum = 127; oamNum >= 0; oamNum--)
+ {
+ ushort attr2 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 4);
+
+ if (((attr2 >> 10) & 3) != priority) continue;
+
+ ushort attr0 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 0);
+ ushort attr1 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 2);
+
+ int x = attr1 & 0x1FF;
+ int y = attr0 & 0xFF;
+
+ bool semiTransparent = false;
+
+ switch ((attr0 >> 10) & 3)
+ {
+ case 1:
+ // Semi-transparent
+ semiTransparent = true;
+ break;
+ case 2:
+ // Obj window
+ continue;
+ case 3:
+ continue;
+ }
+
+ if ((this.dispCnt & 0x7) >= 3 && (attr2 & 0x3FF) < 0x200) continue;
+
+ int width = -1, height = -1;
+ switch ((attr0 >> 14) & 3)
+ {
+ case 0:
+ // Square
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 8; height = 8; break;
+ case 1: width = 16; height = 16; break;
+ case 2: width = 32; height = 32; break;
+ case 3: width = 64; height = 64; break;
+ }
+ break;
+ case 1:
+ // Horizontal Rectangle
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 16; height = 8; break;
+ case 1: width = 32; height = 8; break;
+ case 2: width = 32; height = 16; break;
+ case 3: width = 64; height = 32; break;
+ }
+ break;
+ case 2:
+ // Vertical Rectangle
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 8; height = 16; break;
+ case 1: width = 8; height = 32; break;
+ case 2: width = 16; height = 32; break;
+ case 3: width = 32; height = 64; break;
+ }
+ break;
+ }
+
+ // Check double size flag here
+
+ int rwidth = width, rheight = height;
+ if ((attr0 & (1 << 8)) != 0)
+ {
+ // Rot-scale on
+ if ((attr0 & (1 << 9)) != 0)
+ {
+ rwidth *= 2;
+ rheight *= 2;
+ }
+ }
+ else
+ {
+ // Invalid sprite
+ if ((attr0 & (1 << 9)) != 0)
+ width = -1;
+ }
+
+ if (width == -1)
+ {
+ // Invalid sprite
+ continue;
+ }
+
+ // Y clipping
+ if (y > ((y + rheight) & 0xff))
+ {
+ if (this.curLine >= ((y + rheight) & 0xff) && !(y < this.curLine)) continue;
+ }
+ else
+ {
+ if (this.curLine < y || this.curLine >= ((y + rheight) & 0xff)) continue;
+ }
+
+ int scale = 1;
+ if ((attr0 & (1 << 13)) != 0) scale = 2;
+
+ int spritey = this.curLine - y;
+ if (spritey < 0) spritey += 256;
+
+ if (semiTransparent)
+ {
+ if ((attr0 & (1 << 8)) == 0)
+ {
+ if ((attr1 & (1 << 13)) != 0) spritey = (height - 1) - spritey;
+
+ int baseSprite;
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * (width / 8)) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * 0x20);
+ }
+
+ int baseInc = scale;
+ if ((attr1 & (1 << 12)) != 0)
+ {
+ baseSprite += ((width / 8) * scale) - scale;
+ baseInc = -baseInc;
+ }
+
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && true)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 8) + tx;
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && true)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 4) + (tx / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ }
+ else
+ {
+ int rotScaleParam = (attr1 >> 9) & 0x1F;
+
+ short dx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x6);
+ short dmx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0xE);
+ short dy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x16);
+ short dmy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x1E);
+
+ int cx = rwidth / 2;
+ int cy = rheight / 2;
+
+ int baseSprite = attr2 & 0x3FF;
+ int pitch;
+
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ pitch = (width / 8) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ pitch = 0x20;
+ }
+
+ int rx = (int)((dmx * (spritey - cy)) - (cx * dx) + (width << 7));
+ int ry = (int)((dmy * (spritey - cy)) - (cx * dy) + (height << 7));
+
+ // Draw a rot/scale sprite
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && true)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7);
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && true)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ((attr0 & (1 << 8)) == 0)
+ {
+ if ((attr1 & (1 << 13)) != 0) spritey = (height - 1) - spritey;
+
+ int baseSprite;
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * (width / 8)) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * 0x20);
+ }
+
+ int baseInc = scale;
+ if ((attr1 & (1 << 12)) != 0)
+ {
+ baseSprite += ((width / 8) * scale) - scale;
+ baseInc = -baseInc;
+ }
+
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && true)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 8) + tx;
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && true)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 4) + (tx / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ }
+ else
+ {
+ int rotScaleParam = (attr1 >> 9) & 0x1F;
+
+ short dx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x6);
+ short dmx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0xE);
+ short dy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x16);
+ short dmy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x1E);
+
+ int cx = rwidth / 2;
+ int cy = rheight / 2;
+
+ int baseSprite = attr2 & 0x3FF;
+ int pitch;
+
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ pitch = (width / 8) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ pitch = 0x20;
+ }
+
+ int rx = (int)((dmx * (spritey - cy)) - (cx * dx) + (width << 7));
+ int ry = (int)((dmy * (spritey - cy)) - (cx * dy) + (height << 7));
+
+ // Draw a rot/scale sprite
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && true)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7);
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && true)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ }
+ }
+ private void DrawSpritesBlend(int priority)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ // OBJ must be enabled in this.dispCnt
+ if ((this.dispCnt & (1 << 12)) == 0) return;
+
+ byte blendMaskType = (byte)(1 << 4);
+
+ for (int oamNum = 127; oamNum >= 0; oamNum--)
+ {
+ ushort attr2 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 4);
+
+ if (((attr2 >> 10) & 3) != priority) continue;
+
+ ushort attr0 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 0);
+ ushort attr1 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 2);
+
+ int x = attr1 & 0x1FF;
+ int y = attr0 & 0xFF;
+
+ bool semiTransparent = false;
+
+ switch ((attr0 >> 10) & 3)
+ {
+ case 1:
+ // Semi-transparent
+ semiTransparent = true;
+ break;
+ case 2:
+ // Obj window
+ continue;
+ case 3:
+ continue;
+ }
+
+ if ((this.dispCnt & 0x7) >= 3 && (attr2 & 0x3FF) < 0x200) continue;
+
+ int width = -1, height = -1;
+ switch ((attr0 >> 14) & 3)
+ {
+ case 0:
+ // Square
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 8; height = 8; break;
+ case 1: width = 16; height = 16; break;
+ case 2: width = 32; height = 32; break;
+ case 3: width = 64; height = 64; break;
+ }
+ break;
+ case 1:
+ // Horizontal Rectangle
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 16; height = 8; break;
+ case 1: width = 32; height = 8; break;
+ case 2: width = 32; height = 16; break;
+ case 3: width = 64; height = 32; break;
+ }
+ break;
+ case 2:
+ // Vertical Rectangle
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 8; height = 16; break;
+ case 1: width = 8; height = 32; break;
+ case 2: width = 16; height = 32; break;
+ case 3: width = 32; height = 64; break;
+ }
+ break;
+ }
+
+ // Check double size flag here
+
+ int rwidth = width, rheight = height;
+ if ((attr0 & (1 << 8)) != 0)
+ {
+ // Rot-scale on
+ if ((attr0 & (1 << 9)) != 0)
+ {
+ rwidth *= 2;
+ rheight *= 2;
+ }
+ }
+ else
+ {
+ // Invalid sprite
+ if ((attr0 & (1 << 9)) != 0)
+ width = -1;
+ }
+
+ if (width == -1)
+ {
+ // Invalid sprite
+ continue;
+ }
+
+ // Y clipping
+ if (y > ((y + rheight) & 0xff))
+ {
+ if (this.curLine >= ((y + rheight) & 0xff) && !(y < this.curLine)) continue;
+ }
+ else
+ {
+ if (this.curLine < y || this.curLine >= ((y + rheight) & 0xff)) continue;
+ }
+
+ int scale = 1;
+ if ((attr0 & (1 << 13)) != 0) scale = 2;
+
+ int spritey = this.curLine - y;
+ if (spritey < 0) spritey += 256;
+
+ if (semiTransparent)
+ {
+ if ((attr0 & (1 << 8)) == 0)
+ {
+ if ((attr1 & (1 << 13)) != 0) spritey = (height - 1) - spritey;
+
+ int baseSprite;
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * (width / 8)) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * 0x20);
+ }
+
+ int baseInc = scale;
+ if ((attr1 & (1 << 12)) != 0)
+ {
+ baseSprite += ((width / 8) * scale) - scale;
+ baseInc = -baseInc;
+ }
+
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && true)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 8) + tx;
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && true)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 4) + (tx / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ }
+ else
+ {
+ int rotScaleParam = (attr1 >> 9) & 0x1F;
+
+ short dx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x6);
+ short dmx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0xE);
+ short dy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x16);
+ short dmy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x1E);
+
+ int cx = rwidth / 2;
+ int cy = rheight / 2;
+
+ int baseSprite = attr2 & 0x3FF;
+ int pitch;
+
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ pitch = (width / 8) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ pitch = 0x20;
+ }
+
+ int rx = (int)((dmx * (spritey - cy)) - (cx * dx) + (width << 7));
+ int ry = (int)((dmy * (spritey - cy)) - (cx * dy) + (height << 7));
+
+ // Draw a rot/scale sprite
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && true)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7);
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && true)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ((attr0 & (1 << 8)) == 0)
+ {
+ if ((attr1 & (1 << 13)) != 0) spritey = (height - 1) - spritey;
+
+ int baseSprite;
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * (width / 8)) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * 0x20);
+ }
+
+ int baseInc = scale;
+ if ((attr1 & (1 << 12)) != 0)
+ {
+ baseSprite += ((width / 8) * scale) - scale;
+ baseInc = -baseInc;
+ }
+
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && true)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 8) + tx;
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && true)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 4) + (tx / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ }
+ else
+ {
+ int rotScaleParam = (attr1 >> 9) & 0x1F;
+
+ short dx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x6);
+ short dmx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0xE);
+ short dy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x16);
+ short dmy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x1E);
+
+ int cx = rwidth / 2;
+ int cy = rheight / 2;
+
+ int baseSprite = attr2 & 0x3FF;
+ int pitch;
+
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ pitch = (width / 8) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ pitch = 0x20;
+ }
+
+ int rx = (int)((dmx * (spritey - cy)) - (cx * dx) + (width << 7));
+ int ry = (int)((dmy * (spritey - cy)) - (cx * dy) + (height << 7));
+
+ // Draw a rot/scale sprite
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && true)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7);
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && true)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ }
+ }
+ private void DrawSpritesBrightInc(int priority)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ // OBJ must be enabled in this.dispCnt
+ if ((this.dispCnt & (1 << 12)) == 0) return;
+
+ byte blendMaskType = (byte)(1 << 4);
+
+ for (int oamNum = 127; oamNum >= 0; oamNum--)
+ {
+ ushort attr2 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 4);
+
+ if (((attr2 >> 10) & 3) != priority) continue;
+
+ ushort attr0 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 0);
+ ushort attr1 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 2);
+
+ int x = attr1 & 0x1FF;
+ int y = attr0 & 0xFF;
+
+ bool semiTransparent = false;
+
+ switch ((attr0 >> 10) & 3)
+ {
+ case 1:
+ // Semi-transparent
+ semiTransparent = true;
+ break;
+ case 2:
+ // Obj window
+ continue;
+ case 3:
+ continue;
+ }
+
+ if ((this.dispCnt & 0x7) >= 3 && (attr2 & 0x3FF) < 0x200) continue;
+
+ int width = -1, height = -1;
+ switch ((attr0 >> 14) & 3)
+ {
+ case 0:
+ // Square
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 8; height = 8; break;
+ case 1: width = 16; height = 16; break;
+ case 2: width = 32; height = 32; break;
+ case 3: width = 64; height = 64; break;
+ }
+ break;
+ case 1:
+ // Horizontal Rectangle
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 16; height = 8; break;
+ case 1: width = 32; height = 8; break;
+ case 2: width = 32; height = 16; break;
+ case 3: width = 64; height = 32; break;
+ }
+ break;
+ case 2:
+ // Vertical Rectangle
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 8; height = 16; break;
+ case 1: width = 8; height = 32; break;
+ case 2: width = 16; height = 32; break;
+ case 3: width = 32; height = 64; break;
+ }
+ break;
+ }
+
+ // Check double size flag here
+
+ int rwidth = width, rheight = height;
+ if ((attr0 & (1 << 8)) != 0)
+ {
+ // Rot-scale on
+ if ((attr0 & (1 << 9)) != 0)
+ {
+ rwidth *= 2;
+ rheight *= 2;
+ }
+ }
+ else
+ {
+ // Invalid sprite
+ if ((attr0 & (1 << 9)) != 0)
+ width = -1;
+ }
+
+ if (width == -1)
+ {
+ // Invalid sprite
+ continue;
+ }
+
+ // Y clipping
+ if (y > ((y + rheight) & 0xff))
+ {
+ if (this.curLine >= ((y + rheight) & 0xff) && !(y < this.curLine)) continue;
+ }
+ else
+ {
+ if (this.curLine < y || this.curLine >= ((y + rheight) & 0xff)) continue;
+ }
+
+ int scale = 1;
+ if ((attr0 & (1 << 13)) != 0) scale = 2;
+
+ int spritey = this.curLine - y;
+ if (spritey < 0) spritey += 256;
+
+ if (semiTransparent)
+ {
+ if ((attr0 & (1 << 8)) == 0)
+ {
+ if ((attr1 & (1 << 13)) != 0) spritey = (height - 1) - spritey;
+
+ int baseSprite;
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * (width / 8)) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * 0x20);
+ }
+
+ int baseInc = scale;
+ if ((attr1 & (1 << 12)) != 0)
+ {
+ baseSprite += ((width / 8) * scale) - scale;
+ baseInc = -baseInc;
+ }
+
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && true)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 8) + tx;
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && true)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 4) + (tx / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ }
+ else
+ {
+ int rotScaleParam = (attr1 >> 9) & 0x1F;
+
+ short dx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x6);
+ short dmx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0xE);
+ short dy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x16);
+ short dmy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x1E);
+
+ int cx = rwidth / 2;
+ int cy = rheight / 2;
+
+ int baseSprite = attr2 & 0x3FF;
+ int pitch;
+
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ pitch = (width / 8) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ pitch = 0x20;
+ }
+
+ int rx = (int)((dmx * (spritey - cy)) - (cx * dx) + (width << 7));
+ int ry = (int)((dmy * (spritey - cy)) - (cx * dy) + (height << 7));
+
+ // Draw a rot/scale sprite
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && true)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7);
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && true)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ((attr0 & (1 << 8)) == 0)
+ {
+ if ((attr1 & (1 << 13)) != 0) spritey = (height - 1) - spritey;
+
+ int baseSprite;
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * (width / 8)) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * 0x20);
+ }
+
+ int baseInc = scale;
+ if ((attr1 & (1 << 12)) != 0)
+ {
+ baseSprite += ((width / 8) * scale) - scale;
+ baseInc = -baseInc;
+ }
+
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && true)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 8) + tx;
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r + (((0xFF - r) * this.blendY) >> 4);
+ g = g + (((0xFF - g) * this.blendY) >> 4);
+ b = b + (((0xFF - b) * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && true)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 4) + (tx / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r + (((0xFF - r) * this.blendY) >> 4);
+ g = g + (((0xFF - g) * this.blendY) >> 4);
+ b = b + (((0xFF - b) * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ }
+ else
+ {
+ int rotScaleParam = (attr1 >> 9) & 0x1F;
+
+ short dx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x6);
+ short dmx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0xE);
+ short dy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x16);
+ short dmy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x1E);
+
+ int cx = rwidth / 2;
+ int cy = rheight / 2;
+
+ int baseSprite = attr2 & 0x3FF;
+ int pitch;
+
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ pitch = (width / 8) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ pitch = 0x20;
+ }
+
+ int rx = (int)((dmx * (spritey - cy)) - (cx * dx) + (width << 7));
+ int ry = (int)((dmy * (spritey - cy)) - (cx * dy) + (height << 7));
+
+ // Draw a rot/scale sprite
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && true)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7);
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r + (((0xFF - r) * this.blendY) >> 4);
+ g = g + (((0xFF - g) * this.blendY) >> 4);
+ b = b + (((0xFF - b) * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && true)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r + (((0xFF - r) * this.blendY) >> 4);
+ g = g + (((0xFF - g) * this.blendY) >> 4);
+ b = b + (((0xFF - b) * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ }
+ }
+ private void DrawSpritesBrightDec(int priority)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ // OBJ must be enabled in this.dispCnt
+ if ((this.dispCnt & (1 << 12)) == 0) return;
+
+ byte blendMaskType = (byte)(1 << 4);
+
+ for (int oamNum = 127; oamNum >= 0; oamNum--)
+ {
+ ushort attr2 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 4);
+
+ if (((attr2 >> 10) & 3) != priority) continue;
+
+ ushort attr0 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 0);
+ ushort attr1 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 2);
+
+ int x = attr1 & 0x1FF;
+ int y = attr0 & 0xFF;
+
+ bool semiTransparent = false;
+
+ switch ((attr0 >> 10) & 3)
+ {
+ case 1:
+ // Semi-transparent
+ semiTransparent = true;
+ break;
+ case 2:
+ // Obj window
+ continue;
+ case 3:
+ continue;
+ }
+
+ if ((this.dispCnt & 0x7) >= 3 && (attr2 & 0x3FF) < 0x200) continue;
+
+ int width = -1, height = -1;
+ switch ((attr0 >> 14) & 3)
+ {
+ case 0:
+ // Square
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 8; height = 8; break;
+ case 1: width = 16; height = 16; break;
+ case 2: width = 32; height = 32; break;
+ case 3: width = 64; height = 64; break;
+ }
+ break;
+ case 1:
+ // Horizontal Rectangle
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 16; height = 8; break;
+ case 1: width = 32; height = 8; break;
+ case 2: width = 32; height = 16; break;
+ case 3: width = 64; height = 32; break;
+ }
+ break;
+ case 2:
+ // Vertical Rectangle
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 8; height = 16; break;
+ case 1: width = 8; height = 32; break;
+ case 2: width = 16; height = 32; break;
+ case 3: width = 32; height = 64; break;
+ }
+ break;
+ }
+
+ // Check double size flag here
+
+ int rwidth = width, rheight = height;
+ if ((attr0 & (1 << 8)) != 0)
+ {
+ // Rot-scale on
+ if ((attr0 & (1 << 9)) != 0)
+ {
+ rwidth *= 2;
+ rheight *= 2;
+ }
+ }
+ else
+ {
+ // Invalid sprite
+ if ((attr0 & (1 << 9)) != 0)
+ width = -1;
+ }
+
+ if (width == -1)
+ {
+ // Invalid sprite
+ continue;
+ }
+
+ // Y clipping
+ if (y > ((y + rheight) & 0xff))
+ {
+ if (this.curLine >= ((y + rheight) & 0xff) && !(y < this.curLine)) continue;
+ }
+ else
+ {
+ if (this.curLine < y || this.curLine >= ((y + rheight) & 0xff)) continue;
+ }
+
+ int scale = 1;
+ if ((attr0 & (1 << 13)) != 0) scale = 2;
+
+ int spritey = this.curLine - y;
+ if (spritey < 0) spritey += 256;
+
+ if (semiTransparent)
+ {
+ if ((attr0 & (1 << 8)) == 0)
+ {
+ if ((attr1 & (1 << 13)) != 0) spritey = (height - 1) - spritey;
+
+ int baseSprite;
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * (width / 8)) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * 0x20);
+ }
+
+ int baseInc = scale;
+ if ((attr1 & (1 << 12)) != 0)
+ {
+ baseSprite += ((width / 8) * scale) - scale;
+ baseInc = -baseInc;
+ }
+
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && true)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 8) + tx;
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && true)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 4) + (tx / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ }
+ else
+ {
+ int rotScaleParam = (attr1 >> 9) & 0x1F;
+
+ short dx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x6);
+ short dmx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0xE);
+ short dy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x16);
+ short dmy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x1E);
+
+ int cx = rwidth / 2;
+ int cy = rheight / 2;
+
+ int baseSprite = attr2 & 0x3FF;
+ int pitch;
+
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ pitch = (width / 8) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ pitch = 0x20;
+ }
+
+ int rx = (int)((dmx * (spritey - cy)) - (cx * dx) + (width << 7));
+ int ry = (int)((dmy * (spritey - cy)) - (cx * dy) + (height << 7));
+
+ // Draw a rot/scale sprite
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && true)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7);
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && true)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ((attr0 & (1 << 8)) == 0)
+ {
+ if ((attr1 & (1 << 13)) != 0) spritey = (height - 1) - spritey;
+
+ int baseSprite;
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * (width / 8)) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * 0x20);
+ }
+
+ int baseInc = scale;
+ if ((attr1 & (1 << 12)) != 0)
+ {
+ baseSprite += ((width / 8) * scale) - scale;
+ baseInc = -baseInc;
+ }
+
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && true)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 8) + tx;
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r - ((r * this.blendY) >> 4);
+ g = g - ((g * this.blendY) >> 4);
+ b = b - ((b * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && true)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 4) + (tx / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r - ((r * this.blendY) >> 4);
+ g = g - ((g * this.blendY) >> 4);
+ b = b - ((b * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ }
+ else
+ {
+ int rotScaleParam = (attr1 >> 9) & 0x1F;
+
+ short dx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x6);
+ short dmx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0xE);
+ short dy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x16);
+ short dmy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x1E);
+
+ int cx = rwidth / 2;
+ int cy = rheight / 2;
+
+ int baseSprite = attr2 & 0x3FF;
+ int pitch;
+
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ pitch = (width / 8) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ pitch = 0x20;
+ }
+
+ int rx = (int)((dmx * (spritey - cy)) - (cx * dx) + (width << 7));
+ int ry = (int)((dmy * (spritey - cy)) - (cx * dy) + (height << 7));
+
+ // Draw a rot/scale sprite
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && true)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7);
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r - ((r * this.blendY) >> 4);
+ g = g - ((g * this.blendY) >> 4);
+ b = b - ((b * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && true)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r - ((r * this.blendY) >> 4);
+ g = g - ((g * this.blendY) >> 4);
+ b = b - ((b * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ }
+ }
+ private void DrawSpritesWindow(int priority)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ // OBJ must be enabled in this.dispCnt
+ if ((this.dispCnt & (1 << 12)) == 0) return;
+
+ byte blendMaskType = (byte)(1 << 4);
+
+ for (int oamNum = 127; oamNum >= 0; oamNum--)
+ {
+ ushort attr2 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 4);
+
+ if (((attr2 >> 10) & 3) != priority) continue;
+
+ ushort attr0 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 0);
+ ushort attr1 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 2);
+
+ int x = attr1 & 0x1FF;
+ int y = attr0 & 0xFF;
+
+ bool semiTransparent = false;
+
+ switch ((attr0 >> 10) & 3)
+ {
+ case 1:
+ // Semi-transparent
+ semiTransparent = true;
+ break;
+ case 2:
+ // Obj window
+ continue;
+ case 3:
+ continue;
+ }
+
+ if ((this.dispCnt & 0x7) >= 3 && (attr2 & 0x3FF) < 0x200) continue;
+
+ int width = -1, height = -1;
+ switch ((attr0 >> 14) & 3)
+ {
+ case 0:
+ // Square
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 8; height = 8; break;
+ case 1: width = 16; height = 16; break;
+ case 2: width = 32; height = 32; break;
+ case 3: width = 64; height = 64; break;
+ }
+ break;
+ case 1:
+ // Horizontal Rectangle
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 16; height = 8; break;
+ case 1: width = 32; height = 8; break;
+ case 2: width = 32; height = 16; break;
+ case 3: width = 64; height = 32; break;
+ }
+ break;
+ case 2:
+ // Vertical Rectangle
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 8; height = 16; break;
+ case 1: width = 8; height = 32; break;
+ case 2: width = 16; height = 32; break;
+ case 3: width = 32; height = 64; break;
+ }
+ break;
+ }
+
+ // Check double size flag here
+
+ int rwidth = width, rheight = height;
+ if ((attr0 & (1 << 8)) != 0)
+ {
+ // Rot-scale on
+ if ((attr0 & (1 << 9)) != 0)
+ {
+ rwidth *= 2;
+ rheight *= 2;
+ }
+ }
+ else
+ {
+ // Invalid sprite
+ if ((attr0 & (1 << 9)) != 0)
+ width = -1;
+ }
+
+ if (width == -1)
+ {
+ // Invalid sprite
+ continue;
+ }
+
+ // Y clipping
+ if (y > ((y + rheight) & 0xff))
+ {
+ if (this.curLine >= ((y + rheight) & 0xff) && !(y < this.curLine)) continue;
+ }
+ else
+ {
+ if (this.curLine < y || this.curLine >= ((y + rheight) & 0xff)) continue;
+ }
+
+ int scale = 1;
+ if ((attr0 & (1 << 13)) != 0) scale = 2;
+
+ int spritey = this.curLine - y;
+ if (spritey < 0) spritey += 256;
+
+ if (semiTransparent)
+ {
+ if ((attr0 & (1 << 8)) == 0)
+ {
+ if ((attr1 & (1 << 13)) != 0) spritey = (height - 1) - spritey;
+
+ int baseSprite;
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * (width / 8)) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * 0x20);
+ }
+
+ int baseInc = scale;
+ if ((attr1 & (1 << 12)) != 0)
+ {
+ baseSprite += ((width / 8) * scale) - scale;
+ baseInc = -baseInc;
+ }
+
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 8) + tx;
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 4) + (tx / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ }
+ else
+ {
+ int rotScaleParam = (attr1 >> 9) & 0x1F;
+
+ short dx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x6);
+ short dmx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0xE);
+ short dy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x16);
+ short dmy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x1E);
+
+ int cx = rwidth / 2;
+ int cy = rheight / 2;
+
+ int baseSprite = attr2 & 0x3FF;
+ int pitch;
+
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ pitch = (width / 8) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ pitch = 0x20;
+ }
+
+ int rx = (int)((dmx * (spritey - cy)) - (cx * dx) + (width << 7));
+ int ry = (int)((dmy * (spritey - cy)) - (cx * dy) + (height << 7));
+
+ // Draw a rot/scale sprite
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7);
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ((attr0 & (1 << 8)) == 0)
+ {
+ if ((attr1 & (1 << 13)) != 0) spritey = (height - 1) - spritey;
+
+ int baseSprite;
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * (width / 8)) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * 0x20);
+ }
+
+ int baseInc = scale;
+ if ((attr1 & (1 << 12)) != 0)
+ {
+ baseSprite += ((width / 8) * scale) - scale;
+ baseInc = -baseInc;
+ }
+
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 8) + tx;
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 4) + (tx / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ }
+ else
+ {
+ int rotScaleParam = (attr1 >> 9) & 0x1F;
+
+ short dx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x6);
+ short dmx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0xE);
+ short dy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x16);
+ short dmy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x1E);
+
+ int cx = rwidth / 2;
+ int cy = rheight / 2;
+
+ int baseSprite = attr2 & 0x3FF;
+ int pitch;
+
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ pitch = (width / 8) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ pitch = 0x20;
+ }
+
+ int rx = (int)((dmx * (spritey - cy)) - (cx * dx) + (width << 7));
+ int ry = (int)((dmy * (spritey - cy)) - (cx * dy) + (height << 7));
+
+ // Draw a rot/scale sprite
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7);
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ }
+ }
+ private void DrawSpritesWindowBlend(int priority)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ // OBJ must be enabled in this.dispCnt
+ if ((this.dispCnt & (1 << 12)) == 0) return;
+
+ byte blendMaskType = (byte)(1 << 4);
+
+ for (int oamNum = 127; oamNum >= 0; oamNum--)
+ {
+ ushort attr2 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 4);
+
+ if (((attr2 >> 10) & 3) != priority) continue;
+
+ ushort attr0 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 0);
+ ushort attr1 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 2);
+
+ int x = attr1 & 0x1FF;
+ int y = attr0 & 0xFF;
+
+ bool semiTransparent = false;
+
+ switch ((attr0 >> 10) & 3)
+ {
+ case 1:
+ // Semi-transparent
+ semiTransparent = true;
+ break;
+ case 2:
+ // Obj window
+ continue;
+ case 3:
+ continue;
+ }
+
+ if ((this.dispCnt & 0x7) >= 3 && (attr2 & 0x3FF) < 0x200) continue;
+
+ int width = -1, height = -1;
+ switch ((attr0 >> 14) & 3)
+ {
+ case 0:
+ // Square
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 8; height = 8; break;
+ case 1: width = 16; height = 16; break;
+ case 2: width = 32; height = 32; break;
+ case 3: width = 64; height = 64; break;
+ }
+ break;
+ case 1:
+ // Horizontal Rectangle
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 16; height = 8; break;
+ case 1: width = 32; height = 8; break;
+ case 2: width = 32; height = 16; break;
+ case 3: width = 64; height = 32; break;
+ }
+ break;
+ case 2:
+ // Vertical Rectangle
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 8; height = 16; break;
+ case 1: width = 8; height = 32; break;
+ case 2: width = 16; height = 32; break;
+ case 3: width = 32; height = 64; break;
+ }
+ break;
+ }
+
+ // Check double size flag here
+
+ int rwidth = width, rheight = height;
+ if ((attr0 & (1 << 8)) != 0)
+ {
+ // Rot-scale on
+ if ((attr0 & (1 << 9)) != 0)
+ {
+ rwidth *= 2;
+ rheight *= 2;
+ }
+ }
+ else
+ {
+ // Invalid sprite
+ if ((attr0 & (1 << 9)) != 0)
+ width = -1;
+ }
+
+ if (width == -1)
+ {
+ // Invalid sprite
+ continue;
+ }
+
+ // Y clipping
+ if (y > ((y + rheight) & 0xff))
+ {
+ if (this.curLine >= ((y + rheight) & 0xff) && !(y < this.curLine)) continue;
+ }
+ else
+ {
+ if (this.curLine < y || this.curLine >= ((y + rheight) & 0xff)) continue;
+ }
+
+ int scale = 1;
+ if ((attr0 & (1 << 13)) != 0) scale = 2;
+
+ int spritey = this.curLine - y;
+ if (spritey < 0) spritey += 256;
+
+ if (semiTransparent)
+ {
+ if ((attr0 & (1 << 8)) == 0)
+ {
+ if ((attr1 & (1 << 13)) != 0) spritey = (height - 1) - spritey;
+
+ int baseSprite;
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * (width / 8)) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * 0x20);
+ }
+
+ int baseInc = scale;
+ if ((attr1 & (1 << 12)) != 0)
+ {
+ baseSprite += ((width / 8) * scale) - scale;
+ baseInc = -baseInc;
+ }
+
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 8) + tx;
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 4) + (tx / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ }
+ else
+ {
+ int rotScaleParam = (attr1 >> 9) & 0x1F;
+
+ short dx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x6);
+ short dmx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0xE);
+ short dy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x16);
+ short dmy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x1E);
+
+ int cx = rwidth / 2;
+ int cy = rheight / 2;
+
+ int baseSprite = attr2 & 0x3FF;
+ int pitch;
+
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ pitch = (width / 8) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ pitch = 0x20;
+ }
+
+ int rx = (int)((dmx * (spritey - cy)) - (cx * dx) + (width << 7));
+ int ry = (int)((dmy * (spritey - cy)) - (cx * dy) + (height << 7));
+
+ // Draw a rot/scale sprite
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7);
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ((attr0 & (1 << 8)) == 0)
+ {
+ if ((attr1 & (1 << 13)) != 0) spritey = (height - 1) - spritey;
+
+ int baseSprite;
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * (width / 8)) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * 0x20);
+ }
+
+ int baseInc = scale;
+ if ((attr1 & (1 << 12)) != 0)
+ {
+ baseSprite += ((width / 8) * scale) - scale;
+ baseInc = -baseInc;
+ }
+
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 8) + tx;
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 4) + (tx / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ }
+ else
+ {
+ int rotScaleParam = (attr1 >> 9) & 0x1F;
+
+ short dx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x6);
+ short dmx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0xE);
+ short dy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x16);
+ short dmy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x1E);
+
+ int cx = rwidth / 2;
+ int cy = rheight / 2;
+
+ int baseSprite = attr2 & 0x3FF;
+ int pitch;
+
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ pitch = (width / 8) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ pitch = 0x20;
+ }
+
+ int rx = (int)((dmx * (spritey - cy)) - (cx * dx) + (width << 7));
+ int ry = (int)((dmy * (spritey - cy)) - (cx * dy) + (height << 7));
+
+ // Draw a rot/scale sprite
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7);
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ }
+ }
+ private void DrawSpritesWindowBrightInc(int priority)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ // OBJ must be enabled in this.dispCnt
+ if ((this.dispCnt & (1 << 12)) == 0) return;
+
+ byte blendMaskType = (byte)(1 << 4);
+
+ for (int oamNum = 127; oamNum >= 0; oamNum--)
+ {
+ ushort attr2 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 4);
+
+ if (((attr2 >> 10) & 3) != priority) continue;
+
+ ushort attr0 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 0);
+ ushort attr1 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 2);
+
+ int x = attr1 & 0x1FF;
+ int y = attr0 & 0xFF;
+
+ bool semiTransparent = false;
+
+ switch ((attr0 >> 10) & 3)
+ {
+ case 1:
+ // Semi-transparent
+ semiTransparent = true;
+ break;
+ case 2:
+ // Obj window
+ continue;
+ case 3:
+ continue;
+ }
+
+ if ((this.dispCnt & 0x7) >= 3 && (attr2 & 0x3FF) < 0x200) continue;
+
+ int width = -1, height = -1;
+ switch ((attr0 >> 14) & 3)
+ {
+ case 0:
+ // Square
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 8; height = 8; break;
+ case 1: width = 16; height = 16; break;
+ case 2: width = 32; height = 32; break;
+ case 3: width = 64; height = 64; break;
+ }
+ break;
+ case 1:
+ // Horizontal Rectangle
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 16; height = 8; break;
+ case 1: width = 32; height = 8; break;
+ case 2: width = 32; height = 16; break;
+ case 3: width = 64; height = 32; break;
+ }
+ break;
+ case 2:
+ // Vertical Rectangle
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 8; height = 16; break;
+ case 1: width = 8; height = 32; break;
+ case 2: width = 16; height = 32; break;
+ case 3: width = 32; height = 64; break;
+ }
+ break;
+ }
+
+ // Check double size flag here
+
+ int rwidth = width, rheight = height;
+ if ((attr0 & (1 << 8)) != 0)
+ {
+ // Rot-scale on
+ if ((attr0 & (1 << 9)) != 0)
+ {
+ rwidth *= 2;
+ rheight *= 2;
+ }
+ }
+ else
+ {
+ // Invalid sprite
+ if ((attr0 & (1 << 9)) != 0)
+ width = -1;
+ }
+
+ if (width == -1)
+ {
+ // Invalid sprite
+ continue;
+ }
+
+ // Y clipping
+ if (y > ((y + rheight) & 0xff))
+ {
+ if (this.curLine >= ((y + rheight) & 0xff) && !(y < this.curLine)) continue;
+ }
+ else
+ {
+ if (this.curLine < y || this.curLine >= ((y + rheight) & 0xff)) continue;
+ }
+
+ int scale = 1;
+ if ((attr0 & (1 << 13)) != 0) scale = 2;
+
+ int spritey = this.curLine - y;
+ if (spritey < 0) spritey += 256;
+
+ if (semiTransparent)
+ {
+ if ((attr0 & (1 << 8)) == 0)
+ {
+ if ((attr1 & (1 << 13)) != 0) spritey = (height - 1) - spritey;
+
+ int baseSprite;
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * (width / 8)) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * 0x20);
+ }
+
+ int baseInc = scale;
+ if ((attr1 & (1 << 12)) != 0)
+ {
+ baseSprite += ((width / 8) * scale) - scale;
+ baseInc = -baseInc;
+ }
+
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 8) + tx;
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 4) + (tx / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ }
+ else
+ {
+ int rotScaleParam = (attr1 >> 9) & 0x1F;
+
+ short dx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x6);
+ short dmx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0xE);
+ short dy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x16);
+ short dmy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x1E);
+
+ int cx = rwidth / 2;
+ int cy = rheight / 2;
+
+ int baseSprite = attr2 & 0x3FF;
+ int pitch;
+
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ pitch = (width / 8) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ pitch = 0x20;
+ }
+
+ int rx = (int)((dmx * (spritey - cy)) - (cx * dx) + (width << 7));
+ int ry = (int)((dmy * (spritey - cy)) - (cx * dy) + (height << 7));
+
+ // Draw a rot/scale sprite
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7);
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ((attr0 & (1 << 8)) == 0)
+ {
+ if ((attr1 & (1 << 13)) != 0) spritey = (height - 1) - spritey;
+
+ int baseSprite;
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * (width / 8)) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * 0x20);
+ }
+
+ int baseInc = scale;
+ if ((attr1 & (1 << 12)) != 0)
+ {
+ baseSprite += ((width / 8) * scale) - scale;
+ baseInc = -baseInc;
+ }
+
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 8) + tx;
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r + (((0xFF - r) * this.blendY) >> 4);
+ g = g + (((0xFF - g) * this.blendY) >> 4);
+ b = b + (((0xFF - b) * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 4) + (tx / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r + (((0xFF - r) * this.blendY) >> 4);
+ g = g + (((0xFF - g) * this.blendY) >> 4);
+ b = b + (((0xFF - b) * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ }
+ else
+ {
+ int rotScaleParam = (attr1 >> 9) & 0x1F;
+
+ short dx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x6);
+ short dmx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0xE);
+ short dy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x16);
+ short dmy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x1E);
+
+ int cx = rwidth / 2;
+ int cy = rheight / 2;
+
+ int baseSprite = attr2 & 0x3FF;
+ int pitch;
+
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ pitch = (width / 8) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ pitch = 0x20;
+ }
+
+ int rx = (int)((dmx * (spritey - cy)) - (cx * dx) + (width << 7));
+ int ry = (int)((dmy * (spritey - cy)) - (cx * dy) + (height << 7));
+
+ // Draw a rot/scale sprite
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7);
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r + (((0xFF - r) * this.blendY) >> 4);
+ g = g + (((0xFF - g) * this.blendY) >> 4);
+ b = b + (((0xFF - b) * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r + (((0xFF - r) * this.blendY) >> 4);
+ g = g + (((0xFF - g) * this.blendY) >> 4);
+ b = b + (((0xFF - b) * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ }
+ }
+ private void DrawSpritesWindowBrightDec(int priority)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ // OBJ must be enabled in this.dispCnt
+ if ((this.dispCnt & (1 << 12)) == 0) return;
+
+ byte blendMaskType = (byte)(1 << 4);
+
+ for (int oamNum = 127; oamNum >= 0; oamNum--)
+ {
+ ushort attr2 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 4);
+
+ if (((attr2 >> 10) & 3) != priority) continue;
+
+ ushort attr0 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 0);
+ ushort attr1 = this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(oamNum * 8) + 2);
+
+ int x = attr1 & 0x1FF;
+ int y = attr0 & 0xFF;
+
+ bool semiTransparent = false;
+
+ switch ((attr0 >> 10) & 3)
+ {
+ case 1:
+ // Semi-transparent
+ semiTransparent = true;
+ break;
+ case 2:
+ // Obj window
+ continue;
+ case 3:
+ continue;
+ }
+
+ if ((this.dispCnt & 0x7) >= 3 && (attr2 & 0x3FF) < 0x200) continue;
+
+ int width = -1, height = -1;
+ switch ((attr0 >> 14) & 3)
+ {
+ case 0:
+ // Square
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 8; height = 8; break;
+ case 1: width = 16; height = 16; break;
+ case 2: width = 32; height = 32; break;
+ case 3: width = 64; height = 64; break;
+ }
+ break;
+ case 1:
+ // Horizontal Rectangle
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 16; height = 8; break;
+ case 1: width = 32; height = 8; break;
+ case 2: width = 32; height = 16; break;
+ case 3: width = 64; height = 32; break;
+ }
+ break;
+ case 2:
+ // Vertical Rectangle
+ switch ((attr1 >> 14) & 3)
+ {
+ case 0: width = 8; height = 16; break;
+ case 1: width = 8; height = 32; break;
+ case 2: width = 16; height = 32; break;
+ case 3: width = 32; height = 64; break;
+ }
+ break;
+ }
+
+ // Check double size flag here
+
+ int rwidth = width, rheight = height;
+ if ((attr0 & (1 << 8)) != 0)
+ {
+ // Rot-scale on
+ if ((attr0 & (1 << 9)) != 0)
+ {
+ rwidth *= 2;
+ rheight *= 2;
+ }
+ }
+ else
+ {
+ // Invalid sprite
+ if ((attr0 & (1 << 9)) != 0)
+ width = -1;
+ }
+
+ if (width == -1)
+ {
+ // Invalid sprite
+ continue;
+ }
+
+ // Y clipping
+ if (y > ((y + rheight) & 0xff))
+ {
+ if (this.curLine >= ((y + rheight) & 0xff) && !(y < this.curLine)) continue;
+ }
+ else
+ {
+ if (this.curLine < y || this.curLine >= ((y + rheight) & 0xff)) continue;
+ }
+
+ int scale = 1;
+ if ((attr0 & (1 << 13)) != 0) scale = 2;
+
+ int spritey = this.curLine - y;
+ if (spritey < 0) spritey += 256;
+
+ if (semiTransparent)
+ {
+ if ((attr0 & (1 << 8)) == 0)
+ {
+ if ((attr1 & (1 << 13)) != 0) spritey = (height - 1) - spritey;
+
+ int baseSprite;
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * (width / 8)) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * 0x20);
+ }
+
+ int baseInc = scale;
+ if ((attr1 & (1 << 12)) != 0)
+ {
+ baseSprite += ((width / 8) * scale) - scale;
+ baseInc = -baseInc;
+ }
+
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 8) + tx;
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 4) + (tx / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ }
+ else
+ {
+ int rotScaleParam = (attr1 >> 9) & 0x1F;
+
+ short dx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x6);
+ short dmx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0xE);
+ short dy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x16);
+ short dmy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x1E);
+
+ int cx = rwidth / 2;
+ int cy = rheight / 2;
+
+ int baseSprite = attr2 & 0x3FF;
+ int pitch;
+
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ pitch = (width / 8) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ pitch = 0x20;
+ }
+
+ int rx = (int)((dmx * (spritey - cy)) - (cx * dx) + (width << 7));
+ int ry = (int)((dmy * (spritey - cy)) - (cx * dy) + (height << 7));
+
+ // Draw a rot/scale sprite
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7);
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i & 0x1ff] & this.blendTarget) != 0 && this.blend[i & 0x1ff] != blendMaskType)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[(i & 0x1ff)];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ((attr0 & (1 << 8)) == 0)
+ {
+ if ((attr1 & (1 << 13)) != 0) spritey = (height - 1) - spritey;
+
+ int baseSprite;
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * (width / 8)) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ baseSprite = (attr2 & 0x3FF) + ((spritey / 8) * 0x20);
+ }
+
+ int baseInc = scale;
+ if ((attr1 & (1 << 12)) != 0)
+ {
+ baseSprite += ((width / 8) * scale) - scale;
+ baseInc = -baseInc;
+ }
+
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 8) + tx;
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r - ((r * this.blendY) >> 4);
+ g = g - ((g * this.blendY) >> 4);
+ b = b - ((b * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + width; i++)
+ {
+ if ((i & 0x1ff) < 240 && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int tx = (i - x) & 7;
+ if ((attr1 & (1 << 12)) != 0) tx = 7 - tx;
+ int curIdx = baseSprite * 32 + ((spritey & 7) * 4) + (tx / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r - ((r * this.blendY) >> 4);
+ g = g - ((g * this.blendY) >> 4);
+ b = b - ((b * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+ if (((i - x) & 7) == 7) baseSprite += baseInc;
+ }
+ }
+ }
+ else
+ {
+ int rotScaleParam = (attr1 >> 9) & 0x1F;
+
+ short dx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x6);
+ short dmx = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0xE);
+ short dy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x16);
+ short dmy = (short)this.memory.ReadU16Debug(Memory.OAM_BASE + (uint)(rotScaleParam * 8 * 4) + 0x1E);
+
+ int cx = rwidth / 2;
+ int cy = rheight / 2;
+
+ int baseSprite = attr2 & 0x3FF;
+ int pitch;
+
+ if ((this.dispCnt & (1 << 6)) != 0)
+ {
+ // 1 dimensional
+ pitch = (width / 8) * scale;
+ }
+ else
+ {
+ // 2 dimensional
+ pitch = 0x20;
+ }
+
+ int rx = (int)((dmx * (spritey - cy)) - (cx * dx) + (width << 7));
+ int ry = (int)((dmy * (spritey - cy)) - (cx * dy) + (height << 7));
+
+ // Draw a rot/scale sprite
+ if ((attr0 & (1 << 13)) != 0)
+ {
+ // 256 colors
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7);
+ int lookup = vram[0x10000 + curIdx];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[0x200 + lookup * 2] | (palette[0x200 + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r - ((r * this.blendY) >> 4);
+ g = g - ((g * this.blendY) >> 4);
+ b = b - ((b * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ else
+ {
+ // 16 colors
+ int palIdx = 0x200 + (((attr2 >> 12) & 0xF) * 16 * 2);
+ for (int i = x; i < x + rwidth; i++)
+ {
+ int tx = rx >> 8;
+ int ty = ry >> 8;
+
+ if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height
+ && (this.windowCover[i & 0x1ff] & (1 << 4)) != 0)
+ {
+ int curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2);
+ int lookup = vram[0x10000 + curIdx];
+ if ((tx & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palIdx + lookup * 2] | (palette[palIdx + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i & 0x1ff] & (1 << 5)) != 0)
+ {
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r - ((r * this.blendY) >> 4);
+ g = g - ((g * this.blendY) >> 4);
+ b = b - ((b * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[(i & 0x1ff)] = pixelColor;
+ this.blend[(i & 0x1ff)] = blendMaskType;
+
+ }
+ }
+
+ rx += dx;
+ ry += dy;
+ }
+ }
+ }
+ }
+ }
+ }
+ #endregion Sprite Drawing
+ #region Rot/Scale Bg
+ private void RenderRotScaleBgNormal(int bg)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ byte blendMaskType = (byte)(1 << bg);
+
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)bg);
+
+ int width = 0, height = 0;
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 0: width = 128; height = 128; break;
+ case 1: width = 256; height = 256; break;
+ case 2: width = 512; height = 512; break;
+ case 3: width = 1024; height = 1024; break;
+ }
+
+ int screenBase = ((bgcnt >> 8) & 0x1F) * 0x800;
+ int charBase = ((bgcnt >> 2) & 0x3) * 0x4000;
+
+ int x = this.memory.Bgx[bg - 2];
+ int y = this.memory.Bgy[bg - 2];
+
+ short dx = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PA + (uint)(bg - 2) * 0x10);
+ short dy = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PC + (uint)(bg - 2) * 0x10);
+
+ bool transparent = (bgcnt & (1 << 13)) == 0;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if (true)
+ {
+ int ax = x >> 8;
+ int ay = y >> 8;
+
+ if ((ax >= 0 && ax < width && ay >= 0 && ay < height) || !transparent)
+ {
+ int tmpTileIdx = (int)(screenBase + ((ay & (height - 1)) / 8) * (width / 8) + ((ax & (width - 1)) / 8));
+ int tileChar = vram[tmpTileIdx];
+
+ int lookup = vram[charBase + (tileChar * 64) + ((ay & 7) * 8) + (ax & 7)];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[lookup * 2] | (palette[lookup * 2 + 1] << 8)));
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+
+ x += dx;
+ y += dy;
+ }
+ }
+ private void RenderRotScaleBgBlend(int bg)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ byte blendMaskType = (byte)(1 << bg);
+
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)bg);
+
+ int width = 0, height = 0;
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 0: width = 128; height = 128; break;
+ case 1: width = 256; height = 256; break;
+ case 2: width = 512; height = 512; break;
+ case 3: width = 1024; height = 1024; break;
+ }
+
+ int screenBase = ((bgcnt >> 8) & 0x1F) * 0x800;
+ int charBase = ((bgcnt >> 2) & 0x3) * 0x4000;
+
+ int x = this.memory.Bgx[bg - 2];
+ int y = this.memory.Bgy[bg - 2];
+
+ short dx = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PA + (uint)(bg - 2) * 0x10);
+ short dy = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PC + (uint)(bg - 2) * 0x10);
+
+ bool transparent = (bgcnt & (1 << 13)) == 0;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if (true)
+ {
+ int ax = x >> 8;
+ int ay = y >> 8;
+
+ if ((ax >= 0 && ax < width && ay >= 0 && ay < height) || !transparent)
+ {
+ int tmpTileIdx = (int)(screenBase + ((ay & (height - 1)) / 8) * (width / 8) + ((ax & (width - 1)) / 8));
+ int tileChar = vram[tmpTileIdx];
+
+ int lookup = vram[charBase + (tileChar * 64) + ((ay & 7) * 8) + (ax & 7)];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[lookup * 2] | (palette[lookup * 2 + 1] << 8)));
+ if ((this.blend[i] & this.blendTarget) != 0)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[i];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+
+ x += dx;
+ y += dy;
+ }
+ }
+ private void RenderRotScaleBgBrightInc(int bg)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ byte blendMaskType = (byte)(1 << bg);
+
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)bg);
+
+ int width = 0, height = 0;
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 0: width = 128; height = 128; break;
+ case 1: width = 256; height = 256; break;
+ case 2: width = 512; height = 512; break;
+ case 3: width = 1024; height = 1024; break;
+ }
+
+ int screenBase = ((bgcnt >> 8) & 0x1F) * 0x800;
+ int charBase = ((bgcnt >> 2) & 0x3) * 0x4000;
+
+ int x = this.memory.Bgx[bg - 2];
+ int y = this.memory.Bgy[bg - 2];
+
+ short dx = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PA + (uint)(bg - 2) * 0x10);
+ short dy = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PC + (uint)(bg - 2) * 0x10);
+
+ bool transparent = (bgcnt & (1 << 13)) == 0;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if (true)
+ {
+ int ax = x >> 8;
+ int ay = y >> 8;
+
+ if ((ax >= 0 && ax < width && ay >= 0 && ay < height) || !transparent)
+ {
+ int tmpTileIdx = (int)(screenBase + ((ay & (height - 1)) / 8) * (width / 8) + ((ax & (width - 1)) / 8));
+ int tileChar = vram[tmpTileIdx];
+
+ int lookup = vram[charBase + (tileChar * 64) + ((ay & 7) * 8) + (ax & 7)];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[lookup * 2] | (palette[lookup * 2 + 1] << 8)));
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r + (((0xFF - r) * this.blendY) >> 4);
+ g = g + (((0xFF - g) * this.blendY) >> 4);
+ b = b + (((0xFF - b) * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+
+ x += dx;
+ y += dy;
+ }
+ }
+ private void RenderRotScaleBgBrightDec(int bg)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ byte blendMaskType = (byte)(1 << bg);
+
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)bg);
+
+ int width = 0, height = 0;
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 0: width = 128; height = 128; break;
+ case 1: width = 256; height = 256; break;
+ case 2: width = 512; height = 512; break;
+ case 3: width = 1024; height = 1024; break;
+ }
+
+ int screenBase = ((bgcnt >> 8) & 0x1F) * 0x800;
+ int charBase = ((bgcnt >> 2) & 0x3) * 0x4000;
+
+ int x = this.memory.Bgx[bg - 2];
+ int y = this.memory.Bgy[bg - 2];
+
+ short dx = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PA + (uint)(bg - 2) * 0x10);
+ short dy = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PC + (uint)(bg - 2) * 0x10);
+
+ bool transparent = (bgcnt & (1 << 13)) == 0;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if (true)
+ {
+ int ax = x >> 8;
+ int ay = y >> 8;
+
+ if ((ax >= 0 && ax < width && ay >= 0 && ay < height) || !transparent)
+ {
+ int tmpTileIdx = (int)(screenBase + ((ay & (height - 1)) / 8) * (width / 8) + ((ax & (width - 1)) / 8));
+ int tileChar = vram[tmpTileIdx];
+
+ int lookup = vram[charBase + (tileChar * 64) + ((ay & 7) * 8) + (ax & 7)];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[lookup * 2] | (palette[lookup * 2 + 1] << 8)));
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r - ((r * this.blendY) >> 4);
+ g = g - ((g * this.blendY) >> 4);
+ b = b - ((b * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+
+ x += dx;
+ y += dy;
+ }
+ }
+ private void RenderRotScaleBgWindow(int bg)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ byte blendMaskType = (byte)(1 << bg);
+
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)bg);
+
+ int width = 0, height = 0;
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 0: width = 128; height = 128; break;
+ case 1: width = 256; height = 256; break;
+ case 2: width = 512; height = 512; break;
+ case 3: width = 1024; height = 1024; break;
+ }
+
+ int screenBase = ((bgcnt >> 8) & 0x1F) * 0x800;
+ int charBase = ((bgcnt >> 2) & 0x3) * 0x4000;
+
+ int x = this.memory.Bgx[bg - 2];
+ int y = this.memory.Bgy[bg - 2];
+
+ short dx = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PA + (uint)(bg - 2) * 0x10);
+ short dy = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PC + (uint)(bg - 2) * 0x10);
+
+ bool transparent = (bgcnt & (1 << 13)) == 0;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if ((this.windowCover[i] & (1 << bg)) != 0)
+ {
+ int ax = x >> 8;
+ int ay = y >> 8;
+
+ if ((ax >= 0 && ax < width && ay >= 0 && ay < height) || !transparent)
+ {
+ int tmpTileIdx = (int)(screenBase + ((ay & (height - 1)) / 8) * (width / 8) + ((ax & (width - 1)) / 8));
+ int tileChar = vram[tmpTileIdx];
+
+ int lookup = vram[charBase + (tileChar * 64) + ((ay & 7) * 8) + (ax & 7)];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[lookup * 2] | (palette[lookup * 2 + 1] << 8)));
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+
+ x += dx;
+ y += dy;
+ }
+ }
+ private void RenderRotScaleBgWindowBlend(int bg)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ byte blendMaskType = (byte)(1 << bg);
+
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)bg);
+
+ int width = 0, height = 0;
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 0: width = 128; height = 128; break;
+ case 1: width = 256; height = 256; break;
+ case 2: width = 512; height = 512; break;
+ case 3: width = 1024; height = 1024; break;
+ }
+
+ int screenBase = ((bgcnt >> 8) & 0x1F) * 0x800;
+ int charBase = ((bgcnt >> 2) & 0x3) * 0x4000;
+
+ int x = this.memory.Bgx[bg - 2];
+ int y = this.memory.Bgy[bg - 2];
+
+ short dx = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PA + (uint)(bg - 2) * 0x10);
+ short dy = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PC + (uint)(bg - 2) * 0x10);
+
+ bool transparent = (bgcnt & (1 << 13)) == 0;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if ((this.windowCover[i] & (1 << bg)) != 0)
+ {
+ int ax = x >> 8;
+ int ay = y >> 8;
+
+ if ((ax >= 0 && ax < width && ay >= 0 && ay < height) || !transparent)
+ {
+ int tmpTileIdx = (int)(screenBase + ((ay & (height - 1)) / 8) * (width / 8) + ((ax & (width - 1)) / 8));
+ int tileChar = vram[tmpTileIdx];
+
+ int lookup = vram[charBase + (tileChar * 64) + ((ay & 7) * 8) + (ax & 7)];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[lookup * 2] | (palette[lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i] & this.blendTarget) != 0)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[i];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+
+ x += dx;
+ y += dy;
+ }
+ }
+ private void RenderRotScaleBgWindowBrightInc(int bg)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ byte blendMaskType = (byte)(1 << bg);
+
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)bg);
+
+ int width = 0, height = 0;
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 0: width = 128; height = 128; break;
+ case 1: width = 256; height = 256; break;
+ case 2: width = 512; height = 512; break;
+ case 3: width = 1024; height = 1024; break;
+ }
+
+ int screenBase = ((bgcnt >> 8) & 0x1F) * 0x800;
+ int charBase = ((bgcnt >> 2) & 0x3) * 0x4000;
+
+ int x = this.memory.Bgx[bg - 2];
+ int y = this.memory.Bgy[bg - 2];
+
+ short dx = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PA + (uint)(bg - 2) * 0x10);
+ short dy = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PC + (uint)(bg - 2) * 0x10);
+
+ bool transparent = (bgcnt & (1 << 13)) == 0;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if ((this.windowCover[i] & (1 << bg)) != 0)
+ {
+ int ax = x >> 8;
+ int ay = y >> 8;
+
+ if ((ax >= 0 && ax < width && ay >= 0 && ay < height) || !transparent)
+ {
+ int tmpTileIdx = (int)(screenBase + ((ay & (height - 1)) / 8) * (width / 8) + ((ax & (width - 1)) / 8));
+ int tileChar = vram[tmpTileIdx];
+
+ int lookup = vram[charBase + (tileChar * 64) + ((ay & 7) * 8) + (ax & 7)];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[lookup * 2] | (palette[lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i] & (1 << 5)) != 0)
+ {
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r + (((0xFF - r) * this.blendY) >> 4);
+ g = g + (((0xFF - g) * this.blendY) >> 4);
+ b = b + (((0xFF - b) * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+
+ x += dx;
+ y += dy;
+ }
+ }
+ private void RenderRotScaleBgWindowBrightDec(int bg)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ byte blendMaskType = (byte)(1 << bg);
+
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)bg);
+
+ int width = 0, height = 0;
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 0: width = 128; height = 128; break;
+ case 1: width = 256; height = 256; break;
+ case 2: width = 512; height = 512; break;
+ case 3: width = 1024; height = 1024; break;
+ }
+
+ int screenBase = ((bgcnt >> 8) & 0x1F) * 0x800;
+ int charBase = ((bgcnt >> 2) & 0x3) * 0x4000;
+
+ int x = this.memory.Bgx[bg - 2];
+ int y = this.memory.Bgy[bg - 2];
+
+ short dx = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PA + (uint)(bg - 2) * 0x10);
+ short dy = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PC + (uint)(bg - 2) * 0x10);
+
+ bool transparent = (bgcnt & (1 << 13)) == 0;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if ((this.windowCover[i] & (1 << bg)) != 0)
+ {
+ int ax = x >> 8;
+ int ay = y >> 8;
+
+ if ((ax >= 0 && ax < width && ay >= 0 && ay < height) || !transparent)
+ {
+ int tmpTileIdx = (int)(screenBase + ((ay & (height - 1)) / 8) * (width / 8) + ((ax & (width - 1)) / 8));
+ int tileChar = vram[tmpTileIdx];
+
+ int lookup = vram[charBase + (tileChar * 64) + ((ay & 7) * 8) + (ax & 7)];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[lookup * 2] | (palette[lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i] & (1 << 5)) != 0)
+ {
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r - ((r * this.blendY) >> 4);
+ g = g - ((g * this.blendY) >> 4);
+ b = b - ((b * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+
+ x += dx;
+ y += dy;
+ }
+ }
+ #endregion Rot/Scale Bg
+ #region Text Bg
+ private void RenderTextBgNormal(int bg)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ byte blendMaskType = (byte)(1 << bg);
+
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)bg);
+
+ int width = 0, height = 0;
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 0: width = 256; height = 256; break;
+ case 1: width = 512; height = 256; break;
+ case 2: width = 256; height = 512; break;
+ case 3: width = 512; height = 512; break;
+ }
+
+ int screenBase = ((bgcnt >> 8) & 0x1F) * 0x800;
+ int charBase = ((bgcnt >> 2) & 0x3) * 0x4000;
+
+ int hofs = Memory.ReadU16(this.memory.IORam, Memory.BG0HOFS + (uint)bg * 4) & 0x1FF;
+ int vofs = Memory.ReadU16(this.memory.IORam, Memory.BG0VOFS + (uint)bg * 4) & 0x1FF;
+
+ if ((bgcnt & (1 << 7)) != 0)
+ {
+ // 256 color tiles
+ int bgy = ((this.curLine + vofs) & (height - 1)) / 8;
+
+ int tileIdx = screenBase + (((bgy & 31) * 32) * 2);
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 2: if (bgy >= 32) tileIdx += 32 * 32 * 2; break;
+ case 3: if (bgy >= 32) tileIdx += 32 * 32 * 4; break;
+ }
+
+ int tileY = ((this.curLine + vofs) & 0x7) * 8;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if (true)
+ {
+ int bgx = ((i + hofs) & (width - 1)) / 8;
+ int tmpTileIdx = tileIdx + ((bgx & 31) * 2);
+ if (bgx >= 32) tmpTileIdx += 32 * 32 * 2;
+ int tileChar = vram[tmpTileIdx] | (vram[tmpTileIdx + 1] << 8);
+ int x = (i + hofs) & 7;
+ int y = tileY;
+ if ((tileChar & (1 << 10)) != 0) x = 7 - x;
+ if ((tileChar & (1 << 11)) != 0) y = 56 - y;
+ int lookup = vram[charBase + ((tileChar & 0x3FF) * 64) + y + x];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[lookup * 2] | (palette[lookup * 2 + 1] << 8)));
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+ }
+ else
+ {
+ // 16 color tiles
+ int bgy = ((this.curLine + vofs) & (height - 1)) / 8;
+
+ int tileIdx = screenBase + (((bgy & 31) * 32) * 2);
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 2: if (bgy >= 32) tileIdx += 32 * 32 * 2; break;
+ case 3: if (bgy >= 32) tileIdx += 32 * 32 * 4; break;
+ }
+
+ int tileY = ((this.curLine + vofs) & 0x7) * 4;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if (true)
+ {
+ int bgx = ((i + hofs) & (width - 1)) / 8;
+ int tmpTileIdx = tileIdx + ((bgx & 31) * 2);
+ if (bgx >= 32) tmpTileIdx += 32 * 32 * 2;
+ int tileChar = vram[tmpTileIdx] | (vram[tmpTileIdx + 1] << 8);
+ int x = (i + hofs) & 7;
+ int y = tileY;
+ if ((tileChar & (1 << 10)) != 0) x = 7 - x;
+ if ((tileChar & (1 << 11)) != 0) y = 28 - y;
+ int lookup = vram[charBase + ((tileChar & 0x3FF) * 32) + y + (x / 2)];
+ if ((x & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ int palNum = ((tileChar >> 12) & 0xf) * 16 * 2;
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palNum + lookup * 2] | (palette[palNum + lookup * 2 + 1] << 8)));
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+ }
+ }
+ private void RenderTextBgBlend(int bg)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ byte blendMaskType = (byte)(1 << bg);
+
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)bg);
+
+ int width = 0, height = 0;
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 0: width = 256; height = 256; break;
+ case 1: width = 512; height = 256; break;
+ case 2: width = 256; height = 512; break;
+ case 3: width = 512; height = 512; break;
+ }
+
+ int screenBase = ((bgcnt >> 8) & 0x1F) * 0x800;
+ int charBase = ((bgcnt >> 2) & 0x3) * 0x4000;
+
+ int hofs = Memory.ReadU16(this.memory.IORam, Memory.BG0HOFS + (uint)bg * 4) & 0x1FF;
+ int vofs = Memory.ReadU16(this.memory.IORam, Memory.BG0VOFS + (uint)bg * 4) & 0x1FF;
+
+ if ((bgcnt & (1 << 7)) != 0)
+ {
+ // 256 color tiles
+ int bgy = ((this.curLine + vofs) & (height - 1)) / 8;
+
+ int tileIdx = screenBase + (((bgy & 31) * 32) * 2);
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 2: if (bgy >= 32) tileIdx += 32 * 32 * 2; break;
+ case 3: if (bgy >= 32) tileIdx += 32 * 32 * 4; break;
+ }
+
+ int tileY = ((this.curLine + vofs) & 0x7) * 8;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if (true)
+ {
+ int bgx = ((i + hofs) & (width - 1)) / 8;
+ int tmpTileIdx = tileIdx + ((bgx & 31) * 2);
+ if (bgx >= 32) tmpTileIdx += 32 * 32 * 2;
+ int tileChar = vram[tmpTileIdx] | (vram[tmpTileIdx + 1] << 8);
+ int x = (i + hofs) & 7;
+ int y = tileY;
+ if ((tileChar & (1 << 10)) != 0) x = 7 - x;
+ if ((tileChar & (1 << 11)) != 0) y = 56 - y;
+ int lookup = vram[charBase + ((tileChar & 0x3FF) * 64) + y + x];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[lookup * 2] | (palette[lookup * 2 + 1] << 8)));
+ if ((this.blend[i] & this.blendTarget) != 0)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[i];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+ }
+ else
+ {
+ // 16 color tiles
+ int bgy = ((this.curLine + vofs) & (height - 1)) / 8;
+
+ int tileIdx = screenBase + (((bgy & 31) * 32) * 2);
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 2: if (bgy >= 32) tileIdx += 32 * 32 * 2; break;
+ case 3: if (bgy >= 32) tileIdx += 32 * 32 * 4; break;
+ }
+
+ int tileY = ((this.curLine + vofs) & 0x7) * 4;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if (true)
+ {
+ int bgx = ((i + hofs) & (width - 1)) / 8;
+ int tmpTileIdx = tileIdx + ((bgx & 31) * 2);
+ if (bgx >= 32) tmpTileIdx += 32 * 32 * 2;
+ int tileChar = vram[tmpTileIdx] | (vram[tmpTileIdx + 1] << 8);
+ int x = (i + hofs) & 7;
+ int y = tileY;
+ if ((tileChar & (1 << 10)) != 0) x = 7 - x;
+ if ((tileChar & (1 << 11)) != 0) y = 28 - y;
+ int lookup = vram[charBase + ((tileChar & 0x3FF) * 32) + y + (x / 2)];
+ if ((x & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ int palNum = ((tileChar >> 12) & 0xf) * 16 * 2;
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palNum + lookup * 2] | (palette[palNum + lookup * 2 + 1] << 8)));
+ if ((this.blend[i] & this.blendTarget) != 0)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[i];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+ }
+ }
+ private void RenderTextBgBrightInc(int bg)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ byte blendMaskType = (byte)(1 << bg);
+
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)bg);
+
+ int width = 0, height = 0;
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 0: width = 256; height = 256; break;
+ case 1: width = 512; height = 256; break;
+ case 2: width = 256; height = 512; break;
+ case 3: width = 512; height = 512; break;
+ }
+
+ int screenBase = ((bgcnt >> 8) & 0x1F) * 0x800;
+ int charBase = ((bgcnt >> 2) & 0x3) * 0x4000;
+
+ int hofs = Memory.ReadU16(this.memory.IORam, Memory.BG0HOFS + (uint)bg * 4) & 0x1FF;
+ int vofs = Memory.ReadU16(this.memory.IORam, Memory.BG0VOFS + (uint)bg * 4) & 0x1FF;
+
+ if ((bgcnt & (1 << 7)) != 0)
+ {
+ // 256 color tiles
+ int bgy = ((this.curLine + vofs) & (height - 1)) / 8;
+
+ int tileIdx = screenBase + (((bgy & 31) * 32) * 2);
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 2: if (bgy >= 32) tileIdx += 32 * 32 * 2; break;
+ case 3: if (bgy >= 32) tileIdx += 32 * 32 * 4; break;
+ }
+
+ int tileY = ((this.curLine + vofs) & 0x7) * 8;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if (true)
+ {
+ int bgx = ((i + hofs) & (width - 1)) / 8;
+ int tmpTileIdx = tileIdx + ((bgx & 31) * 2);
+ if (bgx >= 32) tmpTileIdx += 32 * 32 * 2;
+ int tileChar = vram[tmpTileIdx] | (vram[tmpTileIdx + 1] << 8);
+ int x = (i + hofs) & 7;
+ int y = tileY;
+ if ((tileChar & (1 << 10)) != 0) x = 7 - x;
+ if ((tileChar & (1 << 11)) != 0) y = 56 - y;
+ int lookup = vram[charBase + ((tileChar & 0x3FF) * 64) + y + x];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[lookup * 2] | (palette[lookup * 2 + 1] << 8)));
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r + (((0xFF - r) * this.blendY) >> 4);
+ g = g + (((0xFF - g) * this.blendY) >> 4);
+ b = b + (((0xFF - b) * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+ }
+ else
+ {
+ // 16 color tiles
+ int bgy = ((this.curLine + vofs) & (height - 1)) / 8;
+
+ int tileIdx = screenBase + (((bgy & 31) * 32) * 2);
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 2: if (bgy >= 32) tileIdx += 32 * 32 * 2; break;
+ case 3: if (bgy >= 32) tileIdx += 32 * 32 * 4; break;
+ }
+
+ int tileY = ((this.curLine + vofs) & 0x7) * 4;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if (true)
+ {
+ int bgx = ((i + hofs) & (width - 1)) / 8;
+ int tmpTileIdx = tileIdx + ((bgx & 31) * 2);
+ if (bgx >= 32) tmpTileIdx += 32 * 32 * 2;
+ int tileChar = vram[tmpTileIdx] | (vram[tmpTileIdx + 1] << 8);
+ int x = (i + hofs) & 7;
+ int y = tileY;
+ if ((tileChar & (1 << 10)) != 0) x = 7 - x;
+ if ((tileChar & (1 << 11)) != 0) y = 28 - y;
+ int lookup = vram[charBase + ((tileChar & 0x3FF) * 32) + y + (x / 2)];
+ if ((x & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ int palNum = ((tileChar >> 12) & 0xf) * 16 * 2;
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palNum + lookup * 2] | (palette[palNum + lookup * 2 + 1] << 8)));
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r + (((0xFF - r) * this.blendY) >> 4);
+ g = g + (((0xFF - g) * this.blendY) >> 4);
+ b = b + (((0xFF - b) * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+ }
+ }
+ private void RenderTextBgBrightDec(int bg)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ byte blendMaskType = (byte)(1 << bg);
+
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)bg);
+
+ int width = 0, height = 0;
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 0: width = 256; height = 256; break;
+ case 1: width = 512; height = 256; break;
+ case 2: width = 256; height = 512; break;
+ case 3: width = 512; height = 512; break;
+ }
+
+ int screenBase = ((bgcnt >> 8) & 0x1F) * 0x800;
+ int charBase = ((bgcnt >> 2) & 0x3) * 0x4000;
+
+ int hofs = Memory.ReadU16(this.memory.IORam, Memory.BG0HOFS + (uint)bg * 4) & 0x1FF;
+ int vofs = Memory.ReadU16(this.memory.IORam, Memory.BG0VOFS + (uint)bg * 4) & 0x1FF;
+
+ if ((bgcnt & (1 << 7)) != 0)
+ {
+ // 256 color tiles
+ int bgy = ((this.curLine + vofs) & (height - 1)) / 8;
+
+ int tileIdx = screenBase + (((bgy & 31) * 32) * 2);
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 2: if (bgy >= 32) tileIdx += 32 * 32 * 2; break;
+ case 3: if (bgy >= 32) tileIdx += 32 * 32 * 4; break;
+ }
+
+ int tileY = ((this.curLine + vofs) & 0x7) * 8;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if (true)
+ {
+ int bgx = ((i + hofs) & (width - 1)) / 8;
+ int tmpTileIdx = tileIdx + ((bgx & 31) * 2);
+ if (bgx >= 32) tmpTileIdx += 32 * 32 * 2;
+ int tileChar = vram[tmpTileIdx] | (vram[tmpTileIdx + 1] << 8);
+ int x = (i + hofs) & 7;
+ int y = tileY;
+ if ((tileChar & (1 << 10)) != 0) x = 7 - x;
+ if ((tileChar & (1 << 11)) != 0) y = 56 - y;
+ int lookup = vram[charBase + ((tileChar & 0x3FF) * 64) + y + x];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[lookup * 2] | (palette[lookup * 2 + 1] << 8)));
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r - ((r * this.blendY) >> 4);
+ g = g - ((g * this.blendY) >> 4);
+ b = b - ((b * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+ }
+ else
+ {
+ // 16 color tiles
+ int bgy = ((this.curLine + vofs) & (height - 1)) / 8;
+
+ int tileIdx = screenBase + (((bgy & 31) * 32) * 2);
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 2: if (bgy >= 32) tileIdx += 32 * 32 * 2; break;
+ case 3: if (bgy >= 32) tileIdx += 32 * 32 * 4; break;
+ }
+
+ int tileY = ((this.curLine + vofs) & 0x7) * 4;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if (true)
+ {
+ int bgx = ((i + hofs) & (width - 1)) / 8;
+ int tmpTileIdx = tileIdx + ((bgx & 31) * 2);
+ if (bgx >= 32) tmpTileIdx += 32 * 32 * 2;
+ int tileChar = vram[tmpTileIdx] | (vram[tmpTileIdx + 1] << 8);
+ int x = (i + hofs) & 7;
+ int y = tileY;
+ if ((tileChar & (1 << 10)) != 0) x = 7 - x;
+ if ((tileChar & (1 << 11)) != 0) y = 28 - y;
+ int lookup = vram[charBase + ((tileChar & 0x3FF) * 32) + y + (x / 2)];
+ if ((x & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ int palNum = ((tileChar >> 12) & 0xf) * 16 * 2;
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palNum + lookup * 2] | (palette[palNum + lookup * 2 + 1] << 8)));
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r - ((r * this.blendY) >> 4);
+ g = g - ((g * this.blendY) >> 4);
+ b = b - ((b * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+ }
+ }
+ private void RenderTextBgWindow(int bg)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ byte blendMaskType = (byte)(1 << bg);
+
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)bg);
+
+ int width = 0, height = 0;
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 0: width = 256; height = 256; break;
+ case 1: width = 512; height = 256; break;
+ case 2: width = 256; height = 512; break;
+ case 3: width = 512; height = 512; break;
+ }
+
+ int screenBase = ((bgcnt >> 8) & 0x1F) * 0x800;
+ int charBase = ((bgcnt >> 2) & 0x3) * 0x4000;
+
+ int hofs = Memory.ReadU16(this.memory.IORam, Memory.BG0HOFS + (uint)bg * 4) & 0x1FF;
+ int vofs = Memory.ReadU16(this.memory.IORam, Memory.BG0VOFS + (uint)bg * 4) & 0x1FF;
+
+ if ((bgcnt & (1 << 7)) != 0)
+ {
+ // 256 color tiles
+ int bgy = ((this.curLine + vofs) & (height - 1)) / 8;
+
+ int tileIdx = screenBase + (((bgy & 31) * 32) * 2);
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 2: if (bgy >= 32) tileIdx += 32 * 32 * 2; break;
+ case 3: if (bgy >= 32) tileIdx += 32 * 32 * 4; break;
+ }
+
+ int tileY = ((this.curLine + vofs) & 0x7) * 8;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if ((this.windowCover[i] & (1 << bg)) != 0)
+ {
+ int bgx = ((i + hofs) & (width - 1)) / 8;
+ int tmpTileIdx = tileIdx + ((bgx & 31) * 2);
+ if (bgx >= 32) tmpTileIdx += 32 * 32 * 2;
+ int tileChar = vram[tmpTileIdx] | (vram[tmpTileIdx + 1] << 8);
+ int x = (i + hofs) & 7;
+ int y = tileY;
+ if ((tileChar & (1 << 10)) != 0) x = 7 - x;
+ if ((tileChar & (1 << 11)) != 0) y = 56 - y;
+ int lookup = vram[charBase + ((tileChar & 0x3FF) * 64) + y + x];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[lookup * 2] | (palette[lookup * 2 + 1] << 8)));
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+ }
+ else
+ {
+ // 16 color tiles
+ int bgy = ((this.curLine + vofs) & (height - 1)) / 8;
+
+ int tileIdx = screenBase + (((bgy & 31) * 32) * 2);
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 2: if (bgy >= 32) tileIdx += 32 * 32 * 2; break;
+ case 3: if (bgy >= 32) tileIdx += 32 * 32 * 4; break;
+ }
+
+ int tileY = ((this.curLine + vofs) & 0x7) * 4;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if ((this.windowCover[i] & (1 << bg)) != 0)
+ {
+ int bgx = ((i + hofs) & (width - 1)) / 8;
+ int tmpTileIdx = tileIdx + ((bgx & 31) * 2);
+ if (bgx >= 32) tmpTileIdx += 32 * 32 * 2;
+ int tileChar = vram[tmpTileIdx] | (vram[tmpTileIdx + 1] << 8);
+ int x = (i + hofs) & 7;
+ int y = tileY;
+ if ((tileChar & (1 << 10)) != 0) x = 7 - x;
+ if ((tileChar & (1 << 11)) != 0) y = 28 - y;
+ int lookup = vram[charBase + ((tileChar & 0x3FF) * 32) + y + (x / 2)];
+ if ((x & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ int palNum = ((tileChar >> 12) & 0xf) * 16 * 2;
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palNum + lookup * 2] | (palette[palNum + lookup * 2 + 1] << 8)));
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+ }
+ }
+ private void RenderTextBgWindowBlend(int bg)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ byte blendMaskType = (byte)(1 << bg);
+
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)bg);
+
+ int width = 0, height = 0;
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 0: width = 256; height = 256; break;
+ case 1: width = 512; height = 256; break;
+ case 2: width = 256; height = 512; break;
+ case 3: width = 512; height = 512; break;
+ }
+
+ int screenBase = ((bgcnt >> 8) & 0x1F) * 0x800;
+ int charBase = ((bgcnt >> 2) & 0x3) * 0x4000;
+
+ int hofs = Memory.ReadU16(this.memory.IORam, Memory.BG0HOFS + (uint)bg * 4) & 0x1FF;
+ int vofs = Memory.ReadU16(this.memory.IORam, Memory.BG0VOFS + (uint)bg * 4) & 0x1FF;
+
+ if ((bgcnt & (1 << 7)) != 0)
+ {
+ // 256 color tiles
+ int bgy = ((this.curLine + vofs) & (height - 1)) / 8;
+
+ int tileIdx = screenBase + (((bgy & 31) * 32) * 2);
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 2: if (bgy >= 32) tileIdx += 32 * 32 * 2; break;
+ case 3: if (bgy >= 32) tileIdx += 32 * 32 * 4; break;
+ }
+
+ int tileY = ((this.curLine + vofs) & 0x7) * 8;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if ((this.windowCover[i] & (1 << bg)) != 0)
+ {
+ int bgx = ((i + hofs) & (width - 1)) / 8;
+ int tmpTileIdx = tileIdx + ((bgx & 31) * 2);
+ if (bgx >= 32) tmpTileIdx += 32 * 32 * 2;
+ int tileChar = vram[tmpTileIdx] | (vram[tmpTileIdx + 1] << 8);
+ int x = (i + hofs) & 7;
+ int y = tileY;
+ if ((tileChar & (1 << 10)) != 0) x = 7 - x;
+ if ((tileChar & (1 << 11)) != 0) y = 56 - y;
+ int lookup = vram[charBase + ((tileChar & 0x3FF) * 64) + y + x];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[lookup * 2] | (palette[lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i] & this.blendTarget) != 0)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[i];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+ }
+ else
+ {
+ // 16 color tiles
+ int bgy = ((this.curLine + vofs) & (height - 1)) / 8;
+
+ int tileIdx = screenBase + (((bgy & 31) * 32) * 2);
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 2: if (bgy >= 32) tileIdx += 32 * 32 * 2; break;
+ case 3: if (bgy >= 32) tileIdx += 32 * 32 * 4; break;
+ }
+
+ int tileY = ((this.curLine + vofs) & 0x7) * 4;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if ((this.windowCover[i] & (1 << bg)) != 0)
+ {
+ int bgx = ((i + hofs) & (width - 1)) / 8;
+ int tmpTileIdx = tileIdx + ((bgx & 31) * 2);
+ if (bgx >= 32) tmpTileIdx += 32 * 32 * 2;
+ int tileChar = vram[tmpTileIdx] | (vram[tmpTileIdx + 1] << 8);
+ int x = (i + hofs) & 7;
+ int y = tileY;
+ if ((tileChar & (1 << 10)) != 0) x = 7 - x;
+ if ((tileChar & (1 << 11)) != 0) y = 28 - y;
+ int lookup = vram[charBase + ((tileChar & 0x3FF) * 32) + y + (x / 2)];
+ if ((x & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ int palNum = ((tileChar >> 12) & 0xf) * 16 * 2;
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palNum + lookup * 2] | (palette[palNum + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i] & (1 << 5)) != 0)
+ {
+ if ((this.blend[i] & this.blendTarget) != 0)
+ {
+ uint r = ((pixelColor & 0xFF) * this.blendA) >> 4;
+ uint g = (((pixelColor >> 8) & 0xFF) * this.blendA) >> 4;
+ uint b = (((pixelColor >> 16) & 0xFF) * this.blendA) >> 4;
+ uint sourceValue = this.scanline[i];
+ r += ((sourceValue & 0xFF) * this.blendB) >> 4;
+ g += (((sourceValue >> 8) & 0xFF) * this.blendB) >> 4;
+ b += (((sourceValue >> 16) & 0xFF) * this.blendB) >> 4;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ }
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+ }
+ }
+ private void RenderTextBgWindowBrightInc(int bg)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ byte blendMaskType = (byte)(1 << bg);
+
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)bg);
+
+ int width = 0, height = 0;
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 0: width = 256; height = 256; break;
+ case 1: width = 512; height = 256; break;
+ case 2: width = 256; height = 512; break;
+ case 3: width = 512; height = 512; break;
+ }
+
+ int screenBase = ((bgcnt >> 8) & 0x1F) * 0x800;
+ int charBase = ((bgcnt >> 2) & 0x3) * 0x4000;
+
+ int hofs = Memory.ReadU16(this.memory.IORam, Memory.BG0HOFS + (uint)bg * 4) & 0x1FF;
+ int vofs = Memory.ReadU16(this.memory.IORam, Memory.BG0VOFS + (uint)bg * 4) & 0x1FF;
+
+ if ((bgcnt & (1 << 7)) != 0)
+ {
+ // 256 color tiles
+ int bgy = ((this.curLine + vofs) & (height - 1)) / 8;
+
+ int tileIdx = screenBase + (((bgy & 31) * 32) * 2);
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 2: if (bgy >= 32) tileIdx += 32 * 32 * 2; break;
+ case 3: if (bgy >= 32) tileIdx += 32 * 32 * 4; break;
+ }
+
+ int tileY = ((this.curLine + vofs) & 0x7) * 8;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if ((this.windowCover[i] & (1 << bg)) != 0)
+ {
+ int bgx = ((i + hofs) & (width - 1)) / 8;
+ int tmpTileIdx = tileIdx + ((bgx & 31) * 2);
+ if (bgx >= 32) tmpTileIdx += 32 * 32 * 2;
+ int tileChar = vram[tmpTileIdx] | (vram[tmpTileIdx + 1] << 8);
+ int x = (i + hofs) & 7;
+ int y = tileY;
+ if ((tileChar & (1 << 10)) != 0) x = 7 - x;
+ if ((tileChar & (1 << 11)) != 0) y = 56 - y;
+ int lookup = vram[charBase + ((tileChar & 0x3FF) * 64) + y + x];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[lookup * 2] | (palette[lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i] & (1 << 5)) != 0)
+ {
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r + (((0xFF - r) * this.blendY) >> 4);
+ g = g + (((0xFF - g) * this.blendY) >> 4);
+ b = b + (((0xFF - b) * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+ }
+ else
+ {
+ // 16 color tiles
+ int bgy = ((this.curLine + vofs) & (height - 1)) / 8;
+
+ int tileIdx = screenBase + (((bgy & 31) * 32) * 2);
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 2: if (bgy >= 32) tileIdx += 32 * 32 * 2; break;
+ case 3: if (bgy >= 32) tileIdx += 32 * 32 * 4; break;
+ }
+
+ int tileY = ((this.curLine + vofs) & 0x7) * 4;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if ((this.windowCover[i] & (1 << bg)) != 0)
+ {
+ int bgx = ((i + hofs) & (width - 1)) / 8;
+ int tmpTileIdx = tileIdx + ((bgx & 31) * 2);
+ if (bgx >= 32) tmpTileIdx += 32 * 32 * 2;
+ int tileChar = vram[tmpTileIdx] | (vram[tmpTileIdx + 1] << 8);
+ int x = (i + hofs) & 7;
+ int y = tileY;
+ if ((tileChar & (1 << 10)) != 0) x = 7 - x;
+ if ((tileChar & (1 << 11)) != 0) y = 28 - y;
+ int lookup = vram[charBase + ((tileChar & 0x3FF) * 32) + y + (x / 2)];
+ if ((x & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ int palNum = ((tileChar >> 12) & 0xf) * 16 * 2;
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palNum + lookup * 2] | (palette[palNum + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i] & (1 << 5)) != 0)
+ {
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r + (((0xFF - r) * this.blendY) >> 4);
+ g = g + (((0xFF - g) * this.blendY) >> 4);
+ b = b + (((0xFF - b) * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+ }
+ }
+ private void RenderTextBgWindowBrightDec(int bg)
+ {
+ byte[] palette = this.memory.PaletteRam;
+ byte[] vram = this.memory.VideoRam;
+
+ byte blendMaskType = (byte)(1 << bg);
+
+ ushort bgcnt = Memory.ReadU16(this.memory.IORam, Memory.BG0CNT + 0x2 * (uint)bg);
+
+ int width = 0, height = 0;
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 0: width = 256; height = 256; break;
+ case 1: width = 512; height = 256; break;
+ case 2: width = 256; height = 512; break;
+ case 3: width = 512; height = 512; break;
+ }
+
+ int screenBase = ((bgcnt >> 8) & 0x1F) * 0x800;
+ int charBase = ((bgcnt >> 2) & 0x3) * 0x4000;
+
+ int hofs = Memory.ReadU16(this.memory.IORam, Memory.BG0HOFS + (uint)bg * 4) & 0x1FF;
+ int vofs = Memory.ReadU16(this.memory.IORam, Memory.BG0VOFS + (uint)bg * 4) & 0x1FF;
+
+ if ((bgcnt & (1 << 7)) != 0)
+ {
+ // 256 color tiles
+ int bgy = ((this.curLine + vofs) & (height - 1)) / 8;
+
+ int tileIdx = screenBase + (((bgy & 31) * 32) * 2);
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 2: if (bgy >= 32) tileIdx += 32 * 32 * 2; break;
+ case 3: if (bgy >= 32) tileIdx += 32 * 32 * 4; break;
+ }
+
+ int tileY = ((this.curLine + vofs) & 0x7) * 8;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if ((this.windowCover[i] & (1 << bg)) != 0)
+ {
+ int bgx = ((i + hofs) & (width - 1)) / 8;
+ int tmpTileIdx = tileIdx + ((bgx & 31) * 2);
+ if (bgx >= 32) tmpTileIdx += 32 * 32 * 2;
+ int tileChar = vram[tmpTileIdx] | (vram[tmpTileIdx + 1] << 8);
+ int x = (i + hofs) & 7;
+ int y = tileY;
+ if ((tileChar & (1 << 10)) != 0) x = 7 - x;
+ if ((tileChar & (1 << 11)) != 0) y = 56 - y;
+ int lookup = vram[charBase + ((tileChar & 0x3FF) * 64) + y + x];
+ if (lookup != 0)
+ {
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[lookup * 2] | (palette[lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i] & (1 << 5)) != 0)
+ {
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r - ((r * this.blendY) >> 4);
+ g = g - ((g * this.blendY) >> 4);
+ b = b - ((b * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+ }
+ else
+ {
+ // 16 color tiles
+ int bgy = ((this.curLine + vofs) & (height - 1)) / 8;
+
+ int tileIdx = screenBase + (((bgy & 31) * 32) * 2);
+ switch ((bgcnt >> 14) & 0x3)
+ {
+ case 2: if (bgy >= 32) tileIdx += 32 * 32 * 2; break;
+ case 3: if (bgy >= 32) tileIdx += 32 * 32 * 4; break;
+ }
+
+ int tileY = ((this.curLine + vofs) & 0x7) * 4;
+
+ for (int i = 0; i < 240; i++)
+ {
+ if ((this.windowCover[i] & (1 << bg)) != 0)
+ {
+ int bgx = ((i + hofs) & (width - 1)) / 8;
+ int tmpTileIdx = tileIdx + ((bgx & 31) * 2);
+ if (bgx >= 32) tmpTileIdx += 32 * 32 * 2;
+ int tileChar = vram[tmpTileIdx] | (vram[tmpTileIdx + 1] << 8);
+ int x = (i + hofs) & 7;
+ int y = tileY;
+ if ((tileChar & (1 << 10)) != 0) x = 7 - x;
+ if ((tileChar & (1 << 11)) != 0) y = 28 - y;
+ int lookup = vram[charBase + ((tileChar & 0x3FF) * 32) + y + (x / 2)];
+ if ((x & 1) == 0)
+ {
+ lookup &= 0xf;
+ }
+ else
+ {
+ lookup >>= 4;
+ }
+ if (lookup != 0)
+ {
+ int palNum = ((tileChar >> 12) & 0xf) * 16 * 2;
+ uint pixelColor = Renderer.GbaTo32((ushort)(palette[palNum + lookup * 2] | (palette[palNum + lookup * 2 + 1] << 8)));
+ if ((this.windowCover[i] & (1 << 5)) != 0)
+ {
+ uint r = pixelColor & 0xFF;
+ uint g = (pixelColor >> 8) & 0xFF;
+ uint b = (pixelColor >> 16) & 0xFF;
+ r = r - ((r * this.blendY) >> 4);
+ g = g - ((g * this.blendY) >> 4);
+ b = b - ((b * this.blendY) >> 4);
+ pixelColor = r | (g << 8) | (b << 16);
+ }
+ this.scanline[i] = pixelColor; this.blend[i] = blendMaskType;
+
+ }
+ }
+ }
+ }
+ }
+ #endregion Text Bg
+ }
+}
diff --git a/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/SoundManager.cs b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/SoundManager.cs
new file mode 100644
index 0000000000..5679202345
--- /dev/null
+++ b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/SoundManager.cs
@@ -0,0 +1,191 @@
+namespace GarboDev
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Text;
+
+ public class SoundManager
+ {
+ private Memory memory = null;
+ private Queue[] soundQueue = new Queue[2];
+ private byte latchedA, latchedB;
+ private int frequency, cyclesPerSample;
+ private int leftover = 0;
+
+ private short[] soundBuffer = new short[40000];
+ private int soundBufferPos = 0;
+ private int lastSoundBufferPos = 0;
+
+ public SoundManager(Memory memory, int frequency)
+ {
+ this.Frequency = frequency;
+
+ this.memory = memory;
+ this.memory.SoundManager = this;
+
+ this.soundQueue[0] = new Queue(32);
+ this.soundQueue[1] = new Queue(32);
+ }
+
+ #region Public Properties
+ public int Frequency
+ {
+ get { return this.frequency; }
+ set
+ {
+ this.frequency = value;
+ this.cyclesPerSample = (GbaManager.cpuFreq << 5) / this.frequency;
+ }
+ }
+
+ public int QueueSizeA
+ {
+ get { return this.soundQueue[0].Count; }
+ }
+
+ public int QueueSizeB
+ {
+ get { return this.soundQueue[1].Count; }
+ }
+
+ public int SamplesMixed
+ {
+ get
+ {
+ int value = this.soundBufferPos - this.lastSoundBufferPos;
+ if (value < 0) value += this.soundBuffer.Length;
+ return value;
+ }
+ }
+ #endregion
+
+ #region Public Methods
+ public void GetSamples(short[] buffer, int length)
+ {
+ for (int i = 0; i < length; i++)
+ {
+ if (this.lastSoundBufferPos == this.soundBuffer.Length)
+ {
+ this.lastSoundBufferPos = 0;
+ }
+ buffer[i] = this.soundBuffer[this.lastSoundBufferPos++];
+ }
+ }
+
+ public void Mix(int cycles)
+ {
+ ushort soundCntH = Memory.ReadU16(this.memory.IORam, Memory.SOUNDCNT_H);
+ ushort soundCntX = Memory.ReadU16(this.memory.IORam, Memory.SOUNDCNT_X);
+
+ cycles <<= 5;
+ cycles += this.leftover;
+
+ if (cycles > 0)
+ {
+ // Precompute loop invariants
+ short directA = (short)(sbyte)(this.latchedA);
+ short directB = (short)(sbyte)(this.latchedB);
+
+ if ((soundCntH & (1 << 2)) == 0)
+ {
+ directA >>= 1;
+ }
+ if ((soundCntH & (1 << 3)) == 0)
+ {
+ directB >>= 1;
+ }
+
+ while (cycles > 0)
+ {
+ short l = 0, r = 0;
+
+ cycles -= this.cyclesPerSample;
+
+ // Mixing
+ if ((soundCntX & (1 << 7)) != 0)
+ {
+ if ((soundCntH & (1 << 8)) != 0)
+ {
+ r += directA;
+ }
+ if ((soundCntH & (1 << 9)) != 0)
+ {
+ l += directA;
+ }
+ if ((soundCntH & (1 << 12)) != 0)
+ {
+ r += directB;
+ }
+ if ((soundCntH & (1 << 13)) != 0)
+ {
+ l += directB;
+ }
+ }
+
+ if (this.soundBufferPos == this.soundBuffer.Length)
+ {
+ this.soundBufferPos = 0;
+ }
+
+ this.soundBuffer[this.soundBufferPos++] = (short)(l << 6);
+ this.soundBuffer[this.soundBufferPos++] = (short)(r << 6);
+ }
+ }
+
+ this.leftover = cycles;
+ }
+
+ public void ResetFifoA()
+ {
+ this.soundQueue[0].Clear();
+ this.latchedA = 0;
+ }
+
+ public void ResetFifoB()
+ {
+ this.soundQueue[1].Clear();
+ this.latchedB = 0;
+ }
+
+ public void IncrementFifoA()
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ this.EnqueueDSoundSample(0, this.memory.IORam[Memory.FIFO_A_L + i]);
+ }
+ }
+
+ public void IncrementFifoB()
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ this.EnqueueDSoundSample(1, this.memory.IORam[Memory.FIFO_B_L + i]);
+ }
+ }
+
+ public void DequeueA()
+ {
+ if (this.soundQueue[0].Count > 0)
+ {
+ this.latchedA = this.soundQueue[0].Dequeue();
+ }
+ }
+
+ public void DequeueB()
+ {
+ if (this.soundQueue[1].Count > 0)
+ {
+ this.latchedB = this.soundQueue[1].Dequeue();
+ }
+ }
+ #endregion Public Methods
+
+ private void EnqueueDSoundSample(int channel, byte sample)
+ {
+ if (this.soundQueue[channel].Count < 32)
+ {
+ this.soundQueue[channel].Enqueue(sample);
+ }
+ }
+ }
+}
diff --git a/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/ThumbCore.cs b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/ThumbCore.cs
new file mode 100644
index 0000000000..ca17f233c2
--- /dev/null
+++ b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/ThumbCore.cs
@@ -0,0 +1,981 @@
+//#define ARM_DEBUG
+
+namespace GarboDev
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Text;
+
+ public class ThumbCore
+ {
+ private const int COND_EQ = 0; // Z set
+ private const int COND_NE = 1; // Z clear
+ private const int COND_CS = 2; // C set
+ private const int COND_CC = 3; // C clear
+ private const int COND_MI = 4; // N set
+ private const int COND_PL = 5; // N clear
+ private const int COND_VS = 6; // V set
+ private const int COND_VC = 7; // V clear
+ private const int COND_HI = 8; // C set and Z clear
+ private const int COND_LS = 9; // C clear or Z set
+ private const int COND_GE = 10; // N equals V
+ private const int COND_LT = 11; // N not equal to V
+ private const int COND_GT = 12; // Z clear AND (N equals V)
+ private const int COND_LE = 13; // Z set OR (N not equal to V)
+ private const int COND_AL = 14; // Always
+ private const int COND_NV = 15; // Never execute
+
+ private const int OP_AND = 0x0;
+ private const int OP_EOR = 0x1;
+ private const int OP_LSL = 0x2;
+ private const int OP_LSR = 0x3;
+ private const int OP_ASR = 0x4;
+ private const int OP_ADC = 0x5;
+ private const int OP_SBC = 0x6;
+ private const int OP_ROR = 0x7;
+ private const int OP_TST = 0x8;
+ private const int OP_NEG = 0x9;
+ private const int OP_CMP = 0xA;
+ private const int OP_CMN = 0xB;
+ private const int OP_ORR = 0xC;
+ private const int OP_MUL = 0xD;
+ private const int OP_BIC = 0xE;
+ private const int OP_MVN = 0xF;
+
+ private Arm7Processor parent;
+ private Memory memory;
+ private uint[] registers;
+
+ // CPU flags
+ private uint zero, carry, negative, overflow;
+ private ushort curInstruction, instructionQueue;
+
+ private delegate void ExecuteInstruction();
+ private ExecuteInstruction[] NormalOps = null;
+
+ public ThumbCore(Arm7Processor parent, Memory memory)
+ {
+ this.parent = parent;
+ this.memory = memory;
+ this.registers = this.parent.Registers;
+
+ this.NormalOps = new ExecuteInstruction[256]
+ {
+ OpLslImm, OpLslImm, OpLslImm, OpLslImm, OpLslImm, OpLslImm, OpLslImm, OpLslImm,
+ OpLsrImm, OpLsrImm, OpLsrImm, OpLsrImm, OpLsrImm, OpLsrImm, OpLsrImm, OpLsrImm,
+ OpAsrImm, OpAsrImm, OpAsrImm, OpAsrImm, OpAsrImm, OpAsrImm, OpAsrImm, OpAsrImm,
+ OpAddRegReg, OpAddRegReg, OpSubRegReg, OpSubRegReg, OpAddRegImm, OpAddRegImm, OpSubRegImm, OpSubRegImm,
+ OpMovImm, OpMovImm, OpMovImm, OpMovImm, OpMovImm, OpMovImm, OpMovImm, OpMovImm,
+ OpCmpImm, OpCmpImm, OpCmpImm, OpCmpImm, OpCmpImm, OpCmpImm, OpCmpImm, OpCmpImm,
+ OpAddImm, OpAddImm, OpAddImm, OpAddImm, OpAddImm, OpAddImm, OpAddImm, OpAddImm,
+ OpSubImm, OpSubImm, OpSubImm, OpSubImm, OpSubImm, OpSubImm, OpSubImm, OpSubImm,
+ OpArith, OpArith, OpArith, OpArith, OpAddHi, OpCmpHi, OpMovHi, OpBx,
+ OpLdrPc, OpLdrPc, OpLdrPc, OpLdrPc, OpLdrPc, OpLdrPc, OpLdrPc, OpLdrPc,
+ OpStrReg, OpStrReg, OpStrhReg, OpStrhReg, OpStrbReg, OpStrbReg, OpLdrsbReg, OpLdrsbReg,
+ OpLdrReg, OpLdrReg, OpLdrhReg, OpLdrhReg, OpLdrbReg, OpLdrbReg, OpLdrshReg, OpLdrshReg,
+ OpStrImm, OpStrImm, OpStrImm, OpStrImm, OpStrImm, OpStrImm, OpStrImm, OpStrImm,
+ OpLdrImm, OpLdrImm, OpLdrImm, OpLdrImm, OpLdrImm, OpLdrImm, OpLdrImm, OpLdrImm,
+ OpStrbImm, OpStrbImm, OpStrbImm, OpStrbImm, OpStrbImm, OpStrbImm, OpStrbImm, OpStrbImm,
+ OpLdrbImm, OpLdrbImm, OpLdrbImm, OpLdrbImm, OpLdrbImm, OpLdrbImm, OpLdrbImm, OpLdrbImm,
+ OpStrhImm, OpStrhImm, OpStrhImm, OpStrhImm, OpStrhImm, OpStrhImm, OpStrhImm, OpStrhImm,
+ OpLdrhImm, OpLdrhImm, OpLdrhImm, OpLdrhImm, OpLdrhImm, OpLdrhImm, OpLdrhImm, OpLdrhImm,
+ OpStrSp, OpStrSp, OpStrSp, OpStrSp, OpStrSp, OpStrSp, OpStrSp, OpStrSp,
+ OpLdrSp, OpLdrSp, OpLdrSp, OpLdrSp, OpLdrSp, OpLdrSp, OpLdrSp, OpLdrSp,
+ OpAddPc, OpAddPc, OpAddPc, OpAddPc, OpAddPc, OpAddPc, OpAddPc, OpAddPc,
+ OpAddSp, OpAddSp, OpAddSp, OpAddSp, OpAddSp, OpAddSp, OpAddSp, OpAddSp,
+ OpSubSp, OpUnd, OpUnd, OpUnd, OpPush, OpPushLr, OpUnd, OpUnd,
+ OpUnd, OpUnd, OpUnd, OpUnd, OpPop, OpPopPc, OpUnd, OpUnd,
+ OpStmia, OpStmia, OpStmia, OpStmia, OpStmia, OpStmia, OpStmia, OpStmia,
+ OpLdmia, OpLdmia, OpLdmia, OpLdmia, OpLdmia, OpLdmia, OpLdmia, OpLdmia,
+ OpBCond, OpBCond, OpBCond, OpBCond, OpBCond, OpBCond, OpBCond, OpBCond,
+ OpBCond, OpBCond, OpBCond, OpBCond, OpBCond, OpBCond, OpUnd, OpSwi,
+ OpB, OpB, OpB, OpB, OpB, OpB, OpB, OpB,
+ OpUnd, OpUnd, OpUnd, OpUnd, OpUnd, OpUnd, OpUnd, OpUnd,
+ OpBl1, OpBl1, OpBl1, OpBl1, OpBl1, OpBl1, OpBl1, OpBl1,
+ OpBl2, OpBl2, OpBl2, OpBl2, OpBl2, OpBl2, OpBl2, OpBl2
+ };
+ }
+
+ public void BeginExecution()
+ {
+ this.FlushQueue();
+ }
+
+ public void Step()
+ {
+ this.UnpackFlags();
+
+ this.curInstruction = this.instructionQueue;
+ this.instructionQueue = this.memory.ReadU16(registers[15]);
+ registers[15] += 2;
+
+ // Execute the instruction
+ this.NormalOps[this.curInstruction >> 8]();
+
+ this.parent.Cycles -= this.memory.WaitCycles;
+
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) != Arm7Processor.T_MASK)
+ {
+ if ((this.curInstruction >> 8) != 0xDF) this.parent.ReloadQueue();
+ }
+
+ this.PackFlags();
+ }
+
+ public void Execute()
+ {
+ this.UnpackFlags();
+
+ while (this.parent.Cycles > 0)
+ {
+ this.curInstruction = this.instructionQueue;
+ this.instructionQueue = this.memory.ReadU16(registers[15]);
+ registers[15] += 2;
+
+ // Execute the instruction
+ this.NormalOps[this.curInstruction >> 8]();
+
+ this.parent.Cycles -= this.memory.WaitCycles;
+
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) != Arm7Processor.T_MASK)
+ {
+ if ((this.curInstruction >> 8) != 0xDF) this.parent.ReloadQueue();
+ break;
+ }
+
+ // Check the current PC
+#if ARM_DEBUG
+ if (this.parent.Breakpoints.ContainsKey(registers[15] - 2U))
+ {
+ this.parent.BreakpointHit = true;
+ break;
+ }
+#endif
+ }
+
+ this.PackFlags();
+ }
+
+ #region Flag helpers
+ public void OverflowCarryAdd(uint a, uint b, uint r)
+ {
+ overflow = ((a & b & ~r) | (~a & ~b & r)) >> 31;
+ carry = ((a & b) | (a & ~r) | (b & ~r)) >> 31;
+ }
+
+ public void OverflowCarrySub(uint a, uint b, uint r)
+ {
+ overflow = ((a & ~b & ~r) | (~a & b & r)) >> 31;
+ carry = ((a & ~b) | (a & ~r) | (~b & ~r)) >> 31;
+ }
+ #endregion
+
+ #region Opcodes
+ private void OpLslImm()
+ {
+ // 0x00 - 0x07
+ // lsl rd, rm, #immed
+ int rd = this.curInstruction & 0x7;
+ int rm = (this.curInstruction >> 3) & 0x7;
+ int immed = (this.curInstruction >> 6) & 0x1F;
+
+ if (immed == 0)
+ {
+ registers[rd] = registers[rm];
+ } else
+ {
+ carry = (registers[rm] >> (32 - immed)) & 0x1;
+ registers[rd] = registers[rm] << immed;
+ }
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ }
+
+ private void OpLsrImm()
+ {
+ // 0x08 - 0x0F
+ // lsr rd, rm, #immed
+ int rd = this.curInstruction & 0x7;
+ int rm = (this.curInstruction >> 3) & 0x7;
+ int immed = (this.curInstruction >> 6) & 0x1F;
+
+ if (immed == 0)
+ {
+ carry = registers[rm] >> 31;
+ registers[rd] = 0;
+ }
+ else
+ {
+ carry = (registers[rm] >> (immed - 1)) & 0x1;
+ registers[rd] = registers[rm] >> immed;
+ }
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ }
+
+ private void OpAsrImm()
+ {
+ // asr rd, rm, #immed
+ int rd = this.curInstruction & 0x7;
+ int rm = (this.curInstruction >> 3) & 0x7;
+ int immed = (this.curInstruction >> 6) & 0x1F;
+
+ if (immed == 0)
+ {
+ carry = registers[rm] >> 31;
+ if (carry == 1) registers[rd] = 0xFFFFFFFF;
+ else registers[rd] = 0;
+ }
+ else
+ {
+ carry = (registers[rm] >> (immed - 1)) & 0x1;
+ registers[rd] = (uint)(((int)registers[rm]) >> immed);
+ }
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ }
+
+ private void OpAddRegReg()
+ {
+ // add rd, rn, rm
+ int rd = this.curInstruction & 0x7;
+ int rn = (this.curInstruction >> 3) & 0x7;
+ int rm = (this.curInstruction >> 6) & 0x7;
+
+ uint orn = registers[rn];
+ uint orm = registers[rm];
+
+ registers[rd] = orn + orm;
+
+ this.OverflowCarryAdd(orn, orm, registers[rd]);
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ }
+
+ private void OpSubRegReg()
+ {
+ // sub rd, rn, rm
+ int rd = this.curInstruction & 0x7;
+ int rn = (this.curInstruction >> 3) & 0x7;
+ int rm = (this.curInstruction >> 6) & 0x7;
+
+ uint orn = registers[rn];
+ uint orm = registers[rm];
+
+ registers[rd] = orn - orm;
+
+ this.OverflowCarrySub(orn, orm, registers[rd]);
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ }
+
+ private void OpAddRegImm()
+ {
+ // add rd, rn, #immed
+ int rd = this.curInstruction & 0x7;
+ int rn = (this.curInstruction >> 3) & 0x7;
+ uint immed = (uint)((this.curInstruction >> 6) & 0x7);
+
+ uint orn = registers[rn];
+
+ registers[rd] = orn + immed;
+
+ this.OverflowCarryAdd(orn, immed, registers[rd]);
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ }
+
+ private void OpSubRegImm()
+ {
+ // sub rd, rn, #immed
+ int rd = this.curInstruction & 0x7;
+ int rn = (this.curInstruction >> 3) & 0x7;
+ uint immed = (uint)((this.curInstruction >> 6) & 0x7);
+
+ uint orn = registers[rn];
+
+ registers[rd] = orn - immed;
+
+ this.OverflowCarrySub(orn, immed, registers[rd]);
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ }
+
+ private void OpMovImm()
+ {
+ // mov rd, #immed
+ int rd = (this.curInstruction >> 8) & 0x7;
+
+ registers[rd] = (uint)(this.curInstruction & 0xFF);
+
+ negative = 0;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ }
+
+ private void OpCmpImm()
+ {
+ // cmp rn, #immed
+ int rn = (this.curInstruction >> 8) & 0x7;
+
+ uint alu = registers[rn] - (uint)(this.curInstruction & 0xFF);
+
+ this.OverflowCarrySub(registers[rn], (uint)(this.curInstruction & 0xFF), alu);
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ }
+
+ private void OpAddImm()
+ {
+ // add rd, #immed
+ int rd = (this.curInstruction >> 8) & 0x7;
+
+ uint ord = registers[rd];
+
+ registers[rd] += (uint)(this.curInstruction & 0xFF);
+
+ this.OverflowCarryAdd(ord, (uint)(this.curInstruction & 0xFF), registers[rd]);
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ }
+
+ private void OpSubImm()
+ {
+ // sub rd, #immed
+ int rd = (this.curInstruction >> 8) & 0x7;
+
+ uint ord = registers[rd];
+
+ registers[rd] -= (uint)(this.curInstruction & 0xFF);
+
+ this.OverflowCarrySub(ord, (uint)(this.curInstruction & 0xFF), registers[rd]);
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ }
+
+ private void OpArith()
+ {
+ int rd = this.curInstruction & 0x7;
+ uint rn = registers[(this.curInstruction >> 3) & 0x7];
+
+ uint orig, alu;
+ int shiftAmt;
+
+ switch ((this.curInstruction >> 6) & 0xF)
+ {
+ case OP_ADC:
+ orig = registers[rd];
+ registers[rd] += rn + carry;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(orig, rn, registers[rd]);
+ break;
+
+ case OP_AND:
+ registers[rd] &= rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ break;
+
+ case OP_ASR:
+ shiftAmt = (int)(rn & 0xFF);
+ if (shiftAmt == 0)
+ {
+ // Do nothing
+ }
+ else if (shiftAmt < 32)
+ {
+ carry = (registers[rd] >> (shiftAmt - 1)) & 0x1;
+ registers[rd] = (uint)(((int)registers[rd]) >> shiftAmt);
+ }
+ else
+ {
+ carry = (registers[rd] >> 31) & 1;
+ if (carry == 1) registers[rd] = 0xFFFFFFFF;
+ else registers[rd] = 0;
+ }
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ break;
+
+ case OP_BIC:
+ registers[rd] &= ~rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ break;
+
+ case OP_CMN:
+ alu = registers[rd] + rn;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarryAdd(registers[rd], rn, alu);
+ break;
+
+ case OP_CMP:
+ alu = registers[rd] - rn;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(registers[rd], rn, alu);
+ break;
+
+ case OP_EOR:
+ registers[rd] ^= rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ break;
+
+ case OP_LSL:
+ shiftAmt = (int)(rn & 0xFF);
+ if (shiftAmt == 0)
+ {
+ // Do nothing
+ }
+ else if (shiftAmt < 32)
+ {
+ carry = (registers[rd] >> (32 - shiftAmt)) & 0x1;
+ registers[rd] <<= shiftAmt;
+ }
+ else if (shiftAmt == 32)
+ {
+ carry = registers[rd] & 0x1;
+ registers[rd] = 0;
+ }
+ else
+ {
+ carry = 0;
+ registers[rd] = 0;
+ }
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ break;
+
+ case OP_LSR:
+ shiftAmt = (int)(rn & 0xFF);
+ if (shiftAmt == 0)
+ {
+ // Do nothing
+ }
+ else if (shiftAmt < 32)
+ {
+ carry = (registers[rd] >> (shiftAmt - 1)) & 0x1;
+ registers[rd] >>= shiftAmt;
+ }
+ else if (shiftAmt == 32)
+ {
+ carry = (registers[rd] >> 31) & 0x1;
+ registers[rd] = 0;
+ }
+ else
+ {
+ carry = 0;
+ registers[rd] = 0;
+ }
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ break;
+
+ case OP_MUL:
+ int mulCycles = 4;
+ // Multiply cycle calculations
+ if ((rn & 0xFFFFFF00) == 0 || (rn & 0xFFFFFF00) == 0xFFFFFF00)
+ {
+ mulCycles = 1;
+ }
+ else if ((rn & 0xFFFF0000) == 0 || (rn & 0xFFFF0000) == 0xFFFF0000)
+ {
+ mulCycles = 2;
+ }
+ else if ((rn & 0xFF000000) == 0 || (rn & 0xFF000000) == 0xFF000000)
+ {
+ mulCycles = 3;
+ }
+
+ this.parent.Cycles -= mulCycles;
+
+ registers[rd] *= rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ break;
+
+ case OP_MVN:
+ registers[rd] = ~rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ break;
+
+ case OP_NEG:
+ registers[rd] = 0 - rn;
+
+ this.OverflowCarrySub(0, rn, registers[rd]);
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ break;
+
+ case OP_ORR:
+ registers[rd] |= rn;
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ break;
+
+ case OP_ROR:
+ shiftAmt = (int)(rn & 0xFF);
+ if (shiftAmt == 0)
+ {
+ // Do nothing
+ }
+ else if ((shiftAmt & 0x1F) == 0)
+ {
+ carry = registers[rd] >> 31;
+ }
+ else
+ {
+ shiftAmt &= 0x1F;
+ carry = (registers[rd] >> (shiftAmt - 1)) & 0x1;
+ registers[rd] = (registers[rd] >> shiftAmt) | (registers[rd] << (32 - shiftAmt));
+ }
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ break;
+
+ case OP_SBC:
+ orig = registers[rd];
+ registers[rd] = (registers[rd] - rn) - (1U - carry);
+
+ negative = registers[rd] >> 31;
+ zero = registers[rd] == 0 ? 1U : 0U;
+ this.OverflowCarrySub(orig, rn, registers[rd]);
+ break;
+
+ case OP_TST:
+ alu = registers[rd] & rn;
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ break;
+
+ default:
+ throw new Exception("The coder screwed up on the thumb alu op...");
+ }
+ }
+
+ private void OpAddHi()
+ {
+ int rd = ((this.curInstruction & (1 << 7)) >> 4) | (this.curInstruction & 0x7);
+ int rm = (this.curInstruction >> 3) & 0xF;
+
+ registers[rd] += registers[rm];
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~1U;
+ this.FlushQueue();
+ }
+ }
+
+ private void OpCmpHi()
+ {
+ int rd = ((this.curInstruction & (1 << 7)) >> 4) | (this.curInstruction & 0x7);
+ int rm = (this.curInstruction >> 3) & 0xF;
+
+ uint alu = registers[rd] - registers[rm];
+
+ negative = alu >> 31;
+ zero = alu == 0 ? 1U : 0U;
+ this.OverflowCarrySub(registers[rd], registers[rm], alu);
+ }
+
+ private void OpMovHi()
+ {
+ int rd = ((this.curInstruction & (1 << 7)) >> 4) | (this.curInstruction & 0x7);
+ int rm = (this.curInstruction >> 3) & 0xF;
+
+ registers[rd] = registers[rm];
+
+ if (rd == 15)
+ {
+ registers[rd] &= ~1U;
+ this.FlushQueue();
+ }
+ }
+
+ private void OpBx()
+ {
+ int rm = (this.curInstruction >> 3) & 0xf;
+
+ this.PackFlags();
+
+ this.parent.CPSR &= ~Arm7Processor.T_MASK;
+ this.parent.CPSR |= (registers[rm] & 1) << Arm7Processor.T_BIT;
+
+ registers[15] = registers[rm] & (~1U);
+
+ this.UnpackFlags();
+
+ // Check for branch back to Arm Mode
+ if ((this.parent.CPSR & Arm7Processor.T_MASK) != Arm7Processor.T_MASK)
+ {
+ return;
+ }
+
+ this.FlushQueue();
+ }
+
+ private void OpLdrPc()
+ {
+ int rd = (this.curInstruction >> 8) & 0x7;
+
+ registers[rd] = this.memory.ReadU32((registers[15] & ~2U) + (uint)((this.curInstruction & 0xFF) * 4));
+
+ this.parent.Cycles--;
+ }
+
+ private void OpStrReg()
+ {
+ this.memory.WriteU32(registers[(this.curInstruction >> 3) & 0x7] + registers[(this.curInstruction >> 6) & 0x7],
+ registers[this.curInstruction & 0x7]);
+ }
+
+ private void OpStrhReg()
+ {
+ this.memory.WriteU16(registers[(this.curInstruction >> 3) & 0x7] + registers[(this.curInstruction >> 6) & 0x7],
+ (ushort)(registers[this.curInstruction & 0x7] & 0xFFFF));
+ }
+
+ private void OpStrbReg()
+ {
+ this.memory.WriteU8(registers[(this.curInstruction >> 3) & 0x7] + registers[(this.curInstruction >> 6) & 0x7],
+ (byte)(registers[this.curInstruction & 0x7] & 0xFF));
+ }
+
+ private void OpLdrsbReg()
+ {
+ registers[this.curInstruction & 0x7] =
+ this.memory.ReadU8(registers[(this.curInstruction >> 3) & 0x7] + registers[(this.curInstruction >> 6) & 0x7]);
+
+ if ((registers[this.curInstruction & 0x7] & (1 << 7)) != 0)
+ {
+ registers[this.curInstruction & 0x7] |= 0xFFFFFF00;
+ }
+
+ this.parent.Cycles--;
+ }
+
+ private void OpLdrReg()
+ {
+ registers[this.curInstruction & 0x7] =
+ this.memory.ReadU32(registers[(this.curInstruction >> 3) & 0x7] + registers[(this.curInstruction >> 6) & 0x7]);
+
+ this.parent.Cycles--;
+ }
+
+ private void OpLdrhReg()
+ {
+ registers[this.curInstruction & 0x7] =
+ this.memory.ReadU16(registers[(this.curInstruction >> 3) & 0x7] + registers[(this.curInstruction >> 6) & 0x7]);
+
+ this.parent.Cycles--;
+ }
+
+ private void OpLdrbReg()
+ {
+ registers[this.curInstruction & 0x7] =
+ this.memory.ReadU8(registers[(this.curInstruction >> 3) & 0x7] + registers[(this.curInstruction >> 6) & 0x7]);
+
+ this.parent.Cycles--;
+ }
+
+ private void OpLdrshReg()
+ {
+ registers[this.curInstruction & 0x7] =
+ this.memory.ReadU16(registers[(this.curInstruction >> 3) & 0x7] + registers[(this.curInstruction >> 6) & 0x7]);
+
+ if ((registers[this.curInstruction & 0x7] & (1 << 15)) != 0)
+ {
+ registers[this.curInstruction & 0x7] |= 0xFFFF0000;
+ }
+
+ this.parent.Cycles--;
+ }
+
+ private void OpStrImm()
+ {
+ this.memory.WriteU32(registers[(this.curInstruction >> 3) & 0x7] + (uint)(((this.curInstruction >> 6) & 0x1F) * 4),
+ registers[this.curInstruction & 0x7]);
+ }
+
+ private void OpLdrImm()
+ {
+ registers[this.curInstruction & 0x7] =
+ this.memory.ReadU32(registers[(this.curInstruction >> 3) & 0x7] + (uint)(((this.curInstruction >> 6) & 0x1F) * 4));
+
+ this.parent.Cycles--;
+ }
+
+ private void OpStrbImm()
+ {
+ this.memory.WriteU8(registers[(this.curInstruction >> 3) & 0x7] + (uint)((this.curInstruction >> 6) & 0x1F),
+ (byte)(registers[this.curInstruction & 0x7] & 0xFF));
+ }
+
+ private void OpLdrbImm()
+ {
+ registers[this.curInstruction & 0x7] =
+ this.memory.ReadU8(registers[(this.curInstruction >> 3) & 0x7] + (uint)((this.curInstruction >> 6) & 0x1F));
+
+ this.parent.Cycles--;
+ }
+
+ private void OpStrhImm()
+ {
+ this.memory.WriteU16(registers[(this.curInstruction >> 3) & 0x7] + (uint)(((this.curInstruction >> 6) & 0x1F) * 2),
+ (ushort)(registers[this.curInstruction & 0x7] & 0xFFFF));
+ }
+
+ private void OpLdrhImm()
+ {
+ registers[this.curInstruction & 0x7] =
+ this.memory.ReadU16(registers[(this.curInstruction >> 3) & 0x7] + (uint)(((this.curInstruction >> 6) & 0x1F) * 2));
+
+ this.parent.Cycles--;
+ }
+
+ private void OpStrSp()
+ {
+ this.memory.WriteU32(registers[13] + (uint)((this.curInstruction & 0xFF) * 4),
+ registers[(this.curInstruction >> 8) & 0x7]);
+ }
+
+ private void OpLdrSp()
+ {
+ registers[(this.curInstruction >> 8) & 0x7] =
+ this.memory.ReadU32(registers[13] + (uint)((this.curInstruction & 0xFF) * 4));
+ }
+
+ private void OpAddPc()
+ {
+ registers[(this.curInstruction >> 8) & 0x7] =
+ (registers[15] & ~2U) + (uint)((this.curInstruction & 0xFF) * 4);
+ }
+
+ private void OpAddSp()
+ {
+ registers[(this.curInstruction >> 8) & 0x7] =
+ registers[13] + (uint)((this.curInstruction & 0xFF) * 4);
+ }
+
+ private void OpSubSp()
+ {
+ if ((this.curInstruction & (1 << 7)) != 0)
+ registers[13] -= (uint)((this.curInstruction & 0x7F) * 4);
+ else
+ registers[13] += (uint)((this.curInstruction & 0x7F) * 4);
+ }
+
+ private void OpPush()
+ {
+ for (int i = 7; i >= 0; i--)
+ {
+ if (((this.curInstruction >> i) & 1) != 0)
+ {
+ registers[13] -= 4;
+ this.memory.WriteU32(registers[13], registers[i]);
+ }
+ }
+ }
+
+ private void OpPushLr()
+ {
+ registers[13] -= 4;
+ this.memory.WriteU32(registers[13], registers[14]);
+
+ for (int i = 7; i >= 0; i--)
+ {
+ if (((this.curInstruction >> i) & 1) != 0)
+ {
+ registers[13] -= 4;
+ this.memory.WriteU32(registers[13], registers[i]);
+ }
+ }
+ }
+
+ private void OpPop()
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ if (((this.curInstruction >> i) & 1) != 0)
+ {
+ registers[i] = this.memory.ReadU32(registers[13]);
+ registers[13] += 4;
+ }
+ }
+
+ this.parent.Cycles--;
+ }
+
+ private void OpPopPc()
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ if (((this.curInstruction >> i) & 1) != 0)
+ {
+ registers[i] = this.memory.ReadU32(registers[13]);
+ registers[13] += 4;
+ }
+ }
+
+ registers[15] = this.memory.ReadU32(registers[13]) & (~1U);
+ registers[13] += 4;
+
+ // ARM9 check here
+
+ this.FlushQueue();
+
+ this.parent.Cycles--;
+ }
+
+ private void OpStmia()
+ {
+ int rn = (this.curInstruction >> 8) & 0x7;
+
+ for (int i = 0; i < 8; i++)
+ {
+ if (((this.curInstruction >> i) & 1) != 0)
+ {
+ this.memory.WriteU32(registers[rn] & (~3U), registers[i]);
+ registers[rn] += 4;
+ }
+ }
+ }
+
+ private void OpLdmia()
+ {
+ int rn = (this.curInstruction >> 8) & 0x7;
+
+ uint address = registers[rn];
+
+ for (int i = 0; i < 8; i++)
+ {
+ if (((this.curInstruction >> i) & 1) != 0)
+ {
+ registers[i] = this.memory.ReadU32Aligned(address & (~3U));
+ address += 4;
+ }
+ }
+
+ if (((this.curInstruction >> rn) & 1) == 0)
+ {
+ registers[rn] = address;
+ }
+ }
+
+ private void OpBCond()
+ {
+ uint cond = 0;
+ switch ((this.curInstruction >> 8) & 0xF)
+ {
+ case COND_AL: cond = 1; break;
+ case COND_EQ: cond = zero; break;
+ case COND_NE: cond = 1 - zero; break;
+ case COND_CS: cond = carry; break;
+ case COND_CC: cond = 1 - carry; break;
+ case COND_MI: cond = negative; break;
+ case COND_PL: cond = 1 - negative; break;
+ case COND_VS: cond = overflow; break;
+ case COND_VC: cond = 1 - overflow; break;
+ case COND_HI: cond = carry & (1 - zero); break;
+ case COND_LS: cond = (1 - carry) | zero; break;
+ case COND_GE: cond = (1 - negative) ^ overflow; break;
+ case COND_LT: cond = negative ^ overflow; break;
+ case COND_GT: cond = (1 - zero) & (negative ^ (1 - overflow)); break;
+ case COND_LE: cond = (negative ^ overflow) | zero; break;
+ }
+
+ if (cond == 1)
+ {
+ uint offset = (uint)(this.curInstruction & 0xFF);
+ if ((offset & (1 << 7)) != 0) offset |= 0xFFFFFF00;
+
+ registers[15] += offset << 1;
+
+ this.FlushQueue();
+ }
+ }
+
+ private void OpSwi()
+ {
+ registers[15] -= 4U;
+ this.parent.EnterException(Arm7Processor.SVC, 0x8, false, false);
+ }
+
+ private void OpB()
+ {
+ uint offset = (uint)(this.curInstruction & 0x7FF);
+ if ((offset & (1 << 10)) != 0) offset |= 0xFFFFF800;
+
+ registers[15] += offset << 1;
+
+ this.FlushQueue();
+ }
+
+ private void OpBl1()
+ {
+ uint offset = (uint)(this.curInstruction & 0x7FF);
+ if ((offset & (1 << 10)) != 0) offset |= 0xFFFFF800;
+
+ registers[14] = registers[15] + (offset << 12);
+ }
+
+ private void OpBl2()
+ {
+ uint tmp = registers[15];
+ registers[15] = registers[14] + (uint)((this.curInstruction & 0x7FF) << 1);
+ registers[14] = (tmp - 2U) | 1;
+
+ this.FlushQueue();
+ }
+
+ private void OpUnd()
+ {
+ throw new Exception("Unknown opcode");
+ }
+ #endregion
+
+ private void PackFlags()
+ {
+ this.parent.CPSR &= 0x0FFFFFFF;
+ this.parent.CPSR |= this.negative << Arm7Processor.N_BIT;
+ this.parent.CPSR |= this.zero << Arm7Processor.Z_BIT;
+ this.parent.CPSR |= this.carry << Arm7Processor.C_BIT;
+ this.parent.CPSR |= this.overflow << Arm7Processor.V_BIT;
+ }
+
+ private void UnpackFlags()
+ {
+ this.negative = (this.parent.CPSR >> Arm7Processor.N_BIT) & 1;
+ this.zero = (this.parent.CPSR >> Arm7Processor.Z_BIT) & 1;
+ this.carry = (this.parent.CPSR >> Arm7Processor.C_BIT) & 1;
+ this.overflow = (this.parent.CPSR >> Arm7Processor.V_BIT) & 1;
+ }
+
+ private void FlushQueue()
+ {
+ this.instructionQueue = this.memory.ReadU16(registers[15]);
+ registers[15] += 2;
+ }
+ }
+}
diff --git a/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/VideoManager.cs b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/VideoManager.cs
new file mode 100644
index 0000000000..e820aa990d
--- /dev/null
+++ b/BizHawk.Emulation/Consoles/Nintendo/GBAAlt/VideoManager.cs
@@ -0,0 +1,164 @@
+namespace GarboDev
+{
+ public class VideoManager
+ {
+ public delegate void OnPresent(uint[] data);
+
+ private Memory memory = null;
+ private IRenderer renderer = null;
+ private OnPresent presenter;
+ private GbaManager gbaManager;
+ private int curLine;
+
+ public Memory Memory
+ {
+ set{ this.memory = value; }
+ }
+
+ public IRenderer Renderer
+ {
+ set
+ {
+ this.renderer = value;
+ this.renderer.Memory = this.memory;
+ }
+ }
+
+ public OnPresent Presenter
+ {
+ set { this.presenter = value; }
+ }
+
+ public VideoManager(GbaManager gbaManager)
+ {
+ this.gbaManager = gbaManager;
+ }
+
+ public void Reset()
+ {
+ this.curLine = 0;
+
+ this.renderer.Memory = memory;
+ this.renderer.Reset();
+ }
+
+ private void EnterVBlank(Arm7Processor processor)
+ {
+ ushort dispstat = Memory.ReadU16(this.memory.IORam, Memory.DISPSTAT);
+ dispstat |= 1;
+ Memory.WriteU16(this.memory.IORam, Memory.DISPSTAT, dispstat);
+
+ // Render the frame
+ this.gbaManager.FramesRendered++;
+ this.presenter(this.renderer.ShowFrame());
+
+ if ((dispstat & (1 << 3)) != 0)
+ {
+ // Fire the vblank irq
+ processor.RequestIrq(0);
+ }
+
+ // Check for DMA triggers
+ this.memory.VBlankDma();
+ }
+
+ private void LeaveVBlank(Arm7Processor processor)
+ {
+ ushort dispstat = Memory.ReadU16(this.memory.IORam, Memory.DISPSTAT);
+ dispstat &= 0xFFFE;
+ Memory.WriteU16(this.memory.IORam, Memory.DISPSTAT, dispstat);
+
+ processor.UpdateKeyState();
+
+ // Update the rot/scale values
+ this.memory.Bgx[0] = (int)Memory.ReadU32(this.memory.IORam, Memory.BG2X_L);
+ this.memory.Bgx[1] = (int)Memory.ReadU32(this.memory.IORam, Memory.BG3X_L);
+ this.memory.Bgy[0] = (int)Memory.ReadU32(this.memory.IORam, Memory.BG2Y_L);
+ this.memory.Bgy[1] = (int)Memory.ReadU32(this.memory.IORam, Memory.BG3Y_L);
+ }
+
+ public void EnterHBlank(Arm7Processor processor)
+ {
+ ushort dispstat = Memory.ReadU16(this.memory.IORam, Memory.DISPSTAT);
+ dispstat |= 1 << 1;
+ Memory.WriteU16(this.memory.IORam, Memory.DISPSTAT, dispstat);
+
+ // Advance the bgx registers
+ for (int bg = 0; bg <= 1; bg++)
+ {
+ short dmx = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PB + (uint)bg * 0x10);
+ short dmy = (short)Memory.ReadU16(this.memory.IORam, Memory.BG2PD + (uint)bg * 0x10);
+ this.memory.Bgx[bg] += dmx;
+ this.memory.Bgy[bg] += dmy;
+ }
+
+ if (this.curLine < 160)
+ {
+ this.memory.HBlankDma();
+
+ // Trigger hblank irq
+ if ((dispstat & (1 << 4)) != 0)
+ {
+ processor.RequestIrq(1);
+ }
+ }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ /// true if end of frame
+ public bool LeaveHBlank(Arm7Processor processor)
+ {
+ bool ret = false;
+ ushort dispstat = Memory.ReadU16(this.memory.IORam, Memory.DISPSTAT);
+ dispstat &= 0xFFF9;
+ Memory.WriteU16(this.memory.IORam, Memory.DISPSTAT, dispstat);
+
+ // Move to the next line
+ this.curLine++;
+
+ if (this.curLine >= 228)
+ {
+ // Start again at the beginning
+ this.curLine = 0;
+ }
+
+ // Update registers
+ Memory.WriteU16(this.memory.IORam, Memory.VCOUNT, (ushort)this.curLine);
+
+ // Check for vblank
+ if (this.curLine == 160)
+ {
+ this.EnterVBlank(processor);
+ ret = true;
+ }
+ else if (this.curLine == 0)
+ {
+ this.LeaveVBlank(processor);
+ }
+
+ // Check y-line trigger
+ if (((dispstat >> 8) & 0xff) == this.curLine)
+ {
+ dispstat = (ushort)(Memory.ReadU16(this.memory.IORam, Memory.DISPSTAT) | (1 << 2));
+ Memory.WriteU16(this.memory.IORam, Memory.DISPSTAT, dispstat);
+
+ if ((dispstat & (1 << 5)) != 0)
+ {
+ processor.RequestIrq(2);
+ }
+ }
+ return ret;
+ }
+
+ public void RenderLine()
+ {
+ if (this.curLine < 160)
+ {
+ this.renderer.RenderLine(this.curLine);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/BizHawk.MultiClient/MainForm.cs b/BizHawk.MultiClient/MainForm.cs
index cc2e070177..71a88e346a 100644
--- a/BizHawk.MultiClient/MainForm.cs
+++ b/BizHawk.MultiClient/MainForm.cs
@@ -1928,7 +1928,8 @@ namespace BizHawk.MultiClient
MessageBox.Show("Unable to find the required GBA BIOS file - \n" + gbabios, "Unable to load BIOS", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw new Exception();
}
- GBA gba = new GBA(nextComm);
+ //GBA gba = new GBA(nextComm);
+ var gba = new GarboDev.GbaManager(nextComm);
gba.Load(rom.RomData, gbabios);
nextEmulator = gba;
}