func decodeArg()

in arm/armasm/decode.go [198:549]


func decodeArg(aop instArg, x uint32) Arg {
	switch aop {
	default:
		return nil

	case arg_APSR:
		return APSR
	case arg_FPSCR:
		return FPSCR

	case arg_R_0:
		return Reg(x & (1<<4 - 1))
	case arg_R_8:
		return Reg((x >> 8) & (1<<4 - 1))
	case arg_R_12:
		return Reg((x >> 12) & (1<<4 - 1))
	case arg_R_16:
		return Reg((x >> 16) & (1<<4 - 1))

	case arg_R_12_nzcv:
		r := Reg((x >> 12) & (1<<4 - 1))
		if r == R15 {
			return APSR_nzcv
		}
		return r

	case arg_R_16_WB:
		mode := AddrLDM
		if (x>>21)&1 != 0 {
			mode = AddrLDM_WB
		}
		return Mem{Base: Reg((x >> 16) & (1<<4 - 1)), Mode: mode}

	case arg_R_rotate:
		Rm := Reg(x & (1<<4 - 1))
		typ, count := decodeShift(x)
		// ROR #0 here means ROR #0, but decodeShift rewrites to RRX #1.
		if typ == RotateRightExt {
			return Reg(Rm)
		}
		return RegShift{Rm, typ, uint8(count)}

	case arg_R_shift_R:
		Rm := Reg(x & (1<<4 - 1))
		Rs := Reg((x >> 8) & (1<<4 - 1))
		typ := Shift((x >> 5) & (1<<2 - 1))
		return RegShiftReg{Rm, typ, Rs}

	case arg_R_shift_imm:
		Rm := Reg(x & (1<<4 - 1))
		typ, count := decodeShift(x)
		if typ == ShiftLeft && count == 0 {
			return Reg(Rm)
		}
		return RegShift{Rm, typ, uint8(count)}

	case arg_R1_0:
		return Reg((x & (1<<4 - 1)))
	case arg_R1_12:
		return Reg(((x >> 12) & (1<<4 - 1)))
	case arg_R2_0:
		return Reg((x & (1<<4 - 1)) | 1)
	case arg_R2_12:
		return Reg(((x >> 12) & (1<<4 - 1)) | 1)

	case arg_SP:
		return SP

	case arg_Sd_Dd:
		v := (x >> 12) & (1<<4 - 1)
		vx := (x >> 22) & 1
		sz := (x >> 8) & 1
		if sz != 0 {
			return D0 + Reg(vx<<4+v)
		} else {
			return S0 + Reg(v<<1+vx)
		}

	case arg_Dd_Sd:
		return decodeArg(arg_Sd_Dd, x^(1<<8))

	case arg_Sd:
		v := (x >> 12) & (1<<4 - 1)
		vx := (x >> 22) & 1
		return S0 + Reg(v<<1+vx)

	case arg_Sm_Dm:
		v := (x >> 0) & (1<<4 - 1)
		vx := (x >> 5) & 1
		sz := (x >> 8) & 1
		if sz != 0 {
			return D0 + Reg(vx<<4+v)
		} else {
			return S0 + Reg(v<<1+vx)
		}

	case arg_Sm:
		v := (x >> 0) & (1<<4 - 1)
		vx := (x >> 5) & 1
		return S0 + Reg(v<<1+vx)

	case arg_Dn_half:
		v := (x >> 16) & (1<<4 - 1)
		vx := (x >> 7) & 1
		return RegX{D0 + Reg(vx<<4+v), int((x >> 21) & 1)}

	case arg_Sn_Dn:
		v := (x >> 16) & (1<<4 - 1)
		vx := (x >> 7) & 1
		sz := (x >> 8) & 1
		if sz != 0 {
			return D0 + Reg(vx<<4+v)
		} else {
			return S0 + Reg(v<<1+vx)
		}

	case arg_Sn:
		v := (x >> 16) & (1<<4 - 1)
		vx := (x >> 7) & 1
		return S0 + Reg(v<<1+vx)

	case arg_const:
		v := x & (1<<8 - 1)
		rot := (x >> 8) & (1<<4 - 1) * 2
		if rot > 0 && v&3 == 0 {
			// could rotate less
			return ImmAlt{uint8(v), uint8(rot)}
		}
		if rot >= 24 && ((v<<(32-rot))&0xFF)>>(32-rot) == v {
			// could wrap around to rot==0.
			return ImmAlt{uint8(v), uint8(rot)}
		}
		return Imm(v>>rot | v<<(32-rot))

	case arg_endian:
		return Endian((x >> 9) & 1)

	case arg_fbits:
		return Imm((16 << ((x >> 7) & 1)) - ((x&(1<<4-1))<<1 | (x>>5)&1))

	case arg_fp_0:
		return Imm(0)

	case arg_imm24:
		return Imm(x & (1<<24 - 1))

	case arg_imm5:
		return Imm((x >> 7) & (1<<5 - 1))

	case arg_imm5_32:
		x = (x >> 7) & (1<<5 - 1)
		if x == 0 {
			x = 32
		}
		return Imm(x)

	case arg_imm5_nz:
		x = (x >> 7) & (1<<5 - 1)
		if x == 0 {
			return nil
		}
		return Imm(x)

	case arg_imm_4at16_12at0:
		return Imm((x>>16)&(1<<4-1)<<12 | x&(1<<12-1))

	case arg_imm_12at8_4at0:
		return Imm((x>>8)&(1<<12-1)<<4 | x&(1<<4-1))

	case arg_imm_vfp:
		x = (x>>16)&(1<<4-1)<<4 | x&(1<<4-1)
		return Imm(x)

	case arg_label24:
		imm := (x & (1<<24 - 1)) << 2
		return PCRel(int32(imm<<6) >> 6)

	case arg_label24H:
		h := (x >> 24) & 1
		imm := (x&(1<<24-1))<<2 | h<<1
		return PCRel(int32(imm<<6) >> 6)

	case arg_label_m_12:
		d := int32(x & (1<<12 - 1))
		return Mem{Base: PC, Mode: AddrOffset, Offset: int16(-d)}

	case arg_label_p_12:
		d := int32(x & (1<<12 - 1))
		return Mem{Base: PC, Mode: AddrOffset, Offset: int16(d)}

	case arg_label_pm_12:
		d := int32(x & (1<<12 - 1))
		u := (x >> 23) & 1
		if u == 0 {
			d = -d
		}
		return Mem{Base: PC, Mode: AddrOffset, Offset: int16(d)}

	case arg_label_pm_4_4:
		d := int32((x>>8)&(1<<4-1)<<4 | x&(1<<4-1))
		u := (x >> 23) & 1
		if u == 0 {
			d = -d
		}
		return PCRel(d)

	case arg_lsb_width:
		lsb := (x >> 7) & (1<<5 - 1)
		msb := (x >> 16) & (1<<5 - 1)
		if msb < lsb || msb >= 32 {
			return nil
		}
		return Imm(msb + 1 - lsb)

	case arg_mem_R:
		Rn := Reg((x >> 16) & (1<<4 - 1))
		return Mem{Base: Rn, Mode: AddrOffset}

	case arg_mem_R_pm_R_postindex:
		// Treat [<Rn>],+/-<Rm> like [<Rn>,+/-<Rm>{,<shift>}]{!}
		// by forcing shift bits to <<0 and P=0, W=0 (postindex=true).
		return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^((1<<7-1)<<5|1<<24|1<<21))

	case arg_mem_R_pm_R_W:
		// Treat [<Rn>,+/-<Rm>]{!} like [<Rn>,+/-<Rm>{,<shift>}]{!}
		// by forcing shift bits to <<0.
		return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^((1<<7-1)<<5))

	case arg_mem_R_pm_R_shift_imm_offset:
		// Treat [<Rn>],+/-<Rm>{,<shift>} like [<Rn>,+/-<Rm>{,<shift>}]{!}
		// by forcing P=1, W=0 (index=false, wback=false).
		return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^(1<<21)|1<<24)

	case arg_mem_R_pm_R_shift_imm_postindex:
		// Treat [<Rn>],+/-<Rm>{,<shift>} like [<Rn>,+/-<Rm>{,<shift>}]{!}
		// by forcing P=0, W=0 (postindex=true).
		return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^(1<<24|1<<21))

	case arg_mem_R_pm_R_shift_imm_W:
		Rn := Reg((x >> 16) & (1<<4 - 1))
		Rm := Reg(x & (1<<4 - 1))
		typ, count := decodeShift(x)
		u := (x >> 23) & 1
		w := (x >> 21) & 1
		p := (x >> 24) & 1
		if p == 0 && w == 1 {
			return nil
		}
		sign := int8(+1)
		if u == 0 {
			sign = -1
		}
		mode := AddrMode(uint8(p<<1) | uint8(w^1))
		return Mem{Base: Rn, Mode: mode, Sign: sign, Index: Rm, Shift: typ, Count: count}

	case arg_mem_R_pm_imm12_offset:
		// Treat [<Rn>,#+/-<imm12>] like [<Rn>{,#+/-<imm12>}]{!}
		// by forcing P=1, W=0 (index=false, wback=false).
		return decodeArg(arg_mem_R_pm_imm12_W, x&^(1<<21)|1<<24)

	case arg_mem_R_pm_imm12_postindex:
		// Treat [<Rn>],#+/-<imm12> like [<Rn>{,#+/-<imm12>}]{!}
		// by forcing P=0, W=0 (postindex=true).
		return decodeArg(arg_mem_R_pm_imm12_W, x&^(1<<24|1<<21))

	case arg_mem_R_pm_imm12_W:
		Rn := Reg((x >> 16) & (1<<4 - 1))
		u := (x >> 23) & 1
		w := (x >> 21) & 1
		p := (x >> 24) & 1
		if p == 0 && w == 1 {
			return nil
		}
		sign := int8(+1)
		if u == 0 {
			sign = -1
		}
		imm := int16(x & (1<<12 - 1))
		mode := AddrMode(uint8(p<<1) | uint8(w^1))
		return Mem{Base: Rn, Mode: mode, Offset: int16(sign) * imm}

	case arg_mem_R_pm_imm8_postindex:
		// Treat [<Rn>],#+/-<imm8> like [<Rn>{,#+/-<imm8>}]{!}
		// by forcing P=0, W=0 (postindex=true).
		return decodeArg(arg_mem_R_pm_imm8_W, x&^(1<<24|1<<21))

	case arg_mem_R_pm_imm8_W:
		Rn := Reg((x >> 16) & (1<<4 - 1))
		u := (x >> 23) & 1
		w := (x >> 21) & 1
		p := (x >> 24) & 1
		if p == 0 && w == 1 {
			return nil
		}
		sign := int8(+1)
		if u == 0 {
			sign = -1
		}
		imm := int16((x>>8)&(1<<4-1)<<4 | x&(1<<4-1))
		mode := AddrMode(uint8(p<<1) | uint8(w^1))
		return Mem{Base: Rn, Mode: mode, Offset: int16(sign) * imm}

	case arg_mem_R_pm_imm8at0_offset:
		Rn := Reg((x >> 16) & (1<<4 - 1))
		u := (x >> 23) & 1
		sign := int8(+1)
		if u == 0 {
			sign = -1
		}
		imm := int16(x&(1<<8-1)) << 2
		return Mem{Base: Rn, Mode: AddrOffset, Offset: int16(sign) * imm}

	case arg_option:
		return Imm(x & (1<<4 - 1))

	case arg_registers:
		return RegList(x & (1<<16 - 1))

	case arg_registers2:
		x &= 1<<16 - 1
		n := 0
		for i := 0; i < 16; i++ {
			if x>>uint(i)&1 != 0 {
				n++
			}
		}
		if n < 2 {
			return nil
		}
		return RegList(x)

	case arg_registers1:
		Rt := (x >> 12) & (1<<4 - 1)
		return RegList(1 << Rt)

	case arg_satimm4:
		return Imm((x >> 16) & (1<<4 - 1))

	case arg_satimm5:
		return Imm((x >> 16) & (1<<5 - 1))

	case arg_satimm4m1:
		return Imm((x>>16)&(1<<4-1) + 1)

	case arg_satimm5m1:
		return Imm((x>>16)&(1<<5-1) + 1)

	case arg_widthm1:
		return Imm((x>>16)&(1<<5-1) + 1)

	}
}