// Copyright 2024 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package s390xasm import ( "encoding/binary" "fmt" ) // instFormat is a decoding rule for one specific instruction form. // An instruction ins matches the rule if ins&Mask == Value. // DontCare bits are mainly used for finding the same instruction // name differing with the number of argument fields. // The Args are stored in the same order as the instruction manual. type instFormat struct { Op Op Mask uint64 Value uint64 DontCare uint64 Args [8]*argField } // argField indicate how to decode an argument to an instruction. // First parse the value from the BitFields, shift it left by Shift // bits to get the actual numerical value. type argField struct { Type ArgType flags uint16 BitField } // Parse parses the Arg out from the given binary instruction i. func (a argField) Parse(i uint64) Arg { switch a.Type { default: return nil case TypeUnknown: return nil case TypeReg: return R0 + Reg(a.BitField.Parse(i)) case TypeFPReg: return F0 + Reg(a.BitField.Parse(i)) case TypeCReg: return C0 + Reg(a.BitField.Parse(i)) case TypeACReg: return A0 + Reg(a.BitField.Parse(i)) case TypeBaseReg: return B0 + Base(a.BitField.Parse(i)) case TypeIndexReg: return X0 + Index(a.BitField.Parse(i)) case TypeDispUnsigned: return Disp12(a.BitField.Parse(i)) case TypeDispSigned20: return Disp20(a.BitField.ParseSigned(i)) case TypeVecReg: m := i >> 24 // Handling RXB field(bits 36 to 39) if ((m>>3)&0x1 == 1) && (a.BitField.Offs == 8) { return V0 + VReg(a.BitField.Parse(i)) + VReg(16) } else if ((m>>2)&0x1 == 1) && (a.BitField.Offs == 12) { return V0 + VReg(a.BitField.Parse(i)) + VReg(16) } else if ((m>>1)&0x1 == 1) && (a.BitField.Offs == 16) { return V0 + VReg(a.BitField.Parse(i)) + VReg(16) } else if ((m)&0x1 == 1) && (a.BitField.Offs == 32) { return V0 + VReg(a.BitField.Parse(i)) + VReg(16) } else { return V0 + VReg(a.BitField.Parse(i)) } case TypeImmSigned8: return Sign8(a.BitField.ParseSigned(i)) case TypeImmSigned16: return Sign16(a.BitField.ParseSigned(i)) case TypeImmSigned32: return Sign32(a.BitField.ParseSigned(i)) case TypeImmUnsigned: return Imm(a.BitField.Parse(i)) case TypeRegImSigned12: return RegIm12(a.BitField.ParseSigned(i)) case TypeRegImSigned16: return RegIm16(a.BitField.ParseSigned(i)) case TypeRegImSigned24: return RegIm24(a.BitField.ParseSigned(i)) case TypeRegImSigned32: return RegIm32(a.BitField.ParseSigned(i)) case TypeMask: return Mask(a.BitField.Parse(i)) case TypeLen: return Len(a.BitField.Parse(i)) } } type ArgType int8 const ( TypeUnknown ArgType = iota TypeReg // integer register TypeFPReg // floating point register TypeACReg // access register TypeCReg // control register TypeVecReg // vector register TypeImmUnsigned // unsigned immediate/flag/mask, this is the catch-all type TypeImmSigned8 // Signed 8-bit Immdediate TypeImmSigned16 // Signed 16-bit Immdediate TypeImmSigned32 // Signed 32-bit Immdediate TypeBaseReg // Base Register for accessing memory TypeIndexReg // Index Register TypeDispUnsigned // Displacement 12-bit unsigned for memory address TypeDispSigned20 // Displacement 20-bit signed for memory address TypeRegImSigned12 // RegisterImmediate 12-bit signed data TypeRegImSigned16 // RegisterImmediate 16-bit signed data TypeRegImSigned24 // RegisterImmediate 24-bit signed data TypeRegImSigned32 // RegisterImmediate 32-bit signed data TypeMask // 4-bit Mask TypeLen // Length of Memory Operand TypeLast ) func (t ArgType) String() string { switch t { default: return fmt.Sprintf("ArgType(%d)", int(t)) case TypeUnknown: return "Unknown" case TypeReg: return "Reg" case TypeFPReg: return "FPReg" case TypeACReg: return "ACReg" case TypeCReg: return "CReg" case TypeDispUnsigned: return "DispUnsigned" case TypeDispSigned20: return "DispSigned20" case TypeBaseReg: return "BaseReg" case TypeIndexReg: return "IndexReg" case TypeVecReg: return "VecReg" case TypeImmSigned8: return "ImmSigned8" case TypeImmSigned16: return "ImmSigned16" case TypeImmSigned32: return "ImmSigned32" case TypeImmUnsigned: return "ImmUnsigned" case TypeRegImSigned12: return "RegImSigned12" case TypeRegImSigned16: return "RegImSigned16" case TypeRegImSigned24: return "RegImSigned24" case TypeRegImSigned32: return "RegImSigned32" case TypeMask: return "Mask" case TypeLen: return "Len" } } func (t ArgType) GoString() string { s := t.String() if t > 0 && t < TypeLast { return "Type" + s } return s } var ( // Errors errShort = fmt.Errorf("truncated instruction") errUnknown = fmt.Errorf("unknown instruction") ) var decoderCover []bool // Decode decodes the leading bytes in src as a single instruction using // byte order ord. func Decode(src []byte) (inst Inst, err error) { if len(src) < 2 { return inst, errShort } if decoderCover == nil { decoderCover = make([]bool, len(instFormats)) } bit_check := binary.BigEndian.Uint16(src[:2]) bit_check = bit_check >> 14 l := int(0) if (bit_check & 0x03) == 0 { l = 2 } else if bit_check&0x03 == 3 { l = 6 } else if (bit_check&0x01 == 1) || (bit_check&0x02 == 2) { l = 4 } inst.Len = l ui_extn := uint64(0) switch l { case 2: ui_extn = uint64(binary.BigEndian.Uint16(src[:inst.Len])) inst.Enc = ui_extn ui_extn = ui_extn << 48 case 4: ui_extn = uint64(binary.BigEndian.Uint32(src[:inst.Len])) inst.Enc = ui_extn ui_extn = ui_extn << 32 case 6: u1 := binary.BigEndian.Uint32(src[:(inst.Len - 2)]) u2 := binary.BigEndian.Uint16(src[(inst.Len - 2):inst.Len]) ui_extn = uint64(u1)<<16 | uint64(u2) ui_extn = ui_extn << 16 inst.Enc = ui_extn default: return inst, errShort } for _, iform := range instFormats { if ui_extn&iform.Mask != iform.Value { continue } if (iform.DontCare & ^(ui_extn)) != iform.DontCare { continue } for j, argfield := range iform.Args { if argfield == nil { break } inst.Args[j] = argfield.Parse(ui_extn) } inst.Op = iform.Op break } if inst.Op == 0 && inst.Enc != 0 { return inst, errUnknown } return inst, nil }