
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>
301 lines
4.3 KiB
Go
301 lines
4.3 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 (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// An Inst is a single instruction.
|
|
type Inst struct {
|
|
Op Op // Opcode mnemonic
|
|
Enc uint32 // Raw encoding bits.
|
|
Args Args // Instruction arguments, in Loong64 manual order.
|
|
}
|
|
|
|
func (i Inst) String() string {
|
|
var op string = i.Op.String()
|
|
var args []string
|
|
|
|
for _, arg := range i.Args {
|
|
if arg == nil {
|
|
break
|
|
}
|
|
args = append(args, arg.String())
|
|
}
|
|
|
|
switch i.Op {
|
|
case OR:
|
|
if i.Args[2].(Reg) == R0 {
|
|
op = "move"
|
|
args = args[0:2]
|
|
}
|
|
|
|
case ANDI:
|
|
if i.Args[0].(Reg) == R0 && i.Args[1].(Reg) == R0 {
|
|
return "nop"
|
|
}
|
|
|
|
case JIRL:
|
|
if i.Args[0].(Reg) == R0 && i.Args[1].(Reg) == R1 && i.Args[2].(OffsetSimm).Imm == 0 {
|
|
return "ret"
|
|
} else if i.Args[0].(Reg) == R0 && i.Args[2].(OffsetSimm).Imm == 0 {
|
|
return "jr " + args[1]
|
|
}
|
|
|
|
case BLT:
|
|
if i.Args[0].(Reg) == R0 {
|
|
op = "bgtz"
|
|
args = args[1:]
|
|
} else if i.Args[1].(Reg) == R0 {
|
|
op = "bltz"
|
|
args = append(args[:1], args[2:]...)
|
|
}
|
|
|
|
case BGE:
|
|
if i.Args[0].(Reg) == R0 {
|
|
op = "blez"
|
|
args = args[1:]
|
|
} else if i.Args[1].(Reg) == R0 {
|
|
op = "bgez"
|
|
args = append(args[:1], args[2:]...)
|
|
}
|
|
}
|
|
|
|
if len(args) == 0 {
|
|
return op
|
|
} else {
|
|
return op + " " + strings.Join(args, ", ")
|
|
}
|
|
}
|
|
|
|
// An Op is an Loong64 opcode.
|
|
type Op uint16
|
|
|
|
// NOTE: The actual Op values are defined in tables.go.
|
|
// They are chosen to simplify instruction decoding and
|
|
// are not a dense packing from 0 to N, although the
|
|
// density is high, probably at least 90%.
|
|
func (op Op) String() string {
|
|
if (op >= Op(len(opstr))) || (opstr[op] == "") {
|
|
return fmt.Sprintf("Op(%d)", int(op))
|
|
}
|
|
|
|
return opstr[op]
|
|
}
|
|
|
|
// An Args holds the instruction arguments.
|
|
// If an instruction has fewer than 5 arguments,
|
|
// the final elements in the array are nil.
|
|
type Args [5]Arg
|
|
|
|
// An Arg is a single instruction argument
|
|
type Arg interface {
|
|
String() string
|
|
}
|
|
|
|
// A Reg is a single register.
|
|
// The zero value denotes R0, not the absence of a register.
|
|
type Reg uint16
|
|
|
|
const (
|
|
// General-purpose register
|
|
R0 Reg = iota
|
|
R1
|
|
R2
|
|
R3
|
|
R4
|
|
R5
|
|
R6
|
|
R7
|
|
R8
|
|
R9
|
|
R10
|
|
R11
|
|
R12
|
|
R13
|
|
R14
|
|
R15
|
|
R16
|
|
R17
|
|
R18
|
|
R19
|
|
R20
|
|
R21
|
|
R22
|
|
R23
|
|
R24
|
|
R25
|
|
R26
|
|
R27
|
|
R28
|
|
R29
|
|
R30
|
|
R31
|
|
|
|
// Float point register
|
|
F0
|
|
F1
|
|
F2
|
|
F3
|
|
F4
|
|
F5
|
|
F6
|
|
F7
|
|
F8
|
|
F9
|
|
F10
|
|
F11
|
|
F12
|
|
F13
|
|
F14
|
|
F15
|
|
F16
|
|
F17
|
|
F18
|
|
F19
|
|
F20
|
|
F21
|
|
F22
|
|
F23
|
|
F24
|
|
F25
|
|
F26
|
|
F27
|
|
F28
|
|
F29
|
|
F30
|
|
F31
|
|
)
|
|
|
|
func (r Reg) String() string {
|
|
switch {
|
|
case r == R0:
|
|
return "$zero"
|
|
|
|
case r == R1:
|
|
return "$ra"
|
|
|
|
case r == R2:
|
|
return "$tp"
|
|
|
|
case r == R3:
|
|
return "$sp"
|
|
|
|
case (r >= R4) && (r <= R11):
|
|
return fmt.Sprintf("$a%d", int(r-R4))
|
|
|
|
case (r >= R12) && (r <= R20):
|
|
return fmt.Sprintf("$t%d", int(r-R12))
|
|
|
|
case r == R21:
|
|
return "$r21"
|
|
|
|
case r == R22:
|
|
return "$fp"
|
|
|
|
case (r >= R23) && (r <= R31):
|
|
return fmt.Sprintf("$s%d", int(r-R23))
|
|
|
|
case (r >= F0) && (r <= F7):
|
|
return fmt.Sprintf("$fa%d", int(r-F0))
|
|
|
|
case (r >= F8) && (r <= F23):
|
|
return fmt.Sprintf("$ft%d", int(r-F8))
|
|
|
|
case (r >= F24) && (r <= F31):
|
|
return fmt.Sprintf("$fs%d", int(r-F24))
|
|
|
|
default:
|
|
return fmt.Sprintf("Unknown(%d)", int(r))
|
|
}
|
|
}
|
|
|
|
// float control status register
|
|
type Fcsr uint8
|
|
|
|
const (
|
|
FCSR0 Fcsr = iota
|
|
FCSR1
|
|
FCSR2
|
|
FCSR3
|
|
)
|
|
|
|
func (f Fcsr) String() string {
|
|
return fmt.Sprintf("$fcsr%d", uint8(f))
|
|
}
|
|
|
|
// float condition flags register
|
|
type Fcc uint8
|
|
|
|
const (
|
|
FCC0 Fcc = iota
|
|
FCC1
|
|
FCC2
|
|
FCC3
|
|
FCC4
|
|
FCC5
|
|
FCC6
|
|
FCC7
|
|
)
|
|
|
|
func (f Fcc) String() string {
|
|
return fmt.Sprintf("$fcc%d", uint8(f))
|
|
}
|
|
|
|
// An Imm is an integer constant.
|
|
type Uimm struct {
|
|
Imm uint32
|
|
Decimal bool
|
|
}
|
|
|
|
func (i Uimm) String() string {
|
|
if i.Decimal == true {
|
|
return fmt.Sprintf("%d", i.Imm)
|
|
} else {
|
|
return fmt.Sprintf("%#x", i.Imm)
|
|
}
|
|
}
|
|
|
|
type Simm16 struct {
|
|
Imm int16
|
|
Width uint8
|
|
}
|
|
|
|
func (si Simm16) String() string {
|
|
return fmt.Sprintf("%d", int32(si.Imm))
|
|
}
|
|
|
|
type Simm32 struct {
|
|
Imm int32
|
|
Width uint8
|
|
}
|
|
|
|
func (si Simm32) String() string {
|
|
return fmt.Sprintf("%d", int32(si.Imm))
|
|
}
|
|
|
|
type OffsetSimm struct {
|
|
Imm int32
|
|
Width uint8
|
|
}
|
|
|
|
func (o OffsetSimm) String() string {
|
|
return fmt.Sprintf("%d", int32(o.Imm))
|
|
}
|
|
|
|
type SaSimm int16
|
|
|
|
func (s SaSimm) String() string {
|
|
return fmt.Sprintf("%#x", int(s))
|
|
}
|
|
|
|
type CodeSimm int16
|
|
|
|
func (c CodeSimm) String() string {
|
|
return fmt.Sprintf("%#x", int(c))
|
|
}
|