
added loong64 support for gnu format disassembler and plan9 format disassembler in golang.org/x/arch $ go get -u golang.org/x/arch@v0.11.0 $ go mod tidy $ go mod vendor Co-authored-by: Huang Qiqi <huangqiqi@loongson.cn>
270 lines
5.6 KiB
Go
270 lines
5.6 KiB
Go
// 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 loong64asm
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
)
|
|
|
|
type instArgs [5]instArg
|
|
|
|
// An instFormat describes the format of an instruction encoding.
|
|
type instFormat struct {
|
|
mask uint32
|
|
value uint32
|
|
op Op
|
|
// args describe how to decode the instruction arguments.
|
|
// args is stored as a fixed-size array.
|
|
// if there are fewer than len(args) arguments, args[i] == 0 marks
|
|
// the end of the argument list.
|
|
args instArgs
|
|
}
|
|
|
|
var (
|
|
errShort = fmt.Errorf("truncated instruction")
|
|
errUnknown = fmt.Errorf("unknown instruction")
|
|
)
|
|
|
|
var decoderCover []bool
|
|
|
|
func init() {
|
|
decoderCover = make([]bool, len(instFormats))
|
|
}
|
|
|
|
// Decode decodes the 4 bytes in src as a single instruction.
|
|
func Decode(src []byte) (inst Inst, err error) {
|
|
if len(src) < 4 {
|
|
return Inst{}, errShort
|
|
}
|
|
|
|
x := binary.LittleEndian.Uint32(src)
|
|
|
|
Search:
|
|
for i := range instFormats {
|
|
f := &instFormats[i]
|
|
|
|
if (x & f.mask) != f.value {
|
|
continue
|
|
}
|
|
|
|
// Decode args.
|
|
var args Args
|
|
for j, aop := range f.args {
|
|
if aop == 0 {
|
|
break
|
|
}
|
|
|
|
arg := decodeArg(aop, x, i)
|
|
if arg == nil {
|
|
// Cannot decode argument
|
|
continue Search
|
|
}
|
|
|
|
args[j] = arg
|
|
}
|
|
|
|
decoderCover[i] = true
|
|
inst = Inst{
|
|
Op: f.op,
|
|
Args: args,
|
|
Enc: x,
|
|
}
|
|
return inst, nil
|
|
}
|
|
|
|
return Inst{}, errUnknown
|
|
}
|
|
|
|
// decodeArg decodes the arg described by aop from the instruction bits x.
|
|
// It returns nil if x cannot be decoded according to aop.
|
|
func decodeArg(aop instArg, x uint32, index int) Arg {
|
|
switch aop {
|
|
case arg_fd:
|
|
return F0 + Reg(x&((1<<5)-1))
|
|
|
|
case arg_fj:
|
|
return F0 + Reg((x>>5)&((1<<5)-1))
|
|
|
|
case arg_fk:
|
|
return F0 + Reg((x>>10)&((1<<5)-1))
|
|
|
|
case arg_fa:
|
|
return F0 + Reg((x>>15)&((1<<5)-1))
|
|
|
|
case arg_rd:
|
|
return R0 + Reg(x&((1<<5)-1))
|
|
|
|
case arg_rj:
|
|
return R0 + Reg((x>>5)&((1<<5)-1))
|
|
|
|
case arg_rk:
|
|
return R0 + Reg((x>>10)&((1<<5)-1))
|
|
|
|
case arg_fcsr_4_0:
|
|
return FCSR0 + Fcsr(x&((1<<5)-1))
|
|
|
|
case arg_fcsr_9_5:
|
|
return FCSR0 + Fcsr((x>>5)&((1<<5)-1))
|
|
|
|
case arg_cd:
|
|
return FCC0 + Fcc(x&((1<<3)-1))
|
|
|
|
case arg_cj:
|
|
return FCC0 + Fcc((x>>5)&((1<<3)-1))
|
|
|
|
case arg_ca:
|
|
return FCC0 + Fcc((x>>15)&((1<<3)-1))
|
|
|
|
case arg_op_4_0:
|
|
tmp := x & ((1 << 5) - 1)
|
|
return Uimm{tmp, false}
|
|
|
|
case arg_csr_23_10:
|
|
tmp := (x >> 10) & ((1 << 14) - 1)
|
|
return Uimm{tmp, false}
|
|
|
|
case arg_sa2_16_15:
|
|
f := &instFormats[index]
|
|
tmp := SaSimm((x >> 15) & ((1 << 2) - 1))
|
|
if (f.op == ALSL_D) || (f.op == ALSL_W) || (f.op == ALSL_WU) {
|
|
return tmp + 1
|
|
} else {
|
|
return tmp + 0
|
|
}
|
|
|
|
case arg_sa3_17_15:
|
|
return SaSimm((x >> 15) & ((1 << 3) - 1))
|
|
|
|
case arg_code_4_0:
|
|
return CodeSimm(x & ((1 << 5) - 1))
|
|
|
|
case arg_code_14_0:
|
|
return CodeSimm(x & ((1 << 15) - 1))
|
|
|
|
case arg_ui5_14_10:
|
|
tmp := (x >> 10) & ((1 << 5) - 1)
|
|
return Uimm{tmp, false}
|
|
|
|
case arg_ui6_15_10:
|
|
tmp := (x >> 10) & ((1 << 6) - 1)
|
|
return Uimm{tmp, false}
|
|
|
|
case arg_ui12_21_10:
|
|
tmp := ((x >> 10) & ((1 << 12) - 1) & 0xfff)
|
|
return Uimm{tmp, false}
|
|
|
|
case arg_lsbw:
|
|
tmp := (x >> 10) & ((1 << 5) - 1)
|
|
return Uimm{tmp, false}
|
|
|
|
case arg_msbw:
|
|
tmp := (x >> 16) & ((1 << 5) - 1)
|
|
return Uimm{tmp, false}
|
|
|
|
case arg_lsbd:
|
|
tmp := (x >> 10) & ((1 << 6) - 1)
|
|
return Uimm{tmp, false}
|
|
|
|
case arg_msbd:
|
|
tmp := (x >> 16) & ((1 << 6) - 1)
|
|
return Uimm{tmp, false}
|
|
|
|
case arg_hint_4_0:
|
|
tmp := x & ((1 << 5) - 1)
|
|
return Uimm{tmp, false}
|
|
|
|
case arg_hint_14_0:
|
|
tmp := x & ((1 << 15) - 1)
|
|
return Uimm{tmp, false}
|
|
|
|
case arg_level_14_0:
|
|
tmp := x & ((1 << 15) - 1)
|
|
return Uimm{tmp, false}
|
|
|
|
case arg_level_17_10:
|
|
tmp := (x >> 10) & ((1 << 8) - 1)
|
|
return Uimm{tmp, false}
|
|
|
|
case arg_seq_17_10:
|
|
tmp := (x >> 10) & ((1 << 8) - 1)
|
|
return Uimm{tmp, false}
|
|
|
|
case arg_si12_21_10:
|
|
var tmp int16
|
|
|
|
// no int12, so sign-extend a 12-bit signed to 16-bit signed
|
|
if (x & 0x200000) == 0x200000 {
|
|
tmp = int16(((x >> 10) & ((1 << 12) - 1)) | 0xf000)
|
|
} else {
|
|
tmp = int16(((x >> 10) & ((1 << 12) - 1)) | 0x0000)
|
|
}
|
|
return Simm16{tmp, 12}
|
|
|
|
case arg_si14_23_10:
|
|
var tmp int32
|
|
if (x & 0x800000) == 0x800000 {
|
|
tmp = int32((((x >> 10) & ((1 << 14) - 1)) << 2) | 0xffff0000)
|
|
} else {
|
|
tmp = int32((((x >> 10) & ((1 << 14) - 1)) << 2) | 0x00000000)
|
|
}
|
|
return Simm32{tmp, 14}
|
|
|
|
case arg_si16_25_10:
|
|
var tmp int32
|
|
|
|
if (x & 0x2000000) == 0x2000000 {
|
|
tmp = int32(((x >> 10) & ((1 << 16) - 1)) | 0xffff0000)
|
|
} else {
|
|
tmp = int32(((x >> 10) & ((1 << 16) - 1)) | 0x00000000)
|
|
}
|
|
|
|
return Simm32{tmp, 16}
|
|
|
|
case arg_si20_24_5:
|
|
var tmp int32
|
|
if (x & 0x1000000) == 0x1000000 {
|
|
tmp = int32(((x >> 5) & ((1 << 20) - 1)) | 0xfff00000)
|
|
} else {
|
|
tmp = int32(((x >> 5) & ((1 << 20) - 1)) | 0x00000000)
|
|
}
|
|
return Simm32{tmp, 20}
|
|
|
|
case arg_offset_20_0:
|
|
var tmp int32
|
|
|
|
if (x & 0x10) == 0x10 {
|
|
tmp = int32(((((x << 16) | ((x >> 10) & ((1 << 16) - 1))) & ((1 << 21) - 1)) << 2) | 0xff800000)
|
|
} else {
|
|
tmp = int32((((x << 16) | ((x >> 10) & ((1 << 16) - 1))) & ((1 << 21) - 1)) << 2)
|
|
}
|
|
|
|
return OffsetSimm{tmp, 21}
|
|
|
|
case arg_offset_15_0:
|
|
var tmp int32
|
|
if (x & 0x2000000) == 0x2000000 {
|
|
tmp = int32((((x >> 10) & ((1 << 16) - 1)) << 2) | 0xfffc0000)
|
|
} else {
|
|
tmp = int32((((x >> 10) & ((1 << 16) - 1)) << 2) | 0x00000000)
|
|
}
|
|
|
|
return OffsetSimm{tmp, 16}
|
|
|
|
case arg_offset_25_0:
|
|
var tmp int32
|
|
|
|
if (x & 0x200) == 0x200 {
|
|
tmp = int32(((((x << 16) | ((x >> 10) & ((1 << 16) - 1))) & ((1 << 26) - 1)) << 2) | 0xf0000000)
|
|
} else {
|
|
tmp = int32(((((x << 16) | ((x >> 10) & ((1 << 16) - 1))) & ((1 << 26) - 1)) << 2) | 0x00000000)
|
|
}
|
|
|
|
return OffsetSimm{tmp, 26}
|
|
default:
|
|
return nil
|
|
}
|
|
}
|