private Expression RewriteDst(MachineOperand op, Expression src, Func <Expression, Expression, Expression> fn) { var reg = op as RegisterOperand; if (reg != null) { var id = binder.EnsureRegister(reg.Register); m.Assign(id, fn(id, src)); return(id); } if (op is AddressOperand addr) { return(addr.Address); } if (op is MemoryOperand mem) { Expression ea; if (mem.Base != null) { ea = binder.EnsureRegister(mem.Base); } else { ea = arch.MakeAddressFromConstant(mem.Offset, false); } if (mem.Increment < 0) { m.Assign(ea, m.ISub(ea, mem.Width.Size)); } var load = m.Mem(mem.Width, ea); var tmp = binder.CreateTemporary(ea.DataType); m.Assign(tmp, fn(load, src)); m.Assign(m.Mem(mem.Width, ea), tmp); if (mem.Increment > 0) { m.Assign(ea, m.IAdd(ea, mem.Width.Size)); } return(tmp); } throw new NotImplementedException(op.GetType().Name); }
private Expression Dec(Expression e) { return(m.ISub(e, 1)); }
private Expression RewriteSrcOp(int iOp, PrimitiveType width) { var op = this.instr.Operands[iOp]; switch (op) { case RegisterOperand regOp: var reg = binder.EnsureRegister(regOp.Register); if (reg == null) { return(null); } if (width.Size == 4) { return(reg); } else if (width.Size == 8) { var rHi = arch.GetRegister(1 + (int)reg.Storage.Domain); if (rHi == null) { return(null); } var regHi = binder.EnsureRegister(rHi); return(binder.EnsureSequence(width, regHi.Storage, reg.Storage)); } else if (width.Size == 16) { var regHi1 = binder.EnsureRegister(arch.GetRegister(1 + (int)reg.Storage.Domain)); var regHi2 = binder.EnsureRegister(arch.GetRegister(2 + (int)reg.Storage.Domain)); var regHi3 = binder.EnsureRegister(arch.GetRegister(3 + (int)reg.Storage.Domain)); var regLo = binder.EnsureSequence(PrimitiveType.Word64, regHi1.Storage, reg.Storage); var regHi = binder.EnsureSequence(PrimitiveType.Word64, regHi3.Storage, regHi2.Storage); return(binder.EnsureSequence(width, regHi.Storage, regLo.Storage)); } else { return(m.Slice(width, reg, 0)); } case ImmediateOperand immOp: return(immOp.Value); case MemoryOperand memOp: Expression ea; if (memOp.Base != null) { reg = binder.EnsureRegister(memOp.Base); if (memOp.AutoDecrement) { m.Assign(reg, m.ISub(reg, width.Size)); } else if (memOp.AutoIncrement) { var tmp = binder.CreateTemporary(reg.DataType); m.Assign(tmp, reg); reg = tmp; } ea = reg; if (memOp.Offset != null) { if (memOp.Offset.DataType.BitSize < ea.DataType.BitSize) { ea = m.IAddS(ea, memOp.Offset.ToInt32()); } else { ea = m.IAdd(ea, memOp.Offset); } } if (memOp.Index != null) { Expression idx = binder.EnsureRegister(memOp.Index); if (width.Size != 1) { idx = m.IMul(idx, Constant.Int32(width.Size)); } ea = m.IAdd(ea, idx); } Expression load; if (memOp.Deferred) { load = m.Mem(width, m.Mem32(ea)); } else { load = m.Mem(width, ea); } if (memOp.AutoIncrement) { reg = binder.EnsureRegister(memOp.Base); int inc = (memOp.Deferred) ? 4 : width.Size; m.Assign(reg, m.IAdd(reg, inc)); } return(load); } else { ea = arch.MakeAddressFromConstant(memOp.Offset, false); Expression load; if (memOp.Deferred) { load = m.Mem(width, m.Mem32(ea)); } else { load = m.Mem(width, ea); } return(load); } case AddressOperand addrOp: //$BUG: enabling the commented code causes huge regressions in the // unzip subject. /*if (addrOp.Width.BitSize > width.BitSize) * { * var c = addrOp.Address.ToUInt32(); * return Constant.Create(width, c); * } * else*/ { return(addrOp.Address); } } throw new NotImplementedException(op.GetType().Name); }
public IEnumerator <RtlInstructionCluster> GetEnumerator() { while (instrs.MoveNext()) { if (!instrs.Current.TryGetInternal(out this.instr)) { continue; throw new AddressCorrelatedException( instrs.Current.Address, "Invalid opcode cannot be rewritten to IR."); } this.ops = instr.ArchitectureDetail.Operands; this.ric = new RtlInstructionCluster(instrs.Current.Address, instr.Bytes.Length); this.ric.Class = RtlClass.Linear; this.emitter = new RtlEmitter(ric.Instructions); switch (instr.Id) { default: throw new AddressCorrelatedException( instrs.Current.Address, "Rewriting ARM Thumb opcode '{0}' ({1}) is not supported yet.", instr.Mnemonic, instr.Id); case ArmInstruction.ADD: RewriteBinop((a, b) => emitter.IAdd(a, b)); break; case ArmInstruction.ADDW: RewriteAddw(); break; case ArmInstruction.ADR: RewriteAdr(); break; case ArmInstruction.AND: RewriteAnd(); break; case ArmInstruction.ASR: RewriteShift(emitter.Sar); break; case ArmInstruction.B: RewriteB(); break; case ArmInstruction.BIC: RewriteBic(); break; case ArmInstruction.BL: RewriteBl(); break; case ArmInstruction.BLX: RewriteBlx(); break; case ArmInstruction.BX: RewriteBx(); break; case ArmInstruction.CBZ: RewriteCbnz(emitter.Eq0); break; case ArmInstruction.CBNZ: RewriteCbnz(emitter.Ne0); break; case ArmInstruction.CMP: RewriteCmp(); break; case ArmInstruction.DMB: RewriteDmb(); break; case ArmInstruction.EOR: RewriteEor(); break; case ArmInstruction.IT: RewriteIt(); continue; // Don't emit anything yet.; case ArmInstruction.LDR: RewriteLdr(PrimitiveType.Word32, PrimitiveType.Word32); break; case ArmInstruction.LDRB: RewriteLdr(PrimitiveType.UInt32, PrimitiveType.Byte); break; case ArmInstruction.LDRSB: RewriteLdr(PrimitiveType.Int32, PrimitiveType.SByte); break; case ArmInstruction.LDREX: RewriteLdrex(); break; case ArmInstruction.LDRH: RewriteLdr(PrimitiveType.UInt32, PrimitiveType.Word16); break; case ArmInstruction.LSL: RewriteShift(emitter.Shl); break; case ArmInstruction.LSR: RewriteShift(emitter.Shr); break; case ArmInstruction.MOV: RewriteMov(); break; case ArmInstruction.MOVT: RewriteMovt(); break; case ArmInstruction.MOVW: RewriteMovw(); break; case ArmInstruction.MRC: RewriteMrc(); break; case ArmInstruction.MVN: RewriteMvn(); break; case ArmInstruction.POP: RewritePop(); break; case ArmInstruction.PUSH: RewritePush(); break; case ArmInstruction.RSB: RewriteRsb(); break; case ArmInstruction.STM: RewriteStm(); break; case ArmInstruction.STR: RewriteStr(PrimitiveType.Word32); break; case ArmInstruction.STRH: RewriteStr(PrimitiveType.Word16); break; case ArmInstruction.STRB: RewriteStr(PrimitiveType.Byte); break; case ArmInstruction.STREX: RewriteStrex(); break; case ArmInstruction.SUB: RewriteBinop((a, b) => emitter.ISub(a, b)); break; case ArmInstruction.SUBW: RewriteSubw(); break; case ArmInstruction.TRAP: RewriteTrap(); break; case ArmInstruction.TST: RewriteTst(); break; case ArmInstruction.UDF: RewriteUdf(); break; case ArmInstruction.UXTH: RewriteUxth(); break; } itState = (itState << 1) & 0x0F; if (itState == 0) { itStateCondition = ArmCodeCondition.AL; } yield return(ric); } }
private void RewriteBlockInstruction(Func <Expression, Expression, Expression> incdec, bool repeat) { var bc = binder.EnsureRegister(Registers.bc); var de = binder.EnsureRegister(Registers.de); var hl = binder.EnsureRegister(Registers.hl); var V = FlagGroup(FlagM.PF); m.Assign(m.Mem8(de), m.Mem8(hl)); m.Assign(hl, incdec(hl, Constant.Int16(1))); m.Assign(de, incdec(de, Constant.Int16(1))); m.Assign(bc, m.ISub(bc, 1)); if (repeat) { m.BranchInMiddleOfInstruction(m.Ne0(bc), dasm.Current.Address, InstrClass.Transfer); } m.Assign(V, m.Const(PrimitiveType.Bool, 0)); }
public IEnumerator <RtlInstructionCluster> GetEnumerator() { while (dasm.MoveNext()) { this.instr = dasm.Current; var rtls = new List <RtlInstruction>(); m = new RtlEmitter(rtls); this.iclass = instr.InstructionClass; switch (instr.Mnemonic) { default: host.Error(instr.Address, $"WE32100 instruction '{instr}' is not supported yet."); EmitUnitTest(); goto case Mnemonic.invalid; case Mnemonic.invalid: m.Invalid(); iclass = InstrClass.Invalid; break; case Mnemonic.addb2: RewriteArithmetic2(m.IAdd, PrimitiveType.Byte); break; case Mnemonic.addh2: RewriteArithmetic2(m.IAdd, PrimitiveType.Word16); break; case Mnemonic.addw2: RewriteArithmetic2(m.IAdd, PrimitiveType.Word32); break; case Mnemonic.addb3: RewriteArithmetic3(m.IAdd, PrimitiveType.Byte); break; case Mnemonic.addh3: RewriteArithmetic3(m.IAdd, PrimitiveType.Word16); break; case Mnemonic.addw3: RewriteArithmetic3(m.IAdd, PrimitiveType.Word32); break; case Mnemonic.andb2: RewriteLogical2(m.And, PrimitiveType.Byte); break; case Mnemonic.andh2: RewriteLogical2(m.And, PrimitiveType.Word16); break; case Mnemonic.andw2: RewriteLogical2(m.And, PrimitiveType.Word32); break; case Mnemonic.andb3: RewriteLogical3(m.And, PrimitiveType.Byte); break; case Mnemonic.andh3: RewriteLogical3(m.And, PrimitiveType.Word16); break; case Mnemonic.andw3: RewriteLogical3(m.And, PrimitiveType.Word32); break; case Mnemonic.dech: RewriteUnary(e => m.ISub(e, 1), PrimitiveType.Word16, NZVC); break; case Mnemonic.movb: RewriteMov(PrimitiveType.Byte); break; case Mnemonic.subb2: RewriteArithmetic2(m.ISub, PrimitiveType.Byte); break; case Mnemonic.subh2: RewriteArithmetic2(m.ISub, PrimitiveType.Word16); break; case Mnemonic.subw2: RewriteArithmetic2(m.ISub, PrimitiveType.Word32); break; case Mnemonic.xorb2: RewriteLogical2(m.Xor, PrimitiveType.Byte); break; case Mnemonic.xorh2: RewriteLogical2(m.Xor, PrimitiveType.Word16); break; case Mnemonic.xorw2: RewriteLogical2(m.Xor, PrimitiveType.Word32); break; } yield return(m.MakeCluster(instr.Address, instr.Length, iclass)); } }
private Expression RewriteSrcOp(int iOp, PrimitiveType width) { var op = dasm.Current.Operands[iOp]; var regOp = op as RegisterOperand; if (regOp != null) { var reg = frame.EnsureRegister(regOp.Register); if (width.Size == 4) { return(reg); } else if (width.Size == 8) { var regHi = frame.EnsureRegister(arch.GetRegister(1 + (int)reg.Storage.Domain)); return(frame.EnsureSequence(regHi.Storage, reg.Storage, width)); } else if (width.Size == 16) { var regHi1 = frame.EnsureRegister(arch.GetRegister(1 + (int)reg.Storage.Domain)); var regHi2 = frame.EnsureRegister(arch.GetRegister(2 + (int)reg.Storage.Domain)); var regHi3 = frame.EnsureRegister(arch.GetRegister(3 + (int)reg.Storage.Domain)); var regLo = frame.EnsureSequence(regHi1.Storage, reg.Storage, PrimitiveType.Word64); var regHi = frame.EnsureSequence(regHi3.Storage, regHi2.Storage, PrimitiveType.Word64); return(frame.EnsureSequence(regHi.Storage, regLo.Storage, width)); } else { return(emitter.Cast(width, reg)); } } var immOp = op as ImmediateOperand; if (immOp != null) { return(immOp.Value); } var memOp = op as MemoryOperand; if (memOp != null) { Expression ea; if (memOp.Base != null) { var reg = frame.EnsureRegister(memOp.Base); if (memOp.AutoDecrement) { emitter.Assign(reg, emitter.ISub(reg, width.Size)); } else if (memOp.AutoIncrement) { var tmp = frame.CreateTemporary(reg.DataType); emitter.Assign(tmp, reg); reg = tmp; } ea = reg; if (memOp.Offset != null) { ea = emitter.IAdd(ea, memOp.Offset); } if (memOp.Index != null) { Expression idx = frame.EnsureRegister(memOp.Index); if (width.Size != 1) { idx = emitter.IMul(idx, Constant.Int32(width.Size)); } ea = emitter.IAdd(ea, idx); } Expression load; if (memOp.Deferred) { load = emitter.Load(width, emitter.LoadDw(ea)); } else { load = emitter.Load(width, ea); } if (memOp.AutoIncrement) { if (memOp.AutoIncrement) { reg = frame.EnsureRegister(memOp.Base); int inc = (memOp.Deferred) ? 4 : width.Size; emitter.Assign(reg, emitter.IAdd(reg, inc)); } } return(load); } else { } } var addrOp = op as AddressOperand; if (addrOp != null) { return(addrOp.Address); } throw new NotImplementedException(op.GetType().Name); }
private void RewriteCp_b() { var op1 = m.Slice(PrimitiveType.Byte, RewriteOp(0), 0); var op2 = m.Slice(PrimitiveType.Byte, RewriteOp(1), 0); var grf = binder.EnsureFlagGroup(VNZC); m.Assign(grf, m.Cond(m.ISub(op1, op2))); }
private Expression?RewriteApplication(ApplicationOperand app) { var ops = app.Operands.Select(o => OperandSrc(o) !).ToArray(); var dt = app.Width; switch (app.Mnemonic) { case Mnemonic.add: return(m.IAdd(ops[0], ops[1])); case Mnemonic.addasl: return(RewriteAddAsl(ops[0], ops[1], ops[2])); case Mnemonic.allocframe: RewriteAllocFrame(app.Operands[0]); return(null); case Mnemonic.and: return(m.And(ops[0], ops[1])); case Mnemonic.asl: return(m.Shl(ops[0], ops[1])); case Mnemonic.aslh: return(m.Shl(ops[0], 16)); case Mnemonic.asr: return(m.Sar(ops[0], ops[1])); case Mnemonic.asrh: return(m.Sar(ops[0], 16)); case Mnemonic.cmp__eq: return(m.Eq(ops[0], ops[1])); case Mnemonic.cmp__gt: return(m.Gt(ops[0], ops[1])); case Mnemonic.cmp__gtu: return(m.Ugt(ops[0], ops[1])); case Mnemonic.cmpb__eq: return(RewriteCmp(PrimitiveType.Byte, m.Eq, ops[0], ops[1])); case Mnemonic.cmpb__gt: return(RewriteCmp(PrimitiveType.Byte, m.Gt, ops[0], ops[1])); case Mnemonic.cmpb__gtu: return(RewriteCmp(PrimitiveType.Byte, m.Ugt, ops[0], ops[1])); case Mnemonic.cmph__eq: return(RewriteCmp(PrimitiveType.Word16, m.Eq, ops[0], ops[1])); case Mnemonic.cmph__gt: return(RewriteCmp(PrimitiveType.Word16, m.Gt, ops[0], ops[1])); case Mnemonic.cmph__gtu: return(RewriteCmp(PrimitiveType.Word16, m.Ugt, ops[0], ops[1])); case Mnemonic.dfcmp__eq: return(m.FEq(ops[0], ops[1])); case Mnemonic.dfcmp__ge: return(m.FGe(ops[0], ops[1])); case Mnemonic.dfcmp__uo: return(host.Intrinsic("isunordered", false, PrimitiveType.Bool, ops[0], ops[1])); case Mnemonic.combine: return(RewriteCombine(ops[0], ops[1])); case Mnemonic.convert_d2df: return(m.Convert(ops[0], PrimitiveType.Int64, PrimitiveType.Real64)); case Mnemonic.convert_df2sf: return(m.Convert(ops[0], PrimitiveType.Real64, PrimitiveType.Real32)); case Mnemonic.convert_sf2df: return(m.Convert(ops[0], PrimitiveType.Real32, PrimitiveType.Real64)); case Mnemonic.EQ: return(m.Eq(ops[0], ops[1])); case Mnemonic.extract: return(RewriteExtract(Domain.SignedInt, ops[0], app.Operands)); case Mnemonic.extractu: return(RewriteExtract(Domain.UnsignedInt, ops[0], app.Operands)); case Mnemonic.loop0: RewriteLoop(0, ops); return(null); case Mnemonic.loop1: RewriteLoop(1, ops); return(null); case Mnemonic.lsl: return(m.Shl(ops[0], ops[1])); case Mnemonic.lsr: return(m.Shr(ops[0], ops[1])); case Mnemonic.mpy: return(RewriteMpy(ops[0], ops[1])); case Mnemonic.mpyi: return(RewriteMpyi(ops[0], ops[1])); case Mnemonic.mpyu: return(RewriteMpyu(app.Width, ops[0], ops[1])); case Mnemonic.mux: return(m.Conditional(ops[1].DataType, ops[0], ops[1], ops[2])); case Mnemonic.NE: return(m.Ne(ops[0], ops[1])); case Mnemonic.neg: return(m.Neg(ops[0])); case Mnemonic.not: return(m.Not(ops[0])); case Mnemonic.or: return(m.Or(ops[0], ops[1])); case Mnemonic.sub: return(m.ISub(ops[0], ops[1])); case Mnemonic.sxtb: return(RewriteExt(ops[0], PrimitiveType.SByte, PrimitiveType.Int32)); case Mnemonic.sxth: return(RewriteExt(ops[0], PrimitiveType.Int16, PrimitiveType.Int32)); case Mnemonic.xor: return(m.Xor(ops[0], ops[1])); case Mnemonic.zxtb: return(RewriteExt(ops[0], PrimitiveType.Byte, PrimitiveType.UInt32)); case Mnemonic.zxth: return(RewriteExt(ops[0], PrimitiveType.UInt16, PrimitiveType.UInt32)); case Mnemonic.abs: dt = PrimitiveType.Int32; goto intrinsicFunc; case Mnemonic.max: dt = PrimitiveType.Int32; goto intrinsicFunc; case Mnemonic.maxu: dt = PrimitiveType.UInt32; goto intrinsicFunc; case Mnemonic.min: dt = PrimitiveType.Int32; goto intrinsicFunc; case Mnemonic.minu: dt = PrimitiveType.UInt32; goto intrinsicFunc; case Mnemonic.all8: case Mnemonic.any8: case Mnemonic.bitsclr: case Mnemonic.bitsplit: case Mnemonic.bitsset: case Mnemonic.ciad: case Mnemonic.cl0: case Mnemonic.cl1: case Mnemonic.clb: case Mnemonic.clrbit: case Mnemonic.crswap: case Mnemonic.cswi: case Mnemonic.ct0: case Mnemonic.dfclass: case Mnemonic.fastcorner9: case Mnemonic.insert: //$BUG: like DPB? case Mnemonic.memw_locked: case Mnemonic.setbit: case Mnemonic.start: case Mnemonic.stop: case Mnemonic.tlbw: case Mnemonic.tlbp: case Mnemonic.trap0: case Mnemonic.trap1: case Mnemonic.togglebit: case Mnemonic.tstbit: intrinsicFunc: return(RewriteIntrinsic(app.Mnemonic.ToString(), true, dt, ops)); case Mnemonic.dccleana: case Mnemonic.dccleaninva: case Mnemonic.dcfetch: case Mnemonic.dcinva: case Mnemonic.dczeroa: return(RewriteIntrinsic(app.Mnemonic.ToString(), true, VoidType.Instance, ops)); case Mnemonic.vavgh: return(RewriteVectorIntrinsic(app.Mnemonic, false, PrimitiveType.Word16, ops)); case Mnemonic.vcmpb__eq: return(RewriteVectorIntrinsic(app.Mnemonic, false, PrimitiveType.Byte, ops)); case Mnemonic.vmux: return(RewriteVectorIntrinsic(app.Mnemonic, false, PrimitiveType.Byte, ops)); case Mnemonic.vsplatb: return(RewriteVectorIntrinsic(app.Mnemonic, false, PrimitiveType.Byte, ops)); case Mnemonic.vsubh: return(RewriteVectorIntrinsic(app.Mnemonic, false, PrimitiveType.Int16, ops)); } throw new ArgumentException($"Hexagon rewriter for {app.Mnemonic} not implemented yet.", app.Mnemonic.ToString()); }
private Expression Operand(MachineOperand op) { var rop = op as RegisterOperand; if (rop != null) { return(frame.EnsureRegister(rop.Register)); } var immOp = op as ImmediateOperand; if (immOp != null) { return(immOp.Value); } var shOp = op as ShiftOperand; if (shOp != null) { var r = Operand(shOp.Operand); var sh = Operand(shOp.Shift); switch (shOp.Opcode) { case Opcode.lsl: return(emitter.Shl(r, sh)); case Opcode.lsr: return(emitter.Shr(r, sh)); case Opcode.asr: return(emitter.Sar(r, sh)); case Opcode.ror: return(host.PseudoProcedure(PseudoProcedure.Ror, PrimitiveType.Word32, r, sh)); default: throw new NotSupportedException(string.Format("Unsupported shift operation {0}.", shOp.Opcode)); } } var memOp = op as ArmMemoryOperand; if (memOp != null) { Expression baseReg = frame.EnsureRegister(memOp.Base); Expression ea = baseReg; if (memOp.Base.Number == 0x0F) // PC-relative address { var imm = memOp.Offset as ArmImmediateOperand; if (imm != null) { if (memOp.Writeback) { throw new NotImplementedException(); } var dst = (uint)((int)instr.Address.ToUInt32() + imm.Value.ToInt32()) + 8u; return(emitter.Load(memOp.Width, Address.Ptr32(dst))); } } if (memOp.Offset != null && memOp.Preindexed) { var offset = Operand(memOp.Offset); ea = memOp.Subtract ? emitter.ISub(ea, offset) : emitter.IAdd(ea, offset); } if (memOp.Preindexed && memOp.Writeback) { emitter.Assign(baseReg, ea); ea = baseReg; } return(emitter.Load(memOp.Width, ea)); } throw new NotSupportedException(string.Format("Unsupported operand {0}.", op)); }
public IEnumerator <RtlInstructionCluster> GetEnumerator() { while (dasm.MoveNext()) { di = dasm.Current; ric = new RtlInstructionCluster(di.Address, di.Length); emitter = new RtlEmitter(ric.Instructions); orw = new OperandRewriter(arch, this.emitter, this.frame, di.dataWidth); switch (di.code) { case Opcode.add: RewriteBinOp((s, d) => emitter.IAdd(d, s), FlagM.CVZNX); break; case Opcode.adda: RewriteBinOp((s, d) => emitter.IAdd(d, s)); break; case Opcode.addi: RewriteArithmetic((s, d) => emitter.IAdd(d, s)); break; case Opcode.addq: RewriteAddSubq((s, d) => emitter.IAdd(d, s)); break; case Opcode.addx: RewriteAddSubx(Operator.IAdd); break; case Opcode.and: RewriteLogical((s, d) => emitter.And(d, s)); break; case Opcode.andi: RewriteLogical((s, d) => emitter.And(d, s)); break; case Opcode.asl: RewriteArithmetic((s, d) => emitter.Shl(d, s)); break; case Opcode.asr: RewriteShift((s, d) => emitter.Sar(d, s)); break; /* * * Mnemonic Condition Encoding Test * T* True 0000 1 * F* False 0001 0 * HI High 0010 C L Z * LS Low or Same 0011 C V Z * VC Overflow Clear 1000 V * VS Overflow Set 1001 V */ case Opcode.bclr: RewriteBclrBset("__bclr"); break; case Opcode.bcc: RewriteBcc(ConditionCode.UGE, FlagM.CF); break; case Opcode.bcs: RewriteBcc(ConditionCode.ULT, FlagM.CF); break; case Opcode.beq: RewriteBcc(ConditionCode.EQ, FlagM.ZF); break; case Opcode.bge: RewriteBcc(ConditionCode.GE, FlagM.NF | FlagM.VF); break; case Opcode.bgt: RewriteBcc(ConditionCode.GT, FlagM.NF | FlagM.VF | FlagM.ZF); break; case Opcode.bhi: RewriteBcc(ConditionCode.UGT, FlagM.CF | FlagM.ZF); break; case Opcode.ble: RewriteBcc(ConditionCode.LE, FlagM.NF | FlagM.VF | FlagM.ZF); break; case Opcode.blt: RewriteBcc(ConditionCode.LT, FlagM.CF | FlagM.ZF); break; case Opcode.bls: RewriteBcc(ConditionCode.ULE, FlagM.VF | FlagM.ZF); break; case Opcode.bmi: RewriteBcc(ConditionCode.LT, FlagM.NF); break; case Opcode.bne: RewriteBcc(ConditionCode.NE, FlagM.ZF); break; case Opcode.bpl: RewriteBcc(ConditionCode.GT, FlagM.NF); break; case Opcode.bchg: RewriteBchg(); break; case Opcode.bra: RewriteBra(); break; case Opcode.bset: RewriteBclrBset("__bset"); break; case Opcode.bsr: RewriteBsr(); break; case Opcode.btst: RewriteBtst(); break; case Opcode.clr: RewriteClr(); break; case Opcode.cmp: RewriteCmp(); break; case Opcode.cmpa: RewriteCmp(); break; case Opcode.cmpi: RewriteCmp(); break; case Opcode.dble: RewriteDbcc(ConditionCode.GT, FlagM.NF | FlagM.VF | FlagM.ZF); break; case Opcode.dbhi: RewriteDbcc(ConditionCode.ULE, FlagM.CF | FlagM.ZF); break; case Opcode.dbra: RewriteDbcc(ConditionCode.None, 0); break; case Opcode.divu: RewriteDiv(Operator.UDiv); break; case Opcode.eor: RewriteLogical((s, d) => emitter.Xor(d, s)); break; case Opcode.eori: RewriteLogical((s, d) => emitter.Xor(d, s)); break; case Opcode.exg: RewriteExg(); break; case Opcode.ext: RewriteExt(); break; case Opcode.extb: RewriteExtb(); break; case Opcode.illegal: if (!RewriteIllegal()) { goto default; } break; case Opcode.jmp: RewriteJmp(); break; case Opcode.jsr: RewriteJsr(); break; case Opcode.lea: RewriteLea(); break; case Opcode.link: RewriteLink(); break; case Opcode.lsl: RewriteShift((s, d) => emitter.Shl(d, s)); break; case Opcode.lsr: RewriteShift((s, d) => emitter.Shr(d, s)); break; case Opcode.move: RewriteMove(true); break; case Opcode.movea: RewriteMove(false); break; case Opcode.moveq: RewriteMoveq(); break; case Opcode.movem: RewriteMovem(); break; case Opcode.muls: RewriteMul((s, d) => emitter.SMul(d, s)); break; case Opcode.mulu: RewriteMul((s, d) => emitter.UMul(d, s)); break; case Opcode.neg: RewriteUnary(s => emitter.Neg(s), AllConditions); break; case Opcode.negx: RewriteUnary(RewriteNegx, AllConditions); break; case Opcode.nop: continue; case Opcode.not: RewriteUnary(s => emitter.Comp(s), LogicalConditions); break; case Opcode.or: RewriteLogical((s, d) => emitter.Or(d, s)); break; case Opcode.ori: RewriteLogical((s, d) => emitter.Or(d, s)); break; case Opcode.pea: RewritePea(); break; case Opcode.rol: RewriteRotation(PseudoProcedure.Rol); break; case Opcode.ror: RewriteRotation(PseudoProcedure.Ror); break; case Opcode.roxl: RewriteRotationX(PseudoProcedure.RolC); break; case Opcode.roxr: RewriteRotationX(PseudoProcedure.RorC); break; case Opcode.rts: emitter.Return(4, 0); break; case Opcode.scc: RewriteScc(ConditionCode.UGE, FlagM.CF); break; case Opcode.scs: RewriteScc(ConditionCode.ULT, FlagM.CF); break; case Opcode.seq: RewriteScc(ConditionCode.EQ, FlagM.ZF); break; case Opcode.sge: RewriteScc(ConditionCode.GE, FlagM.NF | FlagM.VF); break; case Opcode.sgt: RewriteScc(ConditionCode.GT, FlagM.NF | FlagM.VF | FlagM.ZF); break; case Opcode.shi: RewriteScc(ConditionCode.UGT, FlagM.CF | FlagM.ZF); break; case Opcode.sle: RewriteScc(ConditionCode.LE, FlagM.NF | FlagM.VF | FlagM.ZF); break; case Opcode.slt: RewriteScc(ConditionCode.LT, FlagM.CF | FlagM.ZF); break; case Opcode.sls: RewriteScc(ConditionCode.ULE, FlagM.VF | FlagM.ZF); break; case Opcode.smi: RewriteScc(ConditionCode.LT, FlagM.NF); break; case Opcode.sne: RewriteScc(ConditionCode.NE, FlagM.ZF); break; case Opcode.spl: RewriteScc(ConditionCode.GT, FlagM.NF); break; case Opcode.st: orw.RewriteMoveDst(di.op1, di.Address, PrimitiveType.Bool, Constant.True()); break; case Opcode.sf: orw.RewriteMoveDst(di.op1, di.Address, PrimitiveType.Bool, Constant.False()); break; case Opcode.sub: RewriteArithmetic((s, d) => emitter.ISub(d, s)); break; case Opcode.suba: RewriteArithmetic((s, d) => emitter.ISub(d, s)); break; case Opcode.subi: RewriteArithmetic((s, d) => emitter.ISub(d, s)); break; case Opcode.subq: RewriteAddSubq((s, d) => emitter.ISub(d, s)); break; case Opcode.subx: RewriteArithmetic((s, d) => emitter.ISub(emitter.ISub(d, s), frame.EnsureFlagGroup((uint)FlagM.XF, "X", PrimitiveType.Bool))); break; case Opcode.swap: RewriteSwap(); break; case Opcode.tst: RewriteTst(); break; case Opcode.unlk: RewriteUnlk(); break; default: throw new AddressCorrelatedException( di.Address, "Rewriting M68k opcode '{0}' is not supported yet.", di.code); } yield return(ric); } yield break; }
private Expression RewriteSrcOp(int iOp, PrimitiveType width) { var op = this.instr.Operands[iOp]; switch (op) { case RegisterOperand regOp: var reg = binder.EnsureRegister(regOp.Register); if (reg == null) { return(null); } if (width.Size == 4) { return(reg); } else if (width.Size == 8) { var rHi = arch.GetRegister(1 + (int)reg.Storage.Domain); if (rHi == null) { return(null); } var regHi = binder.EnsureRegister(rHi); return(binder.EnsureSequence(regHi.Storage, reg.Storage, width)); } else if (width.Size == 16) { var regHi1 = binder.EnsureRegister(arch.GetRegister(1 + (int)reg.Storage.Domain)); var regHi2 = binder.EnsureRegister(arch.GetRegister(2 + (int)reg.Storage.Domain)); var regHi3 = binder.EnsureRegister(arch.GetRegister(3 + (int)reg.Storage.Domain)); var regLo = binder.EnsureSequence(regHi1.Storage, reg.Storage, PrimitiveType.Word64); var regHi = binder.EnsureSequence(regHi3.Storage, regHi2.Storage, PrimitiveType.Word64); return(binder.EnsureSequence(regHi.Storage, regLo.Storage, width)); } else { return(m.Cast(width, reg)); } case ImmediateOperand immOp: return(immOp.Value); case MemoryOperand memOp: Expression ea; if (memOp.Base != null) { reg = binder.EnsureRegister(memOp.Base); if (memOp.AutoDecrement) { m.Assign(reg, m.ISub(reg, width.Size)); } else if (memOp.AutoIncrement) { var tmp = binder.CreateTemporary(reg.DataType); m.Assign(tmp, reg); reg = tmp; } ea = reg; if (memOp.Offset != null) { ea = m.IAdd(ea, memOp.Offset); } if (memOp.Index != null) { Expression idx = binder.EnsureRegister(memOp.Index); if (width.Size != 1) { idx = m.IMul(idx, Constant.Int32(width.Size)); } ea = m.IAdd(ea, idx); } Expression load; if (memOp.Deferred) { load = m.Mem(width, m.Mem32(ea)); } else { load = m.Mem(width, ea); } if (memOp.AutoIncrement) { if (memOp.AutoIncrement) { reg = binder.EnsureRegister(memOp.Base); int inc = (memOp.Deferred) ? 4 : width.Size; m.Assign(reg, m.IAdd(reg, inc)); } } return(load); } else { } break; case AddressOperand addrOp: return(addrOp.Address); } throw new NotImplementedException(op.GetType().Name); }
private Expression Sbc(Expression a, Expression b) { var C = binder.EnsureFlagGroup(arch.GetFlagGroup(Registers.CC, (uint)FlagM.C)); return(m.ISub(m.ISub(a, b), C)); }
private Expression DstOp(MachineOperand op, Expression src, Func <Expression, Expression> fn) { var regOp = op as RegisterOperand; if (regOp != null) { var id = binder.EnsureRegister(regOp.Register); m.Assign(id, fn(src)); return(id); } var mem = op as MemoryOperand; if (mem != null) { Identifier r0; Identifier gbr; Identifier reg; var tmp = binder.CreateTemporary(op.Width); switch (mem.mode) { case AddressingMode.Indirect: reg = binder.EnsureRegister(mem.reg); m.Assign( m.Mem(mem.Width, reg), fn(src)); return(null); case AddressingMode.IndirectDisplacement: reg = binder.EnsureRegister(mem.reg); m.Assign( m.Mem(mem.Width, m.IAdd(reg, Constant.Int32(mem.disp))), fn(src)); return(null); case AddressingMode.IndirectPreDecr: reg = binder.EnsureRegister(mem.reg); m.Assign(reg, m.ISub(reg, Constant.Int32(mem.Width.Size))); m.Assign( m.Mem(tmp.DataType, reg), fn(src)); return(null); case AddressingMode.IndexedIndirect: m.Assign( m.Mem(mem.Width, m.IAdd( binder.EnsureRegister(Registers.r0), binder.EnsureRegister(mem.reg))), fn(src)); return(null); case AddressingMode.GbrIndexedIndirect: r0 = binder.EnsureRegister(Registers.r0); gbr = binder.EnsureRegister(Registers.gbr); m.Assign(tmp, m.Mem(tmp.DataType, m.IAdd(r0, gbr))); m.Assign( m.Mem(tmp.DataType, m.IAdd(r0, gbr)), fn(src)); return(tmp); default: throw new NotImplementedException(mem.mode.ToString()); } } throw new NotImplementedException(op.GetType().Name); }
public HExpr ISub(HExpr a, HExpr b) { return(MapToHandle(m.ISub(GetExpression(a), GetExpression(b)))); }
public IEnumerator <RtlInstructionCluster> GetEnumerator() { while (dasm.MoveNext()) { di = dasm.Current; var addr = di.Address; var len = di.Length; rtlInstructions = new List <RtlInstruction>(); rtlc = RtlClass.Linear; m = new RtlEmitter(rtlInstructions); orw = new OperandRewriter(arch, this.m, this.binder, di.dataWidth); switch (di.code) { default: host.Warn( di.Address, "Rewriting M68k opcode '{0}' is not supported yet.", di.code); m.Invalid(); break; case Opcode.illegal: RewriteIllegal(); break; case Opcode.add: RewriteBinOp((s, d) => m.IAdd(d, s), FlagM.CVZNX); break; case Opcode.adda: RewriteBinOp((s, d) => m.IAdd(d, s)); break; case Opcode.addi: RewriteArithmetic((s, d) => m.IAdd(d, s)); break; case Opcode.addq: RewriteAddSubq((s, d) => m.IAdd(d, s)); break; case Opcode.addx: RewriteAddSubx(m.IAdd); break; case Opcode.and: RewriteLogical((s, d) => m.And(d, s)); break; case Opcode.andi: RewriteLogical((s, d) => m.And(d, s)); break; case Opcode.asl: RewriteArithmetic((s, d) => m.Shl(d, s)); break; case Opcode.asr: RewriteShift((s, d) => m.Sar(d, s)); break; /* * * Mnemonic Condition Encoding Test * T* True 0000 1 * F* False 0001 0 * HI High 0010 C L Z * LS Low or Same 0011 C V Z * VC Overflow Clear 1000 V * VS Overflow Set 1001 V */ case Opcode.bclr: RewriteBclrBset("__bclr"); break; case Opcode.bcc: RewriteBcc(ConditionCode.UGE, FlagM.CF); break; case Opcode.bcs: RewriteBcc(ConditionCode.ULT, FlagM.CF); break; case Opcode.beq: RewriteBcc(ConditionCode.EQ, FlagM.ZF); break; case Opcode.bge: RewriteBcc(ConditionCode.GE, FlagM.NF | FlagM.VF); break; case Opcode.bgt: RewriteBcc(ConditionCode.GT, FlagM.NF | FlagM.VF | FlagM.ZF); break; case Opcode.bhi: RewriteBcc(ConditionCode.UGT, FlagM.CF | FlagM.ZF); break; case Opcode.ble: RewriteBcc(ConditionCode.LE, FlagM.NF | FlagM.VF | FlagM.ZF); break; case Opcode.blt: RewriteBcc(ConditionCode.LT, FlagM.CF | FlagM.ZF); break; case Opcode.bls: RewriteBcc(ConditionCode.ULE, FlagM.VF | FlagM.ZF); break; case Opcode.bmi: RewriteBcc(ConditionCode.LT, FlagM.NF); break; case Opcode.bne: RewriteBcc(ConditionCode.NE, FlagM.ZF); break; case Opcode.bpl: RewriteBcc(ConditionCode.GT, FlagM.NF); break; case Opcode.bvs: RewriteBcc(ConditionCode.OV, FlagM.VF); break; case Opcode.bchg: RewriteBchg(); break; case Opcode.bra: RewriteBra(); break; case Opcode.bset: RewriteBclrBset("__bset"); break; case Opcode.bsr: RewriteBsr(); break; case Opcode.btst: RewriteBtst(); break; case Opcode.cas: RewriteCas(); break; case Opcode.clr: RewriteClr(); break; case Opcode.chk: RewriteChk(); break; case Opcode.chk2: RewriteChk2(); break; case Opcode.cmp: RewriteCmp(); break; case Opcode.cmp2: RewriteCmp2(); break; case Opcode.cmpa: RewriteCmp(); break; case Opcode.cmpi: RewriteCmp(); break; case Opcode.cmpm: RewriteCmp(); break; case Opcode.dbeq: RewriteDbcc(ConditionCode.EQ, FlagM.ZF); break; case Opcode.dble: RewriteDbcc(ConditionCode.GT, FlagM.NF | FlagM.VF | FlagM.ZF); break; case Opcode.dbhi: RewriteDbcc(ConditionCode.ULE, FlagM.CF | FlagM.ZF); break; case Opcode.dbne: RewriteDbcc(ConditionCode.NE, FlagM.ZF); break; case Opcode.dbra: RewriteDbcc(ConditionCode.None, 0); break; case Opcode.divs: RewriteDiv(m.SDiv, PrimitiveType.Int16); break; case Opcode.divsl: RewriteDiv(m.SDiv, PrimitiveType.Int32); break; case Opcode.divu: RewriteDiv(m.UDiv, PrimitiveType.UInt16); break; case Opcode.eor: RewriteLogical((s, d) => m.Xor(d, s)); break; case Opcode.eori: RewriteLogical((s, d) => m.Xor(d, s)); break; case Opcode.exg: RewriteExg(); break; case Opcode.ext: RewriteExt(); break; case Opcode.extb: RewriteExtb(); break; case Opcode.fadd: RewriteFBinOp((s, d) => m.FAdd(d, s)); break; //$REVIEW: the following don't respect NaN, but NaN typically doesn't exist in HLLs. case Opcode.fbf: m.Nop(); break; case Opcode.fbnge: RewriteFbcc(ConditionCode.LT); break; case Opcode.fbnlt: RewriteFbcc(ConditionCode.GE); break; case Opcode.fbnle: RewriteFbcc(ConditionCode.GT); break; case Opcode.fbogl: RewriteFbcc(ConditionCode.NE); break; case Opcode.fbult: RewriteFbcc(ConditionCode.LT); break; case Opcode.fbun: RewriteFbcc(ConditionCode.IS_NAN); break; case Opcode.fcmp: RewriteFcmp(); break; case Opcode.fdiv: RewriteFBinOp((s, d) => m.FDiv(d, s)); break; case Opcode.fmove: RewriteFmove(); break; case Opcode.fmovecr: RewriteFmovecr(); break; case Opcode.fmovem: RewriteMovem(i => arch.GetRegister(i + Registers.fp0.Number)); break; case Opcode.fmul: RewriteFBinOp((s, d) => m.FMul(d, s)); break; case Opcode.fneg: RewriteFUnaryOp(m.Neg); break; case Opcode.fsub: RewriteFBinOp((s, d) => m.FSub(d, s)); break; case Opcode.jmp: RewriteJmp(); break; case Opcode.jsr: RewriteJsr(); break; case Opcode.lea: RewriteLea(); break; case Opcode.link: RewriteLink(); break; case Opcode.lsl: RewriteShift((s, d) => m.Shl(d, s)); break; case Opcode.lsr: RewriteShift((s, d) => m.Shr(d, s)); break; case Opcode.move: RewriteMove(true); break; case Opcode.movea: RewriteMove(false); break; case Opcode.movep: RewriteMovep(); break; case Opcode.moveq: RewriteMoveq(); break; case Opcode.movem: RewriteMovem(arch.GetRegister); break; case Opcode.muls: RewriteMul((s, d) => m.SMul(d, s)); break; case Opcode.mulu: RewriteMul((s, d) => m.UMul(d, s)); break; case Opcode.neg: RewriteUnary(s => m.Neg(s), AllConditions); break; case Opcode.negx: RewriteUnary(RewriteNegx, AllConditions); break; case Opcode.nop: m.Nop(); break; case Opcode.not: RewriteUnary(s => m.Comp(s), LogicalConditions); break; case Opcode.or: RewriteLogical((s, d) => m.Or(d, s)); break; case Opcode.ori: RewriteLogical((s, d) => m.Or(d, s)); break; case Opcode.pea: RewritePea(); break; case Opcode.rol: RewriteRotation(PseudoProcedure.Rol); break; case Opcode.ror: RewriteRotation(PseudoProcedure.Ror); break; case Opcode.roxl: RewriteRotationX(PseudoProcedure.RolC); break; case Opcode.roxr: RewriteRotationX(PseudoProcedure.RorC); break; case Opcode.rts: RewriteRts(); break; case Opcode.scc: RewriteScc(ConditionCode.UGE, FlagM.CF); break; case Opcode.scs: RewriteScc(ConditionCode.ULT, FlagM.CF); break; case Opcode.seq: RewriteScc(ConditionCode.EQ, FlagM.ZF); break; case Opcode.sge: RewriteScc(ConditionCode.GE, FlagM.NF | FlagM.VF); break; case Opcode.sgt: RewriteScc(ConditionCode.GT, FlagM.NF | FlagM.VF | FlagM.ZF); break; case Opcode.shi: RewriteScc(ConditionCode.UGT, FlagM.CF | FlagM.ZF); break; case Opcode.sle: RewriteScc(ConditionCode.LE, FlagM.NF | FlagM.VF | FlagM.ZF); break; case Opcode.slt: RewriteScc(ConditionCode.LT, FlagM.CF | FlagM.ZF); break; case Opcode.sls: RewriteScc(ConditionCode.ULE, FlagM.VF | FlagM.ZF); break; case Opcode.smi: RewriteScc(ConditionCode.LT, FlagM.NF); break; case Opcode.sne: RewriteScc(ConditionCode.NE, FlagM.ZF); break; case Opcode.spl: RewriteScc(ConditionCode.GT, FlagM.NF); break; case Opcode.st: orw.RewriteMoveDst(di.op1, di.Address, PrimitiveType.Bool, Constant.True()); break; case Opcode.sf: orw.RewriteMoveDst(di.op1, di.Address, PrimitiveType.Bool, Constant.False()); break; case Opcode.stop: RewriteStop(); break; case Opcode.sub: RewriteArithmetic((s, d) => m.ISub(d, s)); break; case Opcode.suba: RewriteArithmetic((s, d) => m.ISub(d, s)); break; case Opcode.subi: RewriteArithmetic((s, d) => m.ISub(d, s)); break; case Opcode.subq: RewriteAddSubq((s, d) => m.ISub(d, s)); break; case Opcode.subx: RewriteArithmetic((s, d) => m.ISub(m.ISub(d, s), binder.EnsureFlagGroup(Registers.ccr, (uint)FlagM.XF, "X", PrimitiveType.Bool))); break; case Opcode.swap: RewriteSwap(); break; case Opcode.trap: RewriteTrap(); break; case Opcode.tst: RewriteTst(); break; case Opcode.unlk: RewriteUnlk(); break; } yield return(new RtlInstructionCluster( addr, len, rtlInstructions.ToArray()) { Class = rtlc }); } yield break; }
private void RewriteBlockInstruction(Func <Expression, Expression, Expression> incdec, bool repeat) { var bc = frame.EnsureRegister(Registers.bc); var de = frame.EnsureRegister(Registers.de); var hl = frame.EnsureRegister(Registers.hl); var V = FlagGroup(FlagM.PF); emitter.Assign(emitter.LoadB(de), emitter.LoadB(hl)); emitter.Assign(hl, incdec(hl, Constant.Int16(1))); emitter.Assign(de, incdec(de, Constant.Int16(1))); emitter.Assign(bc, emitter.ISub(bc, 1)); if (repeat) { emitter.BranchInMiddleOfInstruction(emitter.Ne0(bc), dasm.Current.Address, RtlClass.Transfer); } emitter.Assign(V, emitter.Const(PrimitiveType.Bool, 0)); }
} // the data width of the current instruction being rewritten. /// <summary> /// Rewrite operands being used as sources. /// </summary> /// <param name="operand"></param> /// <param name="addrInstr">Address of the current instruction</param> /// <returns></returns> public Expression RewriteSrc(MachineOperand operand, Address addrInstr, bool addressAsAddress = false) { var reg = operand as RegisterOperand; if (reg != null) { Expression r = binder.EnsureRegister(reg.Register); if (DataWidth != null && DataWidth.Size != reg.Width.Size) { r = m.Cast(DataWidth, r); } return(r); } var imm = operand as M68kImmediateOperand; if (imm != null) { if (imm.Width.Domain == Domain.Real) { return(imm.Constant.CloneExpression()); } if (DataWidth != null && DataWidth.BitSize > imm.Width.BitSize) { return(Constant.Create(DataWidth, imm.Constant.ToInt64())); } else { return(Constant.Create(imm.Width, imm.Constant.ToUInt32())); } } var mem = operand as MemoryOperand; if (mem != null) { return(RewriteMemoryAccess(mem, DataWidth, addrInstr)); } var addr = operand as M68kAddressOperand; if (addr != null) { if (addressAsAddress) { return(addr.Address); } else { return(m.Mem(DataWidth, addr.Address)); } } var pre = operand as PredecrementMemoryOperand; if (pre != null) { var ea = binder.EnsureRegister(pre.Register); m.Assign(ea, m.ISub(ea, m.Int32(DataWidth.Size))); return(m.Mem(DataWidth, ea)); } var post = operand as PostIncrementMemoryOperand; if (post != null) { var r = binder.EnsureRegister(post.Register); var tmp = binder.CreateTemporary(DataWidth); m.Assign(tmp, m.Mem(DataWidth, r)); m.Assign(r, m.IAdd(r, m.Int32(DataWidth.Size))); return(tmp); } var indidx = operand as IndirectIndexedOperand; if (indidx != null) { Expression ea = RewriteIndirectBaseRegister(indidx, addrInstr); Expression ix = binder.EnsureRegister(indidx.XRegister); if (indidx.XWidth.Size != 4) { ix = m.Cast(PrimitiveType.Int32, m.Cast(PrimitiveType.Int16, ix)); } if (indidx.Scale > 1) { ix = m.IMul(ix, Constant.Int32(indidx.Scale)); } return(m.Mem(DataWidth, m.IAdd(ea, ix))); } var indop = operand as IndexedOperand; if (indop != null) { Expression ea = Combine(indop.Base, indop.base_reg); if (indop.postindex) { ea = m.Mem32(ea); } if (indop.index_reg != null) { var idx = Combine(null, indop.index_reg); if (indop.index_reg_width.BitSize != 32) { idx = m.Cast(PrimitiveType.Word32, m.Cast(PrimitiveType.Int16, idx)); } if (indop.index_scale > 1) { idx = m.IMul(idx, indop.index_scale); } ea = Combine(ea, idx); } if (indop.preindex) { ea = m.Mem32(ea); } ea = Combine(ea, indop.outer); return(m.Mem(DataWidth, ea)); } throw new NotImplementedException("Unimplemented RewriteSrc for operand type " + operand.GetType().Name); }
public IEnumerator <RtlInstructionCluster> GetEnumerator() { while (dasm.MoveNext()) { instr = dasm.Current; var addr = instr.Address; var len = instr.Length; rtlInstructions = new List <RtlInstruction>(); rtlc = instr.InstructionClass; m = new RtlEmitter(rtlInstructions); orw = new OperandRewriter(arch, this.m, this.binder, instr.dataWidth); switch (instr.Mnemonic) { default: host.Warn( instr.Address, "M68k instruction '{0}' is not supported yet.", instr.Mnemonic); m.Invalid(); break; case Mnemonic.illegal: RewriteIllegal(); break; case Mnemonic.abcd: RewriteAbcd(); break; case Mnemonic.add: RewriteBinOp((s, d) => m.IAdd(d, s), FlagM.CVZNX); break; case Mnemonic.adda: RewriteBinOp((s, d) => m.IAdd(d, s)); break; case Mnemonic.addi: RewriteArithmetic((s, d) => m.IAdd(d, s)); break; case Mnemonic.addq: RewriteAddSubq((s, d) => m.IAdd(d, s)); break; case Mnemonic.addx: RewriteAddSubx(m.IAdd); break; case Mnemonic.and: RewriteLogical((s, d) => m.And(d, s)); break; case Mnemonic.andi: RewriteLogical((s, d) => m.And(d, s)); break; case Mnemonic.asl: RewriteArithmetic((s, d) => m.Shl(d, s)); break; case Mnemonic.asr: RewriteShift((s, d) => m.Sar(d, s)); break; /* * * Mnemonic Condition Encoding Test * T* True 0000 1 * F* False 0001 0 * HI High 0010 C L Z * LS Low or Same 0011 C V Z * VC Overflow Clear 1000 V * VS Overflow Set 1001 V */ case Mnemonic.bclr: RewriteBclrBset("__bclr"); break; case Mnemonic.bcc: RewriteBcc(ConditionCode.UGE, FlagM.CF); break; case Mnemonic.bcs: RewriteBcc(ConditionCode.ULT, FlagM.CF); break; case Mnemonic.beq: RewriteBcc(ConditionCode.EQ, FlagM.ZF); break; case Mnemonic.bge: RewriteBcc(ConditionCode.GE, FlagM.NF | FlagM.VF); break; case Mnemonic.bgt: RewriteBcc(ConditionCode.GT, FlagM.NF | FlagM.VF | FlagM.ZF); break; case Mnemonic.bhi: RewriteBcc(ConditionCode.UGT, FlagM.CF | FlagM.ZF); break; case Mnemonic.ble: RewriteBcc(ConditionCode.LE, FlagM.NF | FlagM.VF | FlagM.ZF); break; case Mnemonic.bls: RewriteBcc(ConditionCode.ULE, FlagM.CF | FlagM.ZF); break; case Mnemonic.blt: RewriteBcc(ConditionCode.LT, FlagM.NF | FlagM.VF); break; case Mnemonic.bmi: RewriteBcc(ConditionCode.LT, FlagM.NF); break; case Mnemonic.bne: RewriteBcc(ConditionCode.NE, FlagM.ZF); break; case Mnemonic.bpl: RewriteBcc(ConditionCode.GT, FlagM.NF); break; case Mnemonic.bvc: RewriteBcc(ConditionCode.NO, FlagM.VF); break; case Mnemonic.bvs: RewriteBcc(ConditionCode.OV, FlagM.VF); break; case Mnemonic.bchg: RewriteBchg(); break; case Mnemonic.bkpt: RewriteBkpt(); break; case Mnemonic.bra: RewriteBra(); break; case Mnemonic.bset: RewriteBclrBset("__bset"); break; case Mnemonic.bsr: RewriteBsr(); break; case Mnemonic.btst: RewriteBtst(); break; case Mnemonic.callm: RewriteCallm(); break; case Mnemonic.cas: RewriteCas(); break; case Mnemonic.clr: RewriteClr(); break; case Mnemonic.chk: RewriteChk(); break; case Mnemonic.chk2: RewriteChk2(); break; case Mnemonic.cmp: RewriteCmp(); break; case Mnemonic.cmp2: RewriteCmp2(); break; case Mnemonic.cmpa: RewriteCmp(); break; case Mnemonic.cmpi: RewriteCmp(); break; case Mnemonic.cmpm: RewriteCmp(); break; case Mnemonic.dbcc: RewriteDbcc(ConditionCode.UGE, FlagM.CF); break; case Mnemonic.dbcs: RewriteDbcc(ConditionCode.ULT, FlagM.CF); break; case Mnemonic.dbeq: RewriteDbcc(ConditionCode.EQ, FlagM.ZF); break; case Mnemonic.dbge: RewriteDbcc(ConditionCode.GE, FlagM.NF | FlagM.VF); break; case Mnemonic.dbgt: RewriteDbcc(ConditionCode.GE, FlagM.NF | FlagM.VF | FlagM.ZF); break; case Mnemonic.dbhi: RewriteDbcc(ConditionCode.UGT, FlagM.CF | FlagM.ZF); break; case Mnemonic.dble: RewriteDbcc(ConditionCode.GT, FlagM.NF | FlagM.VF | FlagM.ZF); break; case Mnemonic.dbls: RewriteDbcc(ConditionCode.ULE, FlagM.CF | FlagM.ZF); break; case Mnemonic.dblt: RewriteDbcc(ConditionCode.LT, FlagM.NF | FlagM.VF); break; case Mnemonic.dbmi: RewriteDbcc(ConditionCode.LT, FlagM.NF); break; case Mnemonic.dbne: RewriteDbcc(ConditionCode.NE, FlagM.ZF); break; case Mnemonic.dbpl: RewriteDbcc(ConditionCode.GT, FlagM.NF); break; case Mnemonic.dbt: RewriteDbcc(ConditionCode.ALWAYS, 0); break; case Mnemonic.dbra: RewriteDbcc(ConditionCode.None, 0); break; case Mnemonic.divs: RewriteDiv(m.SDiv, PrimitiveType.Int16); break; case Mnemonic.divsl: RewriteDiv(m.SDiv, PrimitiveType.Int32); break; case Mnemonic.divu: RewriteDiv(m.UDiv, PrimitiveType.UInt16); break; case Mnemonic.divul: RewriteDiv(m.UDiv, PrimitiveType.UInt32); break; case Mnemonic.eor: RewriteLogical((s, d) => m.Xor(d, s)); break; case Mnemonic.eori: RewriteLogical((s, d) => m.Xor(d, s)); break; case Mnemonic.exg: RewriteExg(); break; case Mnemonic.ext: RewriteExt(); break; case Mnemonic.extb: RewriteExtb(); break; case Mnemonic.fadd: RewriteFBinOp((s, d) => m.FAdd(d, s)); break; //$REVIEW: the following don't respect NaN, but NaN typically doesn't exist in HLLs. case Mnemonic.fbf: m.Nop(); break; case Mnemonic.fblt: RewriteFbcc(ConditionCode.LT); break; case Mnemonic.fbgl: RewriteFbcc(ConditionCode.NE); break; case Mnemonic.fbgt: RewriteFbcc(ConditionCode.GT); break; case Mnemonic.fbgle: RewriteFbcc(ConditionCode.NE); break; //$BUG: should be !is_nan case Mnemonic.fbne: RewriteFbcc(ConditionCode.NE); break; case Mnemonic.fbnge: RewriteFbcc(ConditionCode.LT); break; case Mnemonic.fbngl: RewriteFbcc(ConditionCode.EQ); break; case Mnemonic.fbngle: RewriteFbcc(ConditionCode.EQ); break; //$BUG: should be is_nan case Mnemonic.fbnlt: RewriteFbcc(ConditionCode.GE); break; case Mnemonic.fbnle: RewriteFbcc(ConditionCode.GT); break; case Mnemonic.fbogl: RewriteFbcc(ConditionCode.NE); break; case Mnemonic.fbole: RewriteFbcc(ConditionCode.LE); break; case Mnemonic.fbolt: RewriteFbcc(ConditionCode.LT); break; case Mnemonic.fbogt: RewriteFbcc(ConditionCode.GT); break; case Mnemonic.fbor: RewriteFbcc(ConditionCode.EQ); break; //$REVIEW: is this correct? case Mnemonic.fbseq: RewriteFbcc(ConditionCode.EQ); break; case Mnemonic.fbsf: RewriteFbcc(ConditionCode.NEVER); break; case Mnemonic.fbsne: RewriteFbcc(ConditionCode.NE); break; case Mnemonic.fbst: RewriteFbcc(ConditionCode.ALWAYS); break; case Mnemonic.fbuge: RewriteFbcc(ConditionCode.GE); break; case Mnemonic.fbugt: RewriteFbcc(ConditionCode.GT); break; case Mnemonic.fbult: RewriteFbcc(ConditionCode.LT); break; case Mnemonic.fbun: RewriteFbcc(ConditionCode.IS_NAN); break; case Mnemonic.fasin: RewriteFasin(); break; case Mnemonic.fintrz: RewriteFintrz(); break; case Mnemonic.fcmp: RewriteFcmp(); break; case Mnemonic.fdiv: RewriteFBinOp((s, d) => m.FDiv(d, s)); break; case Mnemonic.fmove: RewriteFmove(); break; case Mnemonic.fmovecr: RewriteFmovecr(); break; case Mnemonic.fmovem: RewriteMovem(i => Registers.GetRegister(i + Registers.fp0.Number)); break; case Mnemonic.fmul: RewriteFBinOp((s, d) => m.FMul(d, s)); break; case Mnemonic.fneg: RewriteFUnaryOp(m.Neg); break; case Mnemonic.fsqrt: RewriteFsqrt(); break; case Mnemonic.fsub: RewriteFBinOp((s, d) => m.FSub(d, s)); break; case Mnemonic.ftan: RewriteFtan(); break; case Mnemonic.jmp: RewriteJmp(); break; case Mnemonic.jsr: RewriteJsr(); break; case Mnemonic.lea: RewriteLea(); break; case Mnemonic.link: RewriteLink(); break; case Mnemonic.lsl: RewriteShift((s, d) => m.Shl(d, s)); break; case Mnemonic.lsr: RewriteShift((s, d) => m.Shr(d, s)); break; case Mnemonic.move: RewriteMove(true); break; case Mnemonic.move16: RewriteMove16(); break; case Mnemonic.movea: RewriteMove(false); break; case Mnemonic.movep: RewriteMovep(); break; case Mnemonic.moveq: RewriteMoveq(); break; case Mnemonic.moves: RewriteMoves(); break; case Mnemonic.movem: RewriteMovem(Registers.GetRegister); break; case Mnemonic.muls: RewriteMul((s, d) => m.SMul(d, s)); break; case Mnemonic.mulu: RewriteMul((s, d) => m.UMul(d, s)); break; case Mnemonic.nbcd: RewriteNbcd(); break; case Mnemonic.neg: RewriteUnary(s => m.Neg(s), AllConditions); break; case Mnemonic.negx: RewriteUnary(RewriteNegx, AllConditions); break; case Mnemonic.nop: m.Nop(); break; case Mnemonic.not: RewriteUnary(s => m.Comp(s), LogicalConditions); break; case Mnemonic.or: RewriteLogical((s, d) => m.Or(d, s)); break; case Mnemonic.ori: RewriteLogical((s, d) => m.Or(d, s)); break; case Mnemonic.pack: RewritePack(); break; case Mnemonic.pea: RewritePea(); break; case Mnemonic.pflushr: RewritePflushr(); break; case Mnemonic.ptest: RewritePtest(); break; case Mnemonic.rol: RewriteRotation(PseudoProcedure.Rol); break; case Mnemonic.ror: RewriteRotation(PseudoProcedure.Ror); break; case Mnemonic.roxl: RewriteRotationX(PseudoProcedure.RolC); break; case Mnemonic.roxr: RewriteRotationX(PseudoProcedure.RorC); break; case Mnemonic.rtd: RewriteRtd(); break; case Mnemonic.rte: RewriteRte(); break; case Mnemonic.rtm: RewriteRtm(); break; case Mnemonic.rts: RewriteRts(); break; case Mnemonic.sbcd: RewriteSbcd(); break; case Mnemonic.scc: RewriteScc(ConditionCode.UGE, FlagM.CF); break; case Mnemonic.scs: RewriteScc(ConditionCode.ULT, FlagM.CF); break; case Mnemonic.seq: RewriteScc(ConditionCode.EQ, FlagM.ZF); break; case Mnemonic.sge: RewriteScc(ConditionCode.GE, FlagM.NF | FlagM.VF); break; case Mnemonic.sgt: RewriteScc(ConditionCode.GT, FlagM.NF | FlagM.VF | FlagM.ZF); break; case Mnemonic.shi: RewriteScc(ConditionCode.UGT, FlagM.CF | FlagM.ZF); break; case Mnemonic.sle: RewriteScc(ConditionCode.LE, FlagM.NF | FlagM.VF | FlagM.ZF); break; case Mnemonic.sls: RewriteScc(ConditionCode.ULE, FlagM.CF | FlagM.ZF); break; case Mnemonic.slt: RewriteScc(ConditionCode.LT, FlagM.NF | FlagM.ZF); break; case Mnemonic.smi: RewriteScc(ConditionCode.LT, FlagM.NF); break; case Mnemonic.sne: RewriteScc(ConditionCode.NE, FlagM.ZF); break; case Mnemonic.spl: RewriteScc(ConditionCode.GT, FlagM.NF); break; case Mnemonic.svc: RewriteScc(ConditionCode.NO, FlagM.VF); break; case Mnemonic.svs: RewriteScc(ConditionCode.OV, FlagM.VF); break; case Mnemonic.st: orw.RewriteMoveDst(instr.Operands[0], instr.Address, PrimitiveType.Bool, Constant.True()); break; case Mnemonic.sf: orw.RewriteMoveDst(instr.Operands[0], instr.Address, PrimitiveType.Bool, Constant.False()); break; case Mnemonic.stop: RewriteStop(); break; case Mnemonic.sub: RewriteArithmetic((s, d) => m.ISub(d, s)); break; case Mnemonic.suba: RewriteBinOp((s, d) => m.ISub(d, s)); break; case Mnemonic.subi: RewriteArithmetic((s, d) => m.ISub(d, s)); break; case Mnemonic.subq: RewriteAddSubq((s, d) => m.ISub(d, s)); break; case Mnemonic.subx: RewriteArithmetic((s, d) => m.ISub(m.ISub(d, s), binder.EnsureFlagGroup(Registers.ccr, (uint)FlagM.XF, "X", PrimitiveType.Bool))); break; case Mnemonic.swap: RewriteSwap(); break; case Mnemonic.trap: RewriteTrap(); break; case Mnemonic.trapcc: RewriteTrapCc(ConditionCode.UGE, FlagM.CF); break; case Mnemonic.trapcs: RewriteTrapCc(ConditionCode.ULT, FlagM.CF); break; case Mnemonic.trapeq: RewriteTrapCc(ConditionCode.EQ, FlagM.ZF); break; case Mnemonic.trapf: RewriteTrapCc(ConditionCode.NEVER, 0); break; case Mnemonic.trapge: RewriteTrapCc(ConditionCode.GE, FlagM.NF | FlagM.VF); break; case Mnemonic.trapgt: RewriteTrapCc(ConditionCode.GT, FlagM.NF | FlagM.VF | FlagM.ZF); break; case Mnemonic.traphi: RewriteTrapCc(ConditionCode.UGT, FlagM.CF | FlagM.ZF); break; case Mnemonic.traple: RewriteTrapCc(ConditionCode.LE, FlagM.NF | FlagM.VF | FlagM.ZF); break; case Mnemonic.traplt: RewriteTrapCc(ConditionCode.LT, FlagM.CF | FlagM.VF); break; case Mnemonic.trapls: RewriteTrapCc(ConditionCode.ULE, FlagM.VF | FlagM.ZF); break; case Mnemonic.trapmi: RewriteTrapCc(ConditionCode.LT, FlagM.NF); break; case Mnemonic.trapne: RewriteTrapCc(ConditionCode.NE, FlagM.ZF); break; case Mnemonic.trappl: RewriteTrapCc(ConditionCode.GT, FlagM.NF); break; case Mnemonic.trapvc: RewriteTrapCc(ConditionCode.NO, FlagM.VF); break; case Mnemonic.trapvs: RewriteTrapCc(ConditionCode.OV, FlagM.VF); break; case Mnemonic.tas: RewriteTas(); break; case Mnemonic.tst: RewriteTst(); break; case Mnemonic.unlk: RewriteUnlk(); break; case Mnemonic.unpk: RewriteUnpk(); break; } yield return(new RtlInstructionCluster( addr, len, rtlInstructions.ToArray()) { Class = rtlc }); } yield break; }
private Expression RewriteJmpSrc(MachineOperand op) { var memOp = op as MemoryOperand; if (memOp == null) { throw new AddressCorrelatedException( instrs.Current.Address, "Invalid addressing mode for transfer functions.", memOp.Mode); } var r = frame.EnsureRegister(memOp.Register); var tmp = frame.CreateTemporary(op.Width); switch (memOp.Mode) { default: throw new AddressCorrelatedException( instrs.Current.Address, "Not implemented: addressing mode {0}.", memOp.Mode); case AddressMode.RegDef: return(r); case AddressMode.Absolute: return(Address.Ptr16(memOp.EffectiveAddress)); case AddressMode.AutoIncr: m.Assign(tmp, m.Load(op.Width, m.Load(PrimitiveType.Ptr16, r))); m.Assign(r, m.IAdd(r, memOp.Width.Size)); break; case AddressMode.AutoIncrDef: m.Assign(tmp, m.Load(op.Width, r)); m.Assign(r, m.IAdd(r, memOp.Width.Size)); break; case AddressMode.AutoDecr: m.Assign(r, m.ISub(r, memOp.Width.Size)); return(m.Load(op.Width, r)); case AddressMode.AutoDecrDef: m.Assign(r, m.ISub(r, memOp.Width.Size)); m.Assign(tmp, m.Load(op.Width, m.Load(PrimitiveType.Ptr16, r))); return(tmp); case AddressMode.Indexed: if (memOp.Register == Registers.pc) { var offset = (short)memOp.EffectiveAddress; var addrBase = (long)rtlCluster.Address.ToLinear(); var addr = Address.Ptr16((ushort)(2 + addrBase + offset)); return(addr); } else { return(m.Load( this.instrs.Current.DataWidth, m.IAdd(r, Constant.Word16(memOp.EffectiveAddress)))); } case AddressMode.IndexedDef: if (memOp.Register == Registers.pc) { var offset = (short)memOp.EffectiveAddress; var addrBase = (long)rtlCluster.Address.ToLinear() + rtlCluster.Length; var addr = Constant.Word16((ushort)(addrBase + offset)); return(m.Load( PrimitiveType.Word16, addr)); } else { return(m.Load( PrimitiveType.Ptr16, m.IAdd(r, Constant.Word16(memOp.EffectiveAddress)))); } } return(tmp); /* * var immOp = op as ImmediateOperand; * if (immOp != null) * { * return immOp.Value; * } * var addrOp = op as AddressOperand; * if (addrOp != null) * { * return addrOp.Address; * } * throw new NotImplementedException(); */ }
private Expression RewriteJmpSrc(MachineOperand op) { var memOp = op as MemoryOperand; if (memOp == null) { // PDP-11 always has a memory reference // for the destination of a transfer instruction. return(null); } var r = memOp.Register != null ? binder.EnsureRegister(memOp.Register) : null; var tmp = binder.CreateTemporary(op.Width); switch (memOp.Mode) { default: throw new AddressCorrelatedException( dasm.Current.Address, "Not implemented: addressing mode {0}.", memOp.Mode); case AddressMode.RegDef: return(r); case AddressMode.Absolute: return(Address.Ptr16(memOp.EffectiveAddress)); case AddressMode.AutoIncr: m.Assign(tmp, m.Mem(PrimitiveType.Ptr16, r)); m.Assign(r, m.IAdd(r, memOp.Width.Size)); break; case AddressMode.AutoIncrDef: m.Assign(tmp, m.Mem(op.Width, r)); m.Assign(r, m.IAdd(r, memOp.Width.Size)); break; case AddressMode.AutoDecr: m.Assign(r, m.ISub(r, memOp.Width.Size)); return(m.Mem(op.Width, r)); case AddressMode.AutoDecrDef: m.Assign(r, m.ISub(r, memOp.Width.Size)); m.Assign(tmp, m.Mem(op.Width, m.Mem(PrimitiveType.Ptr16, r))); return(tmp); case AddressMode.Indexed: if (memOp.Register == Registers.pc) { var offset = (short)memOp.EffectiveAddress; var addrBase = (long)instr.Address.ToLinear(); var addr = Address.Ptr16((ushort)(instr.Length + addrBase + offset)); return(addr); } else { return(m.Mem( this.dasm.Current.DataWidth, m.IAdd(r, Constant.Word16(memOp.EffectiveAddress)))); } case AddressMode.IndexedDef: if (memOp.Register == Registers.pc) { var offset = (short)memOp.EffectiveAddress; var addrBase = (long)instr.Address.ToLinear() + instr.Length; var addr = Constant.Word16((ushort)(addrBase + offset)); return(m.Mem( PrimitiveType.Word16, addr)); } else { return(m.Mem( PrimitiveType.Ptr16, m.IAdd(r, Constant.Word16(memOp.EffectiveAddress)))); } } return(tmp); /* * var immOp = op as ImmediateOperand; * if (immOp != null) * { * return immOp.Value; * } * var addrOp = op as AddressOperand; * if (addrOp != null) * { * return addrOp.Address; * } * throw new NotImplementedException(); */ }
private Expression RewriteCondition(Expression left, Expression right) { Expression e; switch (instr.Condition.Type) { case ConditionType.Tr: e = Constant.True(); break; case ConditionType.Never: case ConditionType.Never64: e = Constant.False(); break; case ConditionType.Eq: case ConditionType.Eq64: e = m.Eq(left, right); break; case ConditionType.Ne: case ConditionType.Ne64: e = m.Ne(left, right); break; case ConditionType.Lt: case ConditionType.Lt64: e = m.Lt(left, right); break; case ConditionType.Le: case ConditionType.Le64: e = m.Le(left, right); break; case ConditionType.Ge: case ConditionType.Ge64: e = m.Ge(left, right); break; case ConditionType.Gt: case ConditionType.Gt64: e = m.Gt(left, right); break; case ConditionType.Ult: case ConditionType.Ult64: e = m.Ult(left, right); break; case ConditionType.Ule: case ConditionType.Ule64: e = m.Ule(left, right); break; case ConditionType.Uge: case ConditionType.Uge64: e = m.Uge(left, right); break; case ConditionType.Ugt: case ConditionType.Ugt64: e = m.Ugt(left, right); break; case ConditionType.Uv: case ConditionType.Uv64: e = m.Test(ConditionCode.NO, m.USub(left, right)); break; case ConditionType.Sv: case ConditionType.Sv64: e = m.Test(ConditionCode.NO, m.ISub(left, right)); break; case ConditionType.Nuv: case ConditionType.Nuv64: e = m.Test(ConditionCode.OV, m.USub(left, right)); break; case ConditionType.Nsv: case ConditionType.Nsv64: e = m.Test(ConditionCode.OV, m.ISub(left, right)); break; case ConditionType.Even: case ConditionType.Even64: e = m.Eq0(m.And(left, 1)); break; case ConditionType.Odd: case ConditionType.Odd64: e = m.Ne0(m.And(left, 1)); break; case ConditionType.Vnz: case ConditionType.Vnz64: e = m.And(m.Eq(left, right), m.Test(ConditionCode.NO, m.ISub(left, right))); break; case ConditionType.Znv: case ConditionType.Znv64: e = m.And(m.Ne(left, right), m.Test(ConditionCode.OV, m.ISub(left, right))); break; default: throw new NotImplementedException(instr.Condition.ToString()); } return(e); }