private bool TryPcRelative(ImageReader rdr, ushort opcode, out MachineOperand op) { var addr = rdr.Address; int offset = opcode & 0xFF; if (offset == 0xFF) { if (!rdr.TryReadBeInt32(out offset)) { op = null; return(false); } } else if (offset == 0x00) { short sOffset; if (!rdr.TryReadBeInt16(out sOffset)) { op = null; return(false); } offset = sOffset; } else { offset = (sbyte)offset; } op = new M68kAddressOperand(addr + offset); return(true); }
private bool TryAddressRegisterIndirectWithIndex(ushort uInstr, PrimitiveType dataWidth, EndianImageReader rdr, out MachineOperand op) { if (!rdr.TryReadBeUInt16(out ushort extension)) { op = null; return(false); } if (EXT_FULL(extension)) { if (M68kDisassembler.EXT_EFFECTIVE_ZERO(extension)) { op = new M68kAddressOperand(Address.Ptr32(0)); return(true); } RegisterStorage base_reg = null; RegisterStorage index_reg = null; PrimitiveType index_reg_width = null; int index_scale = 1; Constant @base = null; if (EXT_BASE_DISPLACEMENT_PRESENT(extension)) { @base = rdr.ReadBe(EXT_BASE_DISPLACEMENT_LONG(extension) ? PrimitiveType.Word32 : PrimitiveType.Int16); } Constant outer = null; if (EXT_OUTER_DISPLACEMENT_PRESENT(extension)) { outer = rdr.ReadBe(EXT_OUTER_DISPLACEMENT_LONG(extension) ? PrimitiveType.Word32 : PrimitiveType.Int16); } if (EXT_BASE_REGISTER_PRESENT(extension)) { base_reg = Registers.AddressRegister(uInstr & 7); } if (EXT_INDEX_REGISTER_PRESENT(extension)) { index_reg = EXT_INDEX_AR(extension) ? Registers.AddressRegister((int)EXT_INDEX_REGISTER(extension)) : Registers.DataRegister((int)EXT_INDEX_REGISTER(extension)); index_reg_width = EXT_INDEX_LONG(extension) ? PrimitiveType.Word32 : PrimitiveType.Word16; if (EXT_INDEX_SCALE(extension) != 0) { index_scale = 1 << EXT_INDEX_SCALE(extension); } } bool preindex = (extension & 7) > 0 && (extension & 7) < 4; bool postindex = (extension & 7) > 4; op = new IndexedOperand(dataWidth, @base, outer, base_reg, index_reg, index_reg_width, index_scale, preindex, postindex); } else { op = new IndirectIndexedOperand( dataWidth, EXT_8BIT_DISPLACEMENT(extension), Registers.AddressRegister(uInstr & 7), EXT_INDEX_AR(extension) ? Registers.AddressRegister((int)EXT_INDEX_REGISTER(extension)) : Registers.DataRegister((int)EXT_INDEX_REGISTER(extension)), EXT_INDEX_LONG(extension) ? PrimitiveType.Word32 : PrimitiveType.Int16, 1 << EXT_INDEX_SCALE(extension)); } return(true); }
private bool TryParseOperandInner(ushort uInstr, byte addressMode, byte operandBits, PrimitiveType dataWidth, EndianImageReader rdr, out MachineOperand op) { Constant offset; switch (addressMode) { case 0: // Data register direct. op = DataRegisterOperand(operandBits, 0); return(true); case 1: // Address register direct op = new RegisterOperand(AddressRegister(operandBits, 0)); return(true); case 2: // Address register indirect op = MemoryOperand.Indirect(dataWidth, AddressRegister(operandBits, 0)); return(true); case 3: // Address register indirect with postincrement. op = MemoryOperand.PostIncrement(dataWidth, AddressRegister(operandBits, 0)); return(true); case 4: // Address register indirect with predecrement. op = MemoryOperand.PreDecrement(dataWidth, AddressRegister(operandBits, 0)); return(true); case 5: // Address register indirect with displacement. if (!rdr.TryReadBe(PrimitiveType.Int16, out offset)) { op = null; return(false); } op = MemoryOperand.Indirect(dataWidth, AddressRegister(operandBits, 0), offset); return(true); case 6: // Address register indirect with index return(TryAddressRegisterIndirectWithIndex(uInstr, dataWidth, rdr, out op)); case 7: switch (operandBits) { case 0: // Absolute short address ushort usAddr; if (!rdr.TryReadBeUInt16(out usAddr)) { op = null; return(false); } op = new M68kAddressOperand(usAddr); return(true); case 1: // Absolute long address uint uAddr; if (!rdr.TryReadBeUInt32(out uAddr)) { op = null; return(false); } op = new M68kAddressOperand(uAddr); return(true); case 2: // Program counter with displacement var off = rdr.Address - dasm.instr.Address; short sOffset; if (!rdr.TryReadBeInt16(out sOffset)) { op = null; return(false); } off += sOffset; op = new MemoryOperand(dataWidth, Registers.pc, Constant.Int16((short)off)); return(true); case 3: // Program counter with index var addrExt = rdr.Address; ushort extension; if (!rdr.TryReadBeUInt16(out extension)) { op = null; return(false); } if (EXT_FULL(extension)) { if (EXT_EFFECTIVE_ZERO(extension)) { op = new M68kImmediateOperand(Constant.Word32(0)); return(true); } Constant @base = null; Constant outer = null; if (EXT_BASE_DISPLACEMENT_PRESENT(extension)) { @base = EXT_BASE_DISPLACEMENT_LONG(extension) ? rdr.ReadBe(PrimitiveType.Word32) : rdr.ReadBe(PrimitiveType.Int16); } if (EXT_OUTER_DISPLACEMENT_PRESENT(extension)) { outer = EXT_OUTER_DISPLACEMENT_LONG(extension) ? rdr.ReadBe(PrimitiveType.Word32) : rdr.ReadBe(PrimitiveType.Int16); } RegisterStorage base_reg = EXT_BASE_REGISTER_PRESENT(extension) ? Registers.pc : null; RegisterStorage index_reg = null; PrimitiveType index_width = null; int index_scale = 0; if (EXT_INDEX_REGISTER_PRESENT(extension)) { index_reg = EXT_INDEX_AR(extension) ? Registers.AddressRegister((int)EXT_INDEX_REGISTER(extension)) : Registers.DataRegister((int)EXT_INDEX_REGISTER(extension)); index_width = EXT_INDEX_LONG(extension) ? PrimitiveType.Word32 : PrimitiveType.Int16; index_scale = (EXT_INDEX_SCALE(extension) != 0) ? 1 << EXT_INDEX_SCALE(extension) : 0; } op = new IndexedOperand(dataWidth, @base, outer, base_reg, index_reg, index_width, index_scale, (extension & 7) > 0 && (extension & 7) < 4, (extension & 7) > 4); return(true); } op = new IndirectIndexedOperand( dataWidth, EXT_8BIT_DISPLACEMENT(extension), Registers.pc, EXT_INDEX_AR(extension) ? Registers.AddressRegister((int)EXT_INDEX_REGISTER(extension)) : Registers.DataRegister((int)EXT_INDEX_REGISTER(extension)), EXT_INDEX_LONG(extension) ? PrimitiveType.Word32 : PrimitiveType.Int16, 1 << EXT_INDEX_SCALE(extension)); return(true); case 4: // Immediate if (dataWidth.Size == 1) // don't want the instruction stream to get misaligned! { rdr.Offset += 1; } Constant coff; if (!rdr.TryReadBe(dataWidth, out coff)) { op = null; return(false); } op = new M68kImmediateOperand(coff); return(true); default: op = null; return(false); } default: throw new NotImplementedException(string.Format("Address mode {0:X1} not implemented.", addressMode)); } }
/// <summary> /// Attempts to decode an operand. /// </summary> /// <param name="rdr"></param> /// <param name="args"></param> /// <param name="dataWidth"></param> /// <param name="op"></param> /// <returns>If true, either no more operands are needed, or an /// operand was fetched sucessfully. If false, the operand was /// invalid, either due to a bad encoding or because the reader read /// off the end of the memory area. /// </returns> public bool TryGetOperand(EndianImageReader rdr, string args, PrimitiveType dataWidth, out MachineOperand op) { if (i >= args.Length) { op = null; return(true); } for (; ;) { if (args[i] == ',') { ++i; } Address addr; switch (args[i++]) { case 'A': // Address register A0-A7 encoded in in instrution op = new RegisterOperand(AddressRegister(opcode, GetOpcodeOffset(args[i++]))); return(true); case 'c': // CCR register op = new RegisterOperand(Registers.ccr); return(true); case 'D': // Data register D0-D7 encoded in instruction op = DataRegisterOperand(opcode, GetOpcodeOffset(args[i++])); return(true); case 'E': // Effective address (EA) return(TryParseOperand(opcode, GetOpcodeOffset(args[i++]), dataWidth, rdr, out op)); case 'e': // Effective address with 3-bit halves swapped return(TryParseSwappedOperand(opcode, GetOpcodeOffset(args[i++]), dataWidth, rdr, out op)); case 'I': // Immediate operand return(TryGetImmediate(rdr, GetSizeType(0, args[i++], dataWidth), out op)); case 'J': // PC Relative jump return(TryPcRelative(rdr, opcode, out op)); case 'M': // Register bitset var size = GetSizeType(0, args[i++], dataWidth); op = new RegisterSetOperand(rdr.ReadBeUInt16(), size); return(true); case 'n': // cache bitset bitSet = rdr.ReadBeUInt16(); break; case 'm': // Register bitset reversed size = GetSizeType(0, args[i++], dataWidth); op = RegisterSetOperand.CreateReversed(bitSet, size); return(true); case 'q': // "Small" quick constant (3-bit part of the opcode) op = GetQuickImmediate(GetOpcodeOffset(args[i++]), 0x07, 8, PrimitiveType.Byte); return(true); case 'Q': // "Large" quick constant (8-bit part of the opcode) op = GetQuickImmediate(GetOpcodeOffset(args[i++]), 0xFF, 0, PrimitiveType.SByte); return(true); case 'R': // relative addr = rdr.Address; int relative = 0; switch (args[i++]) { case 'w': relative = rdr.ReadBeInt16(); break; case 'l': relative = rdr.ReadBeInt32(); break; default: throw new NotImplementedException(); } op = new M68kAddressOperand(addr + relative); return(true); case 's': // SR register op = new RegisterOperand(Registers.sr); return(true); case '+': // Postincrement operator; following character specifies bit offset of the address register code. op = new PostIncrementMemoryOperand(dataWidth, AddressRegister(opcode, GetOpcodeOffset(args[i++]))); return(true); case '-': // Predecrement operator; following character specifies bit offset of the address register code. op = new PredecrementMemoryOperand(dataWidth, AddressRegister(opcode, GetOpcodeOffset(args[i++]))); return(true); default: throw new FormatException(string.Format("Unknown argument type {0}.", args[--i])); } } }