private void Jump(uint address) { if (address % 2 != 0) { ExecutionException.Throw(ExecutionError.JumpToUnalignedAddress); } Ip = (int)(address / 2); }
private bool ExecuteNextInstruction() { var instruction = _decoder.Decode(_memoryAccessor.GetShort(_memory, (uint)Ip * 2)); _tracing.TraceCall(instruction, Ip); Ip++; int signedA, signedB; uint address; ulong ulongResult; switch (instruction.Opcode) { case Opcode.And: Registers[instruction.RegisterA] &= Registers[instruction.RegisterB]; break; case Opcode.Add: Registers[instruction.RegisterA] += Registers[instruction.RegisterB]; break; case Opcode.Ashl: Registers[instruction.RegisterA] = (uint)((int)Registers[instruction.RegisterA] << (int)Registers[instruction.RegisterB]); break; case Opcode.Ashr: Registers[instruction.RegisterA] = (uint)((int)Registers[instruction.RegisterA] >> (int)Registers[instruction.RegisterB]); break; case Opcode.Beq: if (CompareStatusUnsigned == 0) { Ip = BranchNewIp(instruction.Value); } break; case Opcode.Bge: if (CompareStatusSigned >= 0) { Ip = BranchNewIp(instruction.Value); } break; case Opcode.Bgeu: if (CompareStatusUnsigned >= 0) { Ip = BranchNewIp(instruction.Value); } break; case Opcode.Bgt: if (CompareStatusSigned > 0) { Ip = BranchNewIp(instruction.Value); } break; case Opcode.Bgtu: if (CompareStatusUnsigned > 0) { Ip = BranchNewIp(instruction.Value); } break; case Opcode.Ble: if (CompareStatusSigned <= 0) { Ip = BranchNewIp(instruction.Value); } break; case Opcode.Bleu: if (CompareStatusUnsigned <= 0) { Ip = BranchNewIp(instruction.Value); } break; case Opcode.Blt: if (CompareStatusSigned < 0) { Ip = BranchNewIp(instruction.Value); } break; case Opcode.Bltu: if (CompareStatusUnsigned < 0) { Ip = BranchNewIp(instruction.Value); } break; case Opcode.Bne: if (CompareStatusUnsigned != 0) { Ip = BranchNewIp(instruction.Value); } break; case Opcode.Brk: return(false); Break(); break; case Opcode.Cmp: signedA = (int)Registers[instruction.RegisterA]; signedB = (int)Registers[instruction.RegisterB]; CompareStatusUnsigned = Registers[instruction.RegisterA].CompareTo(Registers[instruction.RegisterB]); CompareStatusSigned = signedA.CompareTo(signedB); break; case Opcode.Dec: Registers[instruction.RegisterA] = (uint)(Registers[instruction.RegisterA] - instruction.Value); break; case Opcode.Div: signedA = (int)Registers[instruction.RegisterA]; signedB = (int)Registers[instruction.RegisterB]; if (signedB == 0) { ExecutionException.Throw(ExecutionError.DivisionByZero); } else if (signedA == int.MinValue && signedB == -1) { unchecked { Registers[instruction.RegisterA] = (uint)int.MinValue; } } else { Registers[instruction.RegisterA] = (uint)(signedA / signedB); } break; case Opcode.Gsr: Registers[instruction.RegisterA] = SpecialRegisters[instruction.Value]; break; case Opcode.Inc: Registers[instruction.RegisterA] = (uint)(Registers[instruction.RegisterA] + instruction.Value); break; case Opcode.Jmp: Jump(Registers[instruction.RegisterA]); break; case Opcode.Jmpa: Jump(GetLongImmediate()); break; case Opcode.Jsr: JumpToSubroutine(Registers[instruction.RegisterA]); break; case Opcode.Jsra: address = GetLongImmediate(); JumpToSubroutine(address); break; case Opcode.LdB: Registers[instruction.RegisterA] = _memoryAccessor.GetByte(_memory, Registers[instruction.RegisterB]); break; case Opcode.LdL: Registers[instruction.RegisterA] = _memoryAccessor.GetLong(_memory, Registers[instruction.RegisterB]); break; case Opcode.LdS: Registers[instruction.RegisterA] = _memoryAccessor.GetShort(_memory, Registers[instruction.RegisterB]); break; case Opcode.LdaB: Registers[instruction.RegisterA] = _memoryAccessor.GetByte(_memory, GetLongImmediate()); Ip += 2; break; case Opcode.LdaL: Registers[instruction.RegisterA] = _memoryAccessor.GetLong(_memory, GetLongImmediate()); Ip += 2; break; case Opcode.LdaS: Registers[instruction.RegisterA] = _memoryAccessor.GetShort(_memory, GetLongImmediate()); Ip += 2; break; case Opcode.LdiL: Registers[instruction.RegisterA] = GetLongImmediate(); break; case Opcode.LdiB: Registers[instruction.RegisterA] = GetLongImmediate() & 0xFF; break; case Opcode.LdiS: Registers[instruction.RegisterA] = GetLongImmediate() & 0xFFFF; break; case Opcode.LdoB: address = (uint)(Registers[instruction.RegisterB] + GetShortSignedImmediate()); Registers[instruction.RegisterA] = _memoryAccessor.GetByte(_memory, address); break; case Opcode.LdoL: address = (uint)(Registers[instruction.RegisterB] + GetShortSignedImmediate()); Registers[instruction.RegisterA] = _memoryAccessor.GetLong(_memory, address); break; case Opcode.LdoS: address = (uint)(Registers[instruction.RegisterB] + GetShortSignedImmediate()); Registers[instruction.RegisterA] = _memoryAccessor.GetShort(_memory, address); break; case Opcode.Lshr: Registers[instruction.RegisterA] = Registers[instruction.RegisterA] >> (int)Registers[instruction.RegisterB]; break; case Opcode.Mod: signedA = (int)Registers[instruction.RegisterA]; signedB = (int)Registers[instruction.RegisterB]; Registers[instruction.RegisterA] = (uint)(signedA % signedB); break; case Opcode.Mov: Registers[instruction.RegisterA] = Registers[instruction.RegisterB]; break; case Opcode.Mul: signedA = (int)Registers[instruction.RegisterA]; signedB = (int)Registers[instruction.RegisterB]; ulongResult = (ulong)(signedA * signedB); Registers[instruction.RegisterA] = (uint)ulongResult; break; case Opcode.MulX: signedA = (int)Registers[instruction.RegisterA]; signedB = (int)Registers[instruction.RegisterB]; ulongResult = (ulong)(signedA * signedB); ulongResult >>= 32; Registers[instruction.RegisterA] = (uint)ulongResult; break; case Opcode.Neg: signedB = (int)Registers[instruction.RegisterB]; signedB = -signedB; Registers[instruction.RegisterA] = (uint)signedB; break; case Opcode.Nop: break; case Opcode.Not: Registers[instruction.RegisterA] = ~Registers[instruction.RegisterB]; break; case Opcode.Or: Registers[instruction.RegisterA] |= Registers[instruction.RegisterB]; break; case Opcode.Pop: Registers[instruction.RegisterB] = Pop(instruction.RegisterA); break; case Opcode.Push: Push(instruction.RegisterA, Registers[instruction.RegisterB]); break; case Opcode.Ret: ReturnFromSubroutine(); break; case Opcode.SexB: Registers[instruction.RegisterA] = (uint)(sbyte)Registers[instruction.RegisterB]; break; case Opcode.SexS: Registers[instruction.RegisterA] = (uint)(short)Registers[instruction.RegisterB]; break; case Opcode.Ssr: SpecialRegisters[instruction.Value] = Registers[instruction.RegisterA]; break; case Opcode.StB: _memoryAccessor.StoreByte(_memory, Registers[instruction.RegisterA], (byte)Registers[instruction.RegisterB]); break; case Opcode.StL: _memoryAccessor.StoreLong(_memory, Registers[instruction.RegisterA], Registers[instruction.RegisterB]); break; case Opcode.StS: _memoryAccessor.StoreShort(_memory, Registers[instruction.RegisterA], (ushort)Registers[instruction.RegisterB]); break; case Opcode.StaB: _memoryAccessor.StoreByte(_memory, GetLongImmediate(), (byte)Registers[instruction.RegisterA]); break; case Opcode.StaL: _memoryAccessor.StoreLong(_memory, GetLongImmediate(), Registers[instruction.RegisterA]); break; case Opcode.StaS: _memoryAccessor.StoreShort(_memory, GetLongImmediate(), (ushort)Registers[instruction.RegisterA]); break; case Opcode.StoB: address = (uint)(Registers[instruction.RegisterA] + GetShortSignedImmediate()); _memoryAccessor.StoreByte(_memory, address, (byte)Registers[instruction.RegisterB]); break; case Opcode.StoL: address = (uint)(Registers[instruction.RegisterA] + GetShortSignedImmediate()); _memoryAccessor.StoreLong(_memory, address, Registers[instruction.RegisterB]); break; case Opcode.StoS: address = (uint)(Registers[instruction.RegisterA] + GetShortSignedImmediate()); _memoryAccessor.StoreShort(_memory, address, (ushort)Registers[instruction.RegisterB]); break; case Opcode.Sub: Registers[instruction.RegisterA] = Registers[instruction.RegisterA] - Registers[instruction.RegisterB]; break; case Opcode.Swi: SwiRequestIndex = GetLongImmediate(); Exception(ExceptionReason.SoftwareInterrupt); break; case Opcode.Udiv: Registers[instruction.RegisterA] /= Registers[instruction.RegisterB]; break; case Opcode.Umod: Registers[instruction.RegisterA] %= Registers[instruction.RegisterB]; break; case Opcode.UmulX: ulongResult = Registers[instruction.RegisterA] * Registers[instruction.RegisterB]; ulongResult >>= 32; Registers[instruction.RegisterA] = (uint)ulongResult; break; case Opcode.Xor: Registers[instruction.RegisterA] ^= Registers[instruction.RegisterB]; break; case Opcode.ZexB: Registers[instruction.RegisterA] = Registers[instruction.RegisterB] & 0xFF; break; case Opcode.ZexS: Registers[instruction.RegisterA] = Registers[instruction.RegisterB] & 0xFFFF; break; default: ExecutionException.Throw(ExecutionError.IllegalOpcode); break; } _instructionsExecuted += 1; return(true); }