private Tlcs90Instruction DecodeOperands(byte b, Opcode opcode, string format) { int op = 0; var ops = new MachineOperand[2]; Constant c; PrimitiveType size; for (int i = 0; i < format.Length; ++i) { switch (format[i]) { case ',': continue; case 'a': this.dataWidth = PrimitiveType.Byte; ops[op] = new RegisterOperand(Registers.a); break; case '@': this.dataWidth = PrimitiveType.Word16; ops[op] = new RegisterOperand(Registers.af_); break; case 'A': this.dataWidth = PrimitiveType.Word16; ops[op] = new RegisterOperand(Registers.af); break; case 'B': this.dataWidth = PrimitiveType.Word16; ops[op] = new RegisterOperand(Registers.bc); break; case 'c': ops[op] = new ConditionOperand((CondCode)(b & 0xF)); break; case 'D': this.dataWidth = PrimitiveType.Word16; ops[op] = new RegisterOperand(Registers.de); break; case 'I': // Immediate value this.dataWidth = GetSize(format[++i]); if (!rdr.TryReadLe(this.dataWidth, out c)) { return(null); } ops[op] = new ImmediateOperand(c); break; case 'i': // immediate value from opcode bits ops[op] = ImmediateOperand.Byte((byte)(b & 0x7)); break; case 'g': Debug.Assert(byteReg != null); ops[op] = this.byteReg; break; case 'G': Debug.Assert(wordReg != null); ops[op] = this.wordReg; break; case 'H': ops[op] = new RegisterOperand(Registers.hl); break; case 'J': // Absolute jump. size = GetSize(format[++i]); if (!rdr.TryReadLe(size, out c)) { return(null); } ops[op] = AddressOperand.Ptr16(c.ToUInt16()); break; case 'j': // relative jump size = GetSize(format[++i]); Address dest; if (size.Size == 1) { if (!rdr.TryReadByte(out b)) { return(null); } dest = rdr.Address + (sbyte)b; } else { if (!rdr.TryReadLeInt16(out short off)) { return(null); } dest = rdr.Address + off; } ops[op] = AddressOperand.Create(dest); break; case 'M': this.dataWidth = GetSize(format[++i]); ushort absAddr; if (!rdr.TryReadLeUInt16(out absAddr)) { return(null); } ops[op] = MemoryOperand.Absolute(this.dataWidth, absAddr); break; case 'm': size = GetSize(format[++i]); byte pageAddr; if (!rdr.TryReadByte(out pageAddr)) { return(null); } ops[op] = MemoryOperand.Absolute(size, (ushort)(0xFF00 | pageAddr)); break; case 'S': this.dataWidth = PrimitiveType.Word16; ops[op] = new RegisterOperand(Registers.sp); break; case 'X': this.dataWidth = PrimitiveType.Word16; ops[op] = new RegisterOperand(Registers.ix); break; case 'Y': this.dataWidth = PrimitiveType.Word16; ops[op] = new RegisterOperand(Registers.iy); break; case 'r': // Register encoded in low 3 bits of b. ops[op] = new RegisterOperand(Registers.byteRegs[b & 7]); dataWidth = PrimitiveType.Byte; break; case 'x': this.backPatchOp = op; break; default: throw new NotImplementedException(string.Format("Encoding '{0}' not implemented yet.", format[i])); } ++op; } return(new Tlcs90Instruction { Opcode = opcode, op1 = op > 0 ? ops[0] : null, op2 = op > 1 ? ops[1] : null, }); }
public override Tlcs90Instruction Decode(byte b, Tlcs90Disassembler dasm) { RegisterStorage baseReg = null; RegisterStorage idxReg = null; ushort? absAddr = null; Constant offset = null; switch (format[0]) { case 'M': ushort a; if (!dasm.rdr.TryReadLeUInt16(out a)) { return(null); } absAddr = a; break; case 'm': byte bb; if (!dasm.rdr.TryReadByte(out bb)) { return(null); } absAddr = (ushort)(0xFF00 | bb); break; case 'B': baseReg = Registers.bc; break; case 'D': baseReg = Registers.de; break; case 'H': baseReg = Registers.hl; break; case 'X': baseReg = Registers.ix; break; case 'Y': baseReg = Registers.iy; break; case 'S': baseReg = Registers.sp; break; case 'E': switch (format[1]) { case 'S': baseReg = Registers.sp; break; case 'X': baseReg = Registers.ix; break; case 'Y': baseReg = Registers.ix; break; case 'H': baseReg = Registers.hl; idxReg = Registers.a; break; default: throw new NotImplementedException(string.Format("Tlcs-90: dst {0}", format)); } if (idxReg == null) { if (!dasm.rdr.TryReadByte(out b)) { return(null); } offset = Constant.SByte((sbyte)b); } break; default: throw new NotImplementedException(string.Format("Tlcs-90: dst {0}", format)); } if (!dasm.rdr.TryReadByte(out b)) { return(null); } var instr = dstEncodings[b].Decode(b, dasm); if (instr == null) { return(null); } var operand = new MemoryOperand(dasm.dataWidth) { Base = baseReg, Offset = absAddr.HasValue ? Constant.UInt16(absAddr.Value) : offset, }; if (dasm.backPatchOp == 0) { instr.op1 = operand; if (instr.op2 != null) { instr.op1.Width = instr.op2.Width; } } else if (dasm.backPatchOp == 1) { if ((instr.Opcode == Opcode.jp || instr.Opcode == Opcode.call) && operand.Base == null && operand.Index == null && operand.Offset != null) { // JP cc,(XXXX) should be JP cc,XXXX instr.op2 = AddressOperand.Ptr16(operand.Offset.ToUInt16()); instr.op2.Width = PrimitiveType.Ptr16; } else { instr.op2 = operand; instr.op2.Width = instr.op1.Width; } } else { return(null); } return(instr); }
public AvrInstruction Decode(ushort wInstr, Opcode opcode, string fmt) { var ops = new List <MachineOperand>(); int offset; ushort w2; for (int i = 0; i < fmt.Length; ++i) { MachineOperand op; switch (fmt[i++]) { case ',': continue; case '+': op = IncDec(true, fmt[i++]); break; case '-': op = IncDec(false, fmt[i++]); break; case 'A': // I/O location op = ImmediateOperand.Byte((byte)(((wInstr >> 5) & 0x30) | (wInstr & 0xF))); break; case 'B': // 8-bit immediate at bits 8..11 and 0..3 op = ImmediateOperand.Byte((byte)(((wInstr >> 4) & 0xF0) | (wInstr & 0x0F))); break; case 'g': // 4-bit field in sgis op = ImmediateOperand.Byte((byte)((wInstr >> 3) & 0x0F)); break; case 'h': // 3-bit field in sgis, indicating bit nr. op = ImmediateOperand.Byte((byte)(wInstr & 7)); break; case 'I': // 4-bit immediate at bit 0 op = ImmediateOperand.Byte((byte)(wInstr & 0x0F)); break; case 'i': // 4-bit immediate at bit 4 op = ImmediateOperand.Byte((byte)((wInstr >> 4) & 0x0F)); break; case 'J': // Relative jump offset = (short)((wInstr & 0xFFF) << 4); offset = offset >> 3; op = AddressOperand.Create(this.addr + 2 + offset); break; case 'D': // Destination register op = Register((wInstr >> 4) & 0x1F); break; case 'd': // Destination register (r16-r31) op = Register(0x10 | (wInstr >> 4) & 0x1F); break; case 'R': // source register (5 bits) op = Register((wInstr >> 5) & 0x10 | (wInstr) & 0x0F); break; case 'r': // source register (4 bits) op = Register((wInstr >> 4) & 0x10 | (wInstr >> 4) & 0x0F); break; case 'K': op = ImmediateOperand.Byte((byte)(((wInstr >> 4) & 0xF0) | (wInstr & 0xF))); break; case 'P': // register pair source op = Register((wInstr << 1) & ~1); break; case 'p': // register pair destination op = Register((wInstr >> 3) & ~1); break; case 'Q': // absolute address used by jump and call. if (!rdr.TryReadLeUInt16(out w2)) { return(null); } op = AddressOperand.Ptr32( (uint)(((wInstr >> 4) & 0x1F) << 18) | (uint)((wInstr & 1) << 17) | (uint)(w2 << 1)); break; case 'q': // register pair used by adiw op = Register(24 + ((wInstr >> 3) & 6)); break; case 's': // immediate used by adiw/sbiw op = ImmediateOperand.Byte((byte)(((wInstr >> 2) & 0x30) | (wInstr & 0xF))); break; case 'w': // Trailing 16-bit absolute address if (!rdr.TryReadLeUInt16(out w2)) { return(null); } op = AddressOperand.Ptr16(w2); break; case 'o': // Branch offset offset = (short)wInstr; offset = (short)(offset << 6); offset = (short)(offset >> 8); offset = (short)(offset & ~1); op = AddressOperand.Create(this.addr + offset); break; case 'X': op = MemD(arch.x, 0); break; case 'Y': op = MemD(arch.y, 0); break; case 'y': op = MemD(arch.y, Displacement(wInstr)); break; case 'Z': op = MemD(arch.z, 0); break; case 'z': op = MemD(arch.z, Displacement(wInstr)); break; default: throw new NotImplementedException(string.Format("Unimplemented AVR8 format symbol '{0}'.'", fmt[i - 1])); } ops.Add(op); } return(new AvrInstruction { opcode = opcode, operands = ops.ToArray(), }); }
public override Tlcs90Instruction Decode(uint bPrev, Tlcs90Disassembler dasm) { RegisterStorage?baseReg = null; RegisterStorage?idxReg = null; ushort? absAddr = null; Constant? offset = null; switch (format[0]) { case 'M': if (!dasm.rdr.TryReadLeUInt16(out ushort a)) { return(dasm.CreateInvalidInstruction()); } absAddr = a; break; case 'm': if (!dasm.rdr.TryReadByte(out byte bb)) { return(dasm.CreateInvalidInstruction()); } absAddr = (ushort)(0xFF00 | bb); break; case 'B': baseReg = Registers.bc; break; case 'D': baseReg = Registers.de; break; case 'H': baseReg = Registers.hl; break; case 'X': baseReg = Registers.ix; break; case 'Y': baseReg = Registers.iy; break; case 'S': baseReg = Registers.sp; break; case 'E': switch (format[1]) { case 'S': baseReg = Registers.sp; break; case 'X': baseReg = Registers.ix; break; case 'Y': baseReg = Registers.ix; break; case 'H': baseReg = Registers.hl; idxReg = Registers.a; break; default: throw new NotImplementedException(string.Format("Tlcs-90: dst {0}", format)); } if (idxReg == null) { if (!dasm.rdr.TryReadByte(out byte bOff)) { return(dasm.CreateInvalidInstruction()); } offset = Constant.SByte((sbyte)bOff); } break; default: throw new NotImplementedException(string.Format("Tlcs-90: dst {0}", format)); } if (!dasm.rdr.TryReadByte(out byte b)) { return(dasm.CreateInvalidInstruction()); } var instr = dstEncodings[b].Decode(b, dasm); if (instr == null) { return(dasm.CreateInvalidInstruction()); } var operand = new MemoryOperand(dasm.dataWidth !) { Base = baseReg, Offset = absAddr.HasValue ? Constant.UInt16(absAddr.Value) : offset, }; if (dasm.backPatchOp == 0) { if (instr.Operands.Length == 0) { instr.Operands = new MachineOperand[] { operand }; } else { instr.Operands = new MachineOperand[] { operand, instr.Operands[0] }; } if (instr.Operands.Length == 2) { instr.Operands[0].Width = instr.Operands[1].Width; } } else if (dasm.backPatchOp == 1) { if ((instr.Mnemonic == Mnemonic.jp || instr.Mnemonic == Mnemonic.call) && operand.Base == null && operand.Index == null && operand.Offset != null) { // JP cc,(XXXX) should be JP cc,XXXX var op = AddressOperand.Ptr16(operand.Offset.ToUInt16()); op.Width = PrimitiveType.Ptr16; instr.Operands = new MachineOperand[] { instr.Operands[0], op }; } else { instr.Operands = new MachineOperand[] { instr.Operands[0], operand }; instr.Operands[1].Width = instr.Operands[0].Width; } } else { return(dasm.CreateInvalidInstruction()); } return(instr); }
private i8051Instruction Decode(Opcode opcode, byte uInstr, string fmt) { byte b; var ops = new List <MachineOperand>(); foreach (var ch in fmt) { switch (ch) { case ',': continue; case 'j': // An 11-bit address destination. This argument is used by ACALL and AJMP instructions. The target of the CALL or JMP must lie within the same 2K page as the first byte of the following instruction. if (!rdr.TryReadByte(out b)) { return(null); } ops.Add(AddressOperand.Ptr16( (ushort)( (rdr.Address.ToLinear() & ~0x7Ful) | (uInstr & 0xE0u) << 3 | b))); break; case 'J': // A 16-bit address destination. This argument is used by LCALL and LJMP instructions. if (!rdr.TryReadBeUInt16(out var uAddr)) // Yes, big endian! { return(null); } ops.Add(AddressOperand.Ptr16(uAddr)); break; case 'o': // A signed (two's complement) 8-bit offset (-128 to 127) relative to the first byte of the following instruction. if (!rdr.TryReadByte(out b)) { return(null); } ops.Add(AddressOperand.Create(rdr.Address + (sbyte)b)); break; case 'A': // The accumulator. ops.Add(new RegisterOperand(Registers.A)); break; case 'd': // An internal data RAM location (0-127) or SFR (128-255). if (!rdr.TryReadByte(out b)) { return(null); } ops.Add(MemoryOperand.Direct(Address.Ptr16(b))); break; case 'r': // Register r0-r7 ops.Add(Reg(uInstr & 7)); break; case 'b': // A direct addressed bit in internal data RAM or SFR memory. if (!rdr.TryReadByte(out b)) { return(null); } ops.Add(BitReg(b, false)); break; case 'B': // A direct addressed bit in internal data RAM or SFR memory. if (!rdr.TryReadByte(out b)) { return(null); } ops.Add(BitReg(b, true)); break; case 'C': // C flag of PSW ops.Add(new FlagGroupOperand(arch.GetFlagGroup((uint)FlagM.C))); break; case 'D': // @DPTR ops.Add(MemoryOperand.Indirect(Registers.DPTR)); break; case 'p': // DPTR register pair ops.Add(new SequenceOperand(Registers.DPTR)); break; case 'i': // A constant included in the instruction encoding. if (!rdr.TryReadByte(out b)) { return(null); } ops.Add(ImmediateOperand.Byte(b)); break; case 'I': // A constant included in the instruction encoding. if (!rdr.TryReadUInt16(out var w)) { return(null); } ops.Add(ImmediateOperand.Word16(w)); break; case '@': // @Ri An internal data RAM location (0-255) addressed indirectly through R0 or R1. ops.Add(MemoryOperand.Indirect(Registers.GetRegister(uInstr & 1))); break; case '+': // @A + DPTR: ops.Add(MemoryOperand.Indexed(Registers.DPTR, Registers.A)); break; case 'P': // @A + PC: ops.Add(MemoryOperand.Indexed(Registers.PC, Registers.A)); break; case '*': // AB register pair ops.Add(new SequenceOperand(Registers.AB)); break; default: EmitUnitTest(opcode, uInstr); break; } } return(new i8051Instruction { Opcode = opcode, Address = this.addr, Length = (int)(rdr.Address - this.addr), Operand1 = ops.Count >= 1 ? ops[0] : null, Operand2 = ops.Count >= 2 ? ops[1] : null, Operand3 = ops.Count >= 3 ? ops[2] : null, }); }