internal ulong DecodeAddrData(OpSize Size, ulong Mode, ulong Addr) { if (Mode == MODE_ADDR16 || Mode == MODE_ADDR32) { return(Memory.Read(Size, (int)Addr)); } return(Addr); }
public virtual void Move(OpSize Size, ulong Instruction) { ulong SrcEAddr = Decode_SrcEAddr(Instruction.GetBits(5, 0)); ulong DstEAddr = Decode_DestEAddr(Instruction.GetBits(11, 6)); ulong SrcData = DecodeAddrData(Size, SrcEAddr, GetData(Size, SrcEAddr)); SetData(Size, DstEAddr, SrcData); CCR_N_Sign = Size.IsNegative(SrcData); CCR_Z_Zero = SrcData == 0; CCR_V_Overflow = CCR_C_Carry = false; }
public static bool IsNegative(this OpSize Size, ulong Num) { switch (Size) { case OpSize._8: return(((sbyte)Num) < 0); case OpSize._16: return(((short)Num) < 0); case OpSize._32: return(((int)Num) < 0); } return(false); }
public virtual ulong Read(OpSize Size, int Address) { switch (Size) { case OpSize._8: return(Read8(Address)); case OpSize._16: return(Read16(Address)); case OpSize._32: return(Read32(Address)); default: throw new NotImplementedException(); } }
public virtual void Write(OpSize Size, int Address, ulong Value) { switch (Size) { case OpSize._8: Write8(Address, (byte)Value); break; case OpSize._16: Write16(Address, (ushort)Value); break; case OpSize._32: Write32(Address, (uint)Value); break; default: throw new NotImplementedException(); } }
public virtual ulong HandleData(OpSize Size, ulong Addressing, bool Set = false, ulong Value = 0) { byte Mode = (byte)((Addressing >> 8) & 0xFF); byte Data = (byte)(Addressing & 0xFF); // Convert data to register number (Dn or An) for modes 0 .. 6 int Reg = Data; if (Mode >= 1 && Mode <= 6) { Reg += 8; } switch (Mode) { // 000/001 Dn, An case 0: case 1: if (Set) { switch (Size) { case OpSize._8: DA[Reg] = (DA[Reg] & ~0xFF) + (int)(Value & 0xFF); break; case OpSize._16: DA[Reg] = (DA[Reg] & ~0xFFFF) + (int)(Value & 0xFFFF); break; case OpSize._32: DA[Reg] = (int)(DA[Reg] & ~0xFFFFFFFF) + (int)(Value & 0xFFFFFFFF); break; ; } } else { return((ulong)DA[Reg]); } break; // 010 (An) case 2: if (Set) { Memory.Write(Size, DA[Reg], Value); } else { return(Memory.Read(Size, DA[Reg])); } break; // 011 (An)+ case 3: { ulong Ret = 0; if (Set) { Memory.Write(Size, DA[Reg], Value); } else { Ret = Memory.Read(Size, DA[Reg]); } int Inc = (int)Size; if (Inc < 2 && Reg == 15) // If not even and register A7 { Inc = 2; } DA[Reg] += Inc; // TOOD: implement after instruction executes return(Ret); } // 100 -(An) case 4: { int Inc = (int)Size; if (Inc < 2 && Reg == 15) // If not even and register A7 { Inc = 2; } DA[Reg] -= Inc; // TODO: implement before instruction executes if (Set) { Memory.Write(Size, DA[Reg], Value); } else { return(Memory.Read(Size, DA[Reg])); } break; } // 101 (d16, An) case 5: if (Set) { Memory.Write(Size, DA[Reg] + (short)Memory.Read16(PC + InstrLen), Value); InstrLen += 2; } else { short Offset = (short)Memory.Read16(PC + InstrLen); ulong Ret = Memory.Read(Size, DA[Reg] + Offset); InstrLen += 2; return(Ret); } break; // 110 case 6: throw new NotImplementedException(); // 111 case 7: { switch (Data) { // 000 addr16 case 0: { ulong Addr = Memory.Read16(PC + InstrLen); InstrLen += 2; if (Set) { Memory.Write(Size, (int)Addr, Value); } return(Addr); } // 001 addr32 case 1: { ulong Addr = Memory.Read32(PC + InstrLen); InstrLen += 4; if (Set) { Memory.Write(Size, (int)Addr, Value); } return(Addr); } // 010 d16(PC) case 2: { if (Set) { throw new InvalidOperationException(); } short Addr = (short)Memory.Read16(PC + InstrLen); InstrLen += 2; return((ulong)(PC + Addr + 2)); } // 011 case 3: throw new NotImplementedException(); // 100 imm, implied case 4: if (Set) { throw new InvalidOperationException(); } if (Size == OpSize.BYTE) { Size = OpSize.WORD; } ulong Val = Memory.Read(Size, PC + InstrLen); InstrLen += (int)Size; return(Val); default: throw new InvalidOperationException(); } } default: throw new InvalidOperationException(); } return(0); }
public virtual void Step() { if (TrapQueue.Count > 0) { int TrapVector = TrapQueue.Dequeue(); Console.WriteLine("Trap #{0}, not handled", TrapVector); } bool IncPC = true; ushort Word0 = Memory.Read16(PC + sizeof(ushort) * 0); ushort Word1 = Memory.Read16(PC + sizeof(ushort) * 1); ushort Word2 = Memory.Read16(PC + sizeof(ushort) * 2); ushort Word3 = Memory.Read16(PC + sizeof(ushort) * 3); ushort Word4 = Memory.Read16(PC + sizeof(ushort) * 4); uint Instr = (uint)((Word0 << 16) | Word1); ulong Instr2 = ((ulong)Word0 << 64) | ((ulong)Word1 << 48) | ((ulong)Word2 << 32) | ((ulong)Word3 << 16) | Word4; Opcode Opcode = MatchOpcode(Instr); InstrLen = 2; #if DEBUG /*Console.Write(" "); * for (int i = 16 - 1; i >= 0; i--) * Console.Write("{0:X}", i); * Console.WriteLine();*/ Console.ForegroundColor = ConsoleColor.White; Console.Write("0x{0:X8}: ", PC); Console.ResetColor(); OpcodeDef OpcodeDef = MatchOpcodeDef(Instr); if (OpcodeDef != null) { string Bin = Ext.ToBinary(Instr); string Pattern = OpcodeDef.Higher.Pattern + OpcodeDef.Lower.Pattern; Console.Write("0x{0:X8} ", Instr); for (int i = 0; i < Pattern.Length; i++) { if (Pattern[i] == '?') { Console.ForegroundColor = ConsoleColor.Green; } else { Console.ForegroundColor = ConsoleColor.Gray; } Console.Write(Bin[i]); } Console.ResetColor(); Console.Write(" {0}", Opcode); } else { Console.Write("0x{0:X8} {1} {2}", Instr, Ext.ToBinary(Instr), Opcode); } Console.WriteLine(); #endif switch (Opcode) { case Opcode.ILLEGAL_OPCODE: throw new InvalidOperationException(); case Opcode.UNIMPLEMENTED: throw new NotImplementedException(); case Opcode.ADDI: { ushort DstEAddr = Decode_EAddr(((ulong)Word0).GetBits(5, 0)); OpSize Size = Decode_Size(((ulong)Word0).GetBits(7, 6)); ulong Src = GetData(Size, MODE_IMMEDIATE); ulong Dest = GetData(Size, DstEAddr); SetData(Size, DstEAddr, Src + Dest); break; } case Opcode.MOVE_BYTE: { Move(OpSize.BYTE, Word0); break; } case Opcode.MOVE_WORD: { Move(OpSize.WORD, Word0); break; } case Opcode.MOVE_LONG: { Move(OpSize.LONG, Word0); break; } case Opcode.PEA: { ushort EAddr = Decode_EAddr(((ulong)Word0).GetBits(5, 0)); uint Val = (uint)GetData(OpSize.LONG, EAddr); DA[SP] -= 4; Memory.Write32(DA[SP], Val); break; } case Opcode.TRAP: { Trap(Word0.GetBits(3, 0)); break; } case Opcode.UNLK: { ulong Register = Word0.GetBits(2, 0); DA[SP] = (int)GetData(OpSize.LONG, MODE_REGISTER_A | Register); SetData(OpSize.LONG, MODE_REGISTER_A | Register, Memory.Read32(DA[SP])); DA[SP] += 4; break; } case Opcode.LINK_WORD: { ulong Register = Word0.GetBits(2, 0); int Immediate = (int)GetData(OpSize.WORD, MODE_IMMEDIATE); DA[SP] -= 4; Memory.Write32(DA[SP], (uint)GetData(OpSize.LONG, MODE_REGISTER_A | Register)); SetData(OpSize.LONG, MODE_REGISTER_A | Register, (ulong)DA[SP]); DA[SP] = DA[SP] + Immediate; break; } case Opcode.NOP: { break; } case Opcode.JMP: case Opcode.JSR: { ushort EAddr = Decode_EAddr(((ulong)Word0).GetBits(5, 0)); ulong Addr = GetData(OpSize.LONG, EAddr); if (Opcode == Opcode.JSR) { DA[SP] -= 4; Memory.Write32(DA[SP], (uint)(PC + InstrLen)); } PC = (int)Addr; IncPC = false; break; } case Opcode.RTS: { PC = (int)Memory.Read32(DA[SP]); DA[SP] += 4; IncPC = false; break; } case Opcode.MULU_WORD: case Opcode.MULU_LONG: case Opcode.MULS_WORD: case Opcode.MULS_LONG: { OpSize Size = (Opcode == Opcode.MULS_WORD || Opcode == Opcode.MULU_WORD) ? OpSize.WORD : OpSize.LONG; ulong SrcEAddr = Decode_EAddr(Word0.GetBits(5, 0)); ulong DstEAddr = Size == OpSize.LONG ? (MODE_REGISTER_D | Word1.GetBits(14, 12)) : (MODE_REGISTER_D | Word0.GetBits(11, 9)); if (Size == OpSize.LONG) { InstrLen += 2; } ulong Src = GetData(Size, SrcEAddr); ulong Dst = GetData(Size, DstEAddr); ulong Mul = (Opcode == Opcode.MULS_WORD || Opcode == Opcode.MULS_LONG) ? (ulong)((long)Src * (long)Dst) : Src * Dst; SetData(Size, DstEAddr, Mul & 0xFFFFFFFF); if (Size == OpSize.LONG && Word1.GetBit(10)) { ulong RegDh = MODE_REGISTER_D | Word1.GetBits(2, 0); ulong Dh = GetData(Size, RegDh); SetData(Size, RegDh, (Mul >> 32) & 0xFFFFFFFF); } break; } case Opcode.ADDQ: { ushort EAddr = Decode_EAddr(Word0.GetBits(5, 0)); OpSize Size = Decode_Size(Word0.GetBits(7, 6)); ulong Data = Word0.GetBits(11, 9); if (Data == 0) { Data = 8; } ulong Dest = GetData(Size, EAddr); SetData(Size, EAddr, Dest + Data); break; } case Opcode.ADD_ADDA: { ushort EAddr = Decode_EAddr(Word0.GetBits(5, 0)); ushort OpMode = Word0.GetBits(7, 6); OpSize Size = Decode_Size(OpMode); ulong Register = Word0.GetBits(11, 9); bool IsSource = !Word0.GetBit(8); // ADDA part ulong MODE_REGISTER = MODE_REGISTER_D; if (OpMode == 0x3 || OpMode == 0x7) { MODE_REGISTER = MODE_REGISTER_A; IsSource = true; if (OpMode == 0x3) { Size = OpSize.WORD; } else { Size = OpSize.LONG; } } ulong Src, Dst; ulong SetEAddr = MODE_REGISTER | Register; if (IsSource) { Src = GetData(Size, EAddr); Dst = GetData(Size, MODE_REGISTER | Register); } else { Src = GetData(Size, MODE_REGISTER_D | Register); Dst = GetData(Size, EAddr); SetEAddr = EAddr; } SetData(Size, SetEAddr, Src + Dst); break; } default: throw new NotImplementedException(); } if (IncPC) { PC += InstrLen; } }
public virtual ulong GetData(OpSize Size, ulong Addressing) { return(HandleData(Size, Addressing)); }
public virtual void SetData(OpSize Size, ulong Addressing, ulong Value) { HandleData(Size, Addressing, true, Value); }