loong64: Implement loong64 GNU and plan9 format disassembler
Loong64 documentation: https://github.com/loongson/LoongArch-Documentation.git
Change-Id: Iff47bdcfc787f69361be510bc4784fe91e10431c
Co-authored-by: huangqiqi <huangqiqi@loongson.cn>
Co-authored-by: chenguoqi <chenguoqi@loongson.cn>
Reviewed-on: https://go-review.googlesource.com/c/arch/+/358854
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: sophie zhao <zhaoxiaolin@loongson.cn>
Reviewed-by: abner chenc <chenguoqi@loongson.cn>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Qiqi Huang <huangqiqi@loongson.cn>
Reviewed-by: Zxilly Chou <zxilly@outlook.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
diff --git a/loong64/loong64asm/arg.go b/loong64/loong64asm/arg.go
new file mode 100644
index 0000000..460af3d
--- /dev/null
+++ b/loong64/loong64asm/arg.go
@@ -0,0 +1,93 @@
+// 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
+
+// Naming for Go decoder arguments:
+//
+// - arg_fd: a Floating Point operand register fd encoded in the fd[4:0] field
+//
+// - arg_fj: a Floating Point operand register fj encoded in the fj[9:5] field
+//
+// - arg_fk: a Floating Point operand register fk encoded in the fk[14:10] field
+//
+// - arg_fa: a Floating Point operand register fa encoded in the fa[19:15] field
+//
+// - arg_rd: a general-purpose register rd encoded in the rd[4:0] field
+//
+// - arg_rj: a general-purpose register rj encoded in the rj[9:5] field
+//
+// - arg_rk: a general-purpose register rk encoded in the rk[14:10] field
+//
+// - arg_fcsr_4_0: float control status register encoded in [4:0] field
+//
+// - arg_cd_2_0: condition flag register encoded in [2:0] field
+//
+// - arg_sa2_16_15: shift bits constant encoded in [16:15] field
+//
+// - arg_code_14_0: arg for exception process routine encoded in [14:0] field
+//
+// - arg_ui5_14_10: 5bits unsigned immediate
+//
+// - arg_lsbw: For details, please refer to chapter 2.2.3.8 of instruction manual
+//
+// - arg_msbw: For details, please refer to chapter 2.2.3.9 of instruction manual
+//
+// - arg_hint_4_0: hint field implied the prefetch type and the data should fetch to cache's level
+// 0: load to data cache level 1
+// 8: store to data cache level 1
+// other: no define
+//
+// - arg_si12_21_10: 12bits signed immediate
+
+type instArg uint16
+
+const (
+ _ instArg = iota
+ // 1-5
+ arg_fd
+ arg_fj
+ arg_fk
+ arg_fa
+ arg_rd
+ // 6-10
+ arg_rj
+ arg_rk
+ arg_op_4_0
+ arg_fcsr_4_0
+ arg_fcsr_9_5
+ // 11-15
+ arg_csr_23_10
+ arg_cd
+ arg_cj
+ arg_ca
+ arg_sa2_16_15
+ // 16-20
+ arg_sa3_17_15
+ arg_code_4_0
+ arg_code_14_0
+ arg_ui5_14_10
+ arg_ui6_15_10
+ // 21-25
+ arg_ui12_21_10
+ arg_lsbw
+ arg_msbw
+ arg_lsbd
+ arg_msbd
+ // 26-30
+ arg_hint_4_0
+ arg_hint_14_0
+ arg_level_14_0
+ arg_level_17_10
+ arg_seq_17_10
+ // 31-35
+ arg_si12_21_10
+ arg_si14_23_10
+ arg_si16_25_10
+ arg_si20_24_5
+ arg_offset_20_0
+ // 36~
+ arg_offset_25_0
+ arg_offset_15_0
+)
diff --git a/loong64/loong64asm/decode.go b/loong64/loong64asm/decode.go
new file mode 100644
index 0000000..3aca007
--- /dev/null
+++ b/loong64/loong64asm/decode.go
@@ -0,0 +1,269 @@
+// 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
+ }
+}
diff --git a/loong64/loong64asm/decode_test.go b/loong64/loong64asm/decode_test.go
new file mode 100644
index 0000000..74a3277
--- /dev/null
+++ b/loong64/loong64asm/decode_test.go
@@ -0,0 +1,76 @@
+// 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/hex"
+ "io/ioutil"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+func testDecode(t *testing.T, syntax string) {
+ input := filepath.Join("testdata", syntax+"cases.txt")
+ data, err := ioutil.ReadFile(input)
+ if err != nil {
+ t.Fatal(err)
+ }
+ all := string(data)
+ for strings.Contains(all, "\t\t") {
+ all = strings.Replace(all, "\t\t", "\t", -1)
+ }
+ for _, line := range strings.Split(all, "\n") {
+ line = strings.TrimSpace(line)
+ if line == "" || strings.HasPrefix(line, "#") {
+ continue
+ }
+ f := strings.SplitN(line, "\t", 2)
+ i := strings.Index(f[0], "|")
+ if i < 0 {
+ t.Errorf("parsing %q: missing | separator", f[0])
+ continue
+ }
+ if i%2 != 0 {
+ t.Errorf("parsing %q: misaligned | separator", f[0])
+ }
+ code, err := hex.DecodeString(f[0][:i] + f[0][i+1:])
+ if err != nil {
+ t.Errorf("parsing %q: %v", f[0], err)
+ continue
+ }
+ asm := f[1]
+ inst, decodeErr := Decode(code)
+ if decodeErr != nil && decodeErr != errUnknown {
+ // Some rarely used system instructions are not supported
+ // Following logicals will filter such unknown instructions
+ t.Errorf("parsing %x: %s", code, decodeErr)
+ continue
+ }
+ var out string
+ switch syntax {
+ case "gnu":
+ out = GNUSyntax(inst)
+ case "plan9":
+ out = GoSyntax(inst, 0, nil)
+ default:
+ t.Errorf("unknown syntax %q", syntax)
+ continue
+ }
+
+ // var out string
+ if asm != out || len(asm) != len(out) {
+ t.Errorf("Decode(%s) [%s] = %s want %s", f[0], syntax, out, asm)
+ }
+ }
+}
+
+func TestDecodeGNUSyntax(t *testing.T) {
+ testDecode(t, "gnu")
+}
+
+func TestDecodeGoSyntax(t *testing.T) {
+ testDecode(t, "plan9")
+}
diff --git a/loong64/loong64asm/ext_test.go b/loong64/loong64asm/ext_test.go
new file mode 100644
index 0000000..5c90586
--- /dev/null
+++ b/loong64/loong64asm/ext_test.go
@@ -0,0 +1,405 @@
+// 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.
+
+// Support for testing against external disassembler program.
+
+package loong64asm
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/hex"
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "math/rand"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+ "time"
+)
+
+var (
+ dumpTest = flag.Bool("dump", false, "dump all encodings")
+ mismatch = flag.Bool("mismatch", false, "log allowed mismatches")
+ keep = flag.Bool("keep", false, "keep object files around")
+ debug = false
+)
+
+// An ExtInst represents a single decoded instruction parsed
+// from an external disassembler's output.
+type ExtInst struct {
+ addr uint64
+ enc [4]byte
+ nenc int
+ text string
+}
+
+func (r ExtInst) String() string {
+ return fmt.Sprintf("%#x: % x: %s", r.addr, r.enc, r.text)
+}
+
+// An ExtDis is a connection between an external disassembler and a test.
+type ExtDis struct {
+ Dec chan ExtInst
+ File *os.File
+ Size int
+ Cmd *exec.Cmd
+}
+
+// Run runs the given command - the external disassembler - and returns
+// a buffered reader of its standard output.
+func (ext *ExtDis) Run(cmd ...string) (*bufio.Reader, error) {
+ if *keep {
+ log.Printf("%s\n", strings.Join(cmd, " "))
+ }
+ ext.Cmd = exec.Command(cmd[0], cmd[1:]...)
+ out, err := ext.Cmd.StdoutPipe()
+ if err != nil {
+ return nil, fmt.Errorf("stdoutpipe: %v", err)
+ }
+ if err := ext.Cmd.Start(); err != nil {
+ return nil, fmt.Errorf("exec: %v", err)
+ }
+
+ b := bufio.NewReaderSize(out, 1<<20)
+ return b, nil
+}
+
+// Wait waits for the command started with Run to exit.
+func (ext *ExtDis) Wait() error {
+ return ext.Cmd.Wait()
+}
+
+// testExtDis tests a set of byte sequences against an external disassembler.
+// The disassembler is expected to produce the given syntax and run
+// in the given architecture mode (16, 32, or 64-bit).
+// The extdis function must start the external disassembler
+// and then parse its output, sending the parsed instructions on ext.Dec.
+// The generate function calls its argument f once for each byte sequence
+// to be tested. The generate function itself will be called twice, and it must
+// make the same sequence of calls to f each time.
+// When a disassembly does not match the internal decoding,
+// allowedMismatch determines whether this mismatch should be
+// allowed, or else considered an error.
+func testExtDis(
+ t *testing.T,
+ syntax string,
+ extdis func(ext *ExtDis) error,
+ generate func(f func([]byte)),
+ allowedMismatch func(text string, inst *Inst, dec ExtInst) bool,
+) {
+ start := time.Now()
+ ext := &ExtDis{
+ Dec: make(chan ExtInst),
+ }
+ errc := make(chan error)
+
+ // First pass: write instructions to input file for external disassembler.
+ file, f, size, err := writeInst(generate)
+ if err != nil {
+ t.Fatal(err)
+ }
+ ext.Size = size
+ ext.File = f
+ defer func() {
+ f.Close()
+ if !*keep {
+ os.Remove(file)
+ }
+ }()
+
+ // Second pass: compare disassembly against our decodings.
+ var (
+ totalTests = 0
+ totalSkips = 0
+ totalErrors = 0
+
+ errors = make([]string, 0, 100) // Sampled errors, at most cap
+ )
+ go func() {
+ errc <- extdis(ext)
+ }()
+
+ generate(func(enc []byte) {
+ dec, ok := <-ext.Dec
+ if !ok {
+ t.Errorf("decoding stream ended early")
+ return
+ }
+ inst, text := disasm(syntax, pad(enc))
+
+ totalTests++
+ if *dumpTest {
+ fmt.Printf("%x -> %s [%d]\n", enc[:len(enc)], dec.text, dec.nenc)
+ }
+
+ if text != dec.text && !strings.Contains(dec.text, "unknown") && syntax == "gnu" {
+ suffix := ""
+ if allowedMismatch(text, &inst, dec) {
+ totalSkips++
+ if !*mismatch {
+ return
+ }
+ suffix += " (allowed mismatch)"
+ }
+ totalErrors++
+ cmp := fmt.Sprintf("decode(%x) = %q, %d, want %q, %d%s\n", enc, text, len(enc), dec.text, dec.nenc, suffix)
+
+ if len(errors) >= cap(errors) {
+ j := rand.Intn(totalErrors)
+ if j >= cap(errors) {
+ return
+ }
+ errors = append(errors[:j], errors[j+1:]...)
+ }
+ errors = append(errors, cmp)
+ }
+ })
+
+ if *mismatch {
+ totalErrors -= totalSkips
+ }
+
+ fmt.Printf("totalTest: %d total skip: %d total error: %d\n", totalTests, totalSkips, totalErrors)
+
+ // Here are some errors about mismatches(44)
+ for _, b := range errors {
+ t.Log(b)
+ }
+
+ if totalErrors > 0 {
+ t.Fail()
+ }
+ t.Logf("%d test cases, %d expected mismatches, %d failures; %.0f cases/second", totalTests, totalSkips, totalErrors, float64(totalTests)/time.Since(start).Seconds())
+ t.Logf("decoder coverage: %.1f%%;\n", decodeCoverage())
+}
+
+// Start address of text.
+const start = 0x8000
+
+// writeInst writes the generated byte sequences to a new file
+// starting at offset start. That file is intended to be the input to
+// the external disassembler.
+func writeInst(generate func(func([]byte))) (file string, f *os.File, size int, err error) {
+ f, err = ioutil.TempFile("", "loong64asm")
+ if err != nil {
+ return
+ }
+
+ file = f.Name()
+
+ f.Seek(start, io.SeekStart)
+ w := bufio.NewWriter(f)
+ defer w.Flush()
+ size = 0
+ generate(func(x []byte) {
+ if debug {
+ fmt.Printf("%#x: %x%x\n", start+size, x, zeros[len(x):])
+ }
+ w.Write(x)
+ w.Write(zeros[len(x):])
+ size += len(zeros)
+ })
+ return file, f, size, nil
+}
+
+var zeros = []byte{0, 0, 0, 0}
+
+// pad pads the code sequence with pops.
+func pad(enc []byte) []byte {
+ if len(enc) < 4 {
+ enc = append(enc[:len(enc):len(enc)], zeros[:4-len(enc)]...)
+ }
+ return enc
+}
+
+// disasm returns the decoded instruction and text
+// for the given source bytes, using the given syntax and mode.
+func disasm(syntax string, src []byte) (inst Inst, text string) {
+ var err error
+ inst, err = Decode(src)
+ if err != nil {
+ text = "error: " + err.Error()
+ return
+ }
+ text = inst.String()
+ switch syntax {
+ case "gnu":
+ text = GNUSyntax(inst)
+ case "plan9": // [sic]
+ text = GoSyntax(inst, 0, nil)
+ default:
+ text = "error: unknown syntax " + syntax
+ }
+ return
+}
+
+// decodecoverage returns a floating point number denoting the
+// decoder coverage.
+func decodeCoverage() float64 {
+ n := 0
+ for _, t := range decoderCover {
+ if t {
+ n++
+ }
+ }
+ return 100 * float64(1+n) / float64(1+len(decoderCover))
+}
+
+// Helpers for writing disassembler output parsers.
+
+// isHex reports whether b is a hexadecimal character (0-9a-fA-F).
+func isHex(b byte) bool {
+ return ('0' <= b && b <= '9') || ('a' <= b && b <= 'f') || ('A' <= b && b <= 'F')
+}
+
+// parseHex parses the hexadecimal byte dump in hex,
+// appending the parsed bytes to raw and returning the updated slice.
+// The returned bool reports whether any invalid hex was found.
+// Spaces and tabs between bytes are okay but any other non-hex is not.
+func parseHex(hex []byte, raw []byte) ([]byte, bool) {
+ hex = bytes.TrimSpace(hex)
+ for j := 0; j < len(hex); {
+ for hex[j] == ' ' || hex[j] == '\t' {
+ j++
+ }
+ if j >= len(hex) {
+ break
+ }
+ if j+2 > len(hex) || !isHex(hex[j]) || !isHex(hex[j+1]) {
+ return nil, false
+ }
+ raw = append(raw, unhex(hex[j])<<4|unhex(hex[j+1]))
+ j += 2
+ }
+ return raw, true
+}
+
+func unhex(b byte) byte {
+ if '0' <= b && b <= '9' {
+ return b - '0'
+ } else if 'A' <= b && b <= 'F' {
+ return b - 'A' + 10
+ } else if 'a' <= b && b <= 'f' {
+ return b - 'a' + 10
+ }
+ return 0
+}
+
+// index is like bytes.Index(s, []byte(t)) but avoids the allocation.
+func index(s []byte, t string) int {
+ i := 0
+ for {
+ j := bytes.IndexByte(s[i:], t[0])
+ if j < 0 {
+ return -1
+ }
+ i = i + j
+ if i+len(t) > len(s) {
+ return -1
+ }
+ for k := 1; k < len(t); k++ {
+ if s[i+k] != t[k] {
+ goto nomatch
+ }
+ }
+ return i
+ nomatch:
+ i++
+ }
+}
+
+// fixSpace rewrites runs of spaces, tabs, and newline characters into single spaces in s.
+// If s must be rewritten, it is rewritten in place.
+func fixSpace(s []byte) []byte {
+ s = bytes.TrimSpace(s)
+ for i := 0; i < len(s); i++ {
+ if s[i] == '\t' || s[i] == '\n' || i > 0 && s[i] == ' ' && s[i-1] == ' ' {
+ goto Fix
+ }
+ }
+ return s
+
+Fix:
+ b := s
+ w := 0
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ if c == '\t' || c == '\n' {
+ c = ' '
+ }
+ if c == ' ' && w > 0 && b[w-1] == ' ' {
+ continue
+ }
+ b[w] = c
+ w++
+ }
+ if w > 0 && b[w-1] == ' ' {
+ w--
+ }
+ return b[:w]
+}
+
+// Generators.
+//
+// The test cases are described as functions that invoke a callback repeatedly,
+// with a new input sequence each time. These helpers make writing those
+// a little easier.
+
+// hexCases generates the cases written in hexadecimal in the encoded string.
+// Spaces in 'encoded' separate entire test cases, not individual bytes.
+func hexCases(t *testing.T, encoded string) func(func([]byte)) {
+ return func(try func([]byte)) {
+ for _, x := range strings.Fields(encoded) {
+ src, err := hex.DecodeString(x)
+ if err != nil {
+ t.Errorf("parsing %q: %v", x, err)
+ }
+ try(src)
+ }
+ }
+}
+
+// testdataCases generates the test cases recorded in testdata/cases.txt.
+// It only uses the inputs; it ignores the answers recorded in that file.
+func testdataCases(t *testing.T, syntax string) func(func([]byte)) {
+ var codes [][]byte
+ input := filepath.Join("testdata", syntax+"cases.txt")
+ data, err := ioutil.ReadFile(input)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, line := range strings.Split(string(data), "\n") {
+ line = strings.TrimSpace(line)
+ if line == "" || strings.HasPrefix(line, "#") {
+ continue
+ }
+ f := strings.Fields(line)[0]
+ i := strings.Index(f, "|")
+ if i < 0 {
+ t.Errorf("parsing %q: missing | separator", f)
+ continue
+ }
+ if i%2 != 0 {
+ t.Errorf("parsing %q: misaligned | separator", f)
+ }
+ code, err := hex.DecodeString(f[:i] + f[i+1:])
+ if err != nil {
+ t.Errorf("parsing %q: %v", f, err)
+ continue
+ }
+ codes = append(codes, code)
+ }
+
+ return func(try func([]byte)) {
+ for _, code := range codes {
+ try(code)
+ }
+ }
+}
diff --git a/loong64/loong64asm/gnu.go b/loong64/loong64asm/gnu.go
new file mode 100644
index 0000000..4807abc
--- /dev/null
+++ b/loong64/loong64asm/gnu.go
@@ -0,0 +1,16 @@
+// 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 (
+ "strings"
+)
+
+// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
+// This form typically matches the syntax defined in the Loong64 Reference Manual. See
+// https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html
+func GNUSyntax(inst Inst) string {
+ return strings.ToLower(inst.String())
+}
diff --git a/loong64/loong64asm/inst.go b/loong64/loong64asm/inst.go
new file mode 100644
index 0000000..1ac5c79
--- /dev/null
+++ b/loong64/loong64asm/inst.go
@@ -0,0 +1,298 @@
+// 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[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))
+}
diff --git a/loong64/loong64asm/objdump_test.go b/loong64/loong64asm/objdump_test.go
new file mode 100644
index 0000000..0476655
--- /dev/null
+++ b/loong64/loong64asm/objdump_test.go
@@ -0,0 +1,145 @@
+// 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 (
+ "strconv"
+ "strings"
+ "testing"
+)
+
+func TestObjdumpLoong64TestDecodeGNUSyntaxdata(t *testing.T) {
+ testObjdumpLoong64(t, testdataCases(t, "gnu"))
+}
+
+func TestObjdumpLoong64TestDecodeGoSyntaxdata(t *testing.T) {
+ testObjdumpLoong64(t, testdataCases(t, "plan9"))
+}
+
+func TestObjdumpLoong64Manual(t *testing.T) {
+ testObjdumpLoong64(t, hexCases(t, objdumpManualTests))
+}
+
+// objdumpManualTests holds test cases that will be run by TestObjdumpLoong64Manual.
+// If you are debugging a few cases that turned up in a longer run, it can be useful
+// to list them here and then use -run=Manual, particularly with tracing enabled.
+// Note that these are byte sequences, so they must be reversed from the usual
+// word presentation.
+var objdumpManualTests = `
+00007238
+00807238
+00004003
+00100050
+ac410028
+ac41002a
+ac41c028
+ac414028
+ac41402a
+ac418028
+ac41802a
+ac397838
+acb97938
+acb97838
+ac397938
+ac397a38
+acb97b38
+acb97a38
+ac397b38
+ac110026
+ac110024
+ac390038
+ac392038
+ac390c38
+ac390438
+ac392438
+ac390838
+ac392838
+ac391600
+ac391400
+ac391500
+ac418003
+`
+
+// allowedMismatchObjdump reports whether the mismatch between text and dec
+// should be allowed by the test.
+func allowedMismatchObjdump(text string, inst *Inst, dec ExtInst) bool {
+ // GNU objdump use register, decode use alias of register, so corrected it in here
+ var dec_text = strings.Replace(dec.text, " ", ",", -1)
+ var decsp []string = strings.Split(dec_text, ",")
+ var num int = cap(decsp)
+ for i := 0; i < num; i++ {
+ dex := strings.Index(decsp[i], "$r")
+ fdex := strings.Index(decsp[i], "$f")
+ ddex := strings.Index(decsp[i], "(")
+ if ddex > 0 {
+ // ldptr.w $r12,$r13,16(0x10)
+ decsp[i] = decsp[i][0:ddex]
+ }
+ xdex := strings.Index(decsp[i], "0x")
+ // convert registers to registers aliases
+ if dex >= 0 {
+ reg, _ := strconv.Atoi(decsp[i][dex+2:])
+ // r12~r20 $t0~t8
+ if reg >= 12 && reg <= 20 {
+ decsp[i] = strings.Join([]string{"t", strconv.Itoa(reg - 12)}, "")
+ }
+ // r4~r11 $a0~a7
+ if reg >= 4 && reg <= 11 {
+ decsp[i] = strings.Join([]string{"a", strconv.Itoa(reg - 4)}, "")
+ }
+ // r23~r31 $s0~s8
+ if reg >= 23 && reg <= 31 {
+ decsp[i] = strings.Join([]string{"s", strconv.Itoa(reg - 23)}, "")
+ }
+ // r0 zero
+ if reg == 0 {
+ decsp[i] = strings.Join([]string{"zero"}, "")
+ }
+ // r1 ra
+ if reg == 1 {
+ decsp[i] = strings.Join([]string{"ra"}, "")
+ }
+ // r2 tp
+ if reg == 2 {
+ decsp[i] = strings.Join([]string{"tp"}, "")
+ }
+ // r3 sp
+ if reg == 3 {
+ decsp[i] = strings.Join([]string{"sp"}, "")
+ }
+ // r21 x
+ if reg == 21 {
+ decsp[i] = strings.Join([]string{"x"}, "")
+ }
+ // r22 fp
+ if reg == 22 {
+ decsp[i] = strings.Join([]string{"fp"}, "")
+ }
+ }
+ // convert hexadecimal to decimal
+ if xdex >= 0 {
+ parseint, _ := strconv.ParseInt(decsp[i][xdex+2:], 16, 32)
+ decsp[i] = strings.Join([]string{strconv.Itoa(int(parseint))}, "")
+ }
+ // convert floating-point registers to floating-point aliases
+ if fdex >= 0 && !strings.Contains(decsp[i], "$fcc") {
+ freg, _ := strconv.Atoi(decsp[i][fdex+2:])
+ // f0~f7 fa0~fa7
+ if freg >= 0 && freg <= 7 {
+ decsp[i] = strings.Join([]string{"fa", strconv.Itoa(freg - 0)}, "")
+ }
+ // f8~f23 ft0~ft15
+ if freg >= 8 && freg <= 23 {
+ decsp[i] = strings.Join([]string{"ft", strconv.Itoa(freg - 8)}, "")
+ }
+ // f24~f31 fs0~fs7
+ if freg >= 24 && freg <= 31 {
+ decsp[i] = strings.Join([]string{"fs", strconv.Itoa(freg - 24)}, "")
+ }
+ }
+ }
+
+ return false
+}
diff --git a/loong64/loong64asm/objdumpext_test.go b/loong64/loong64asm/objdumpext_test.go
new file mode 100644
index 0000000..80396d9
--- /dev/null
+++ b/loong64/loong64asm/objdumpext_test.go
@@ -0,0 +1,249 @@
+// 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 (
+ "bytes"
+ "debug/elf"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "os/exec"
+ "strconv"
+ "strings"
+ "testing"
+)
+
+const objdumpPath = "/usr/bin/objdump"
+
+func testObjdumpLoong64(t *testing.T, generate func(func([]byte))) {
+ testObjdumpArch(t, generate)
+}
+
+func testObjdumpArch(t *testing.T, generate func(func([]byte))) {
+ checkObjdumpLoong64(t)
+ testExtDis(t, "gnu", objdump, generate, allowedMismatchObjdump)
+ testExtDis(t, "plan9", objdump, generate, allowedMismatchObjdump)
+}
+
+func checkObjdumpLoong64(t *testing.T) {
+ out, err := exec.Command(objdumpPath, "-i").Output()
+ if err != nil {
+ t.Skipf("cannot run objdump: %v\n%s", err, out)
+ }
+ if !strings.Contains(string(out), "Loongarch64") {
+ t.Skip("objdump does not have loong64 support")
+ }
+}
+
+func objdump(ext *ExtDis) error {
+ // File already written with instructions; add ELF header.
+ if err := writeELF64(ext.File, ext.Size); err != nil {
+ return err
+ }
+
+ b, err := ext.Run(objdumpPath, "-d", "-z", ext.File.Name())
+ if err != nil {
+ return err
+ }
+
+ var (
+ nmatch int
+ reading bool
+ next uint64 = start
+ addr uint64
+ encbuf [4]byte
+ enc []byte
+ text string
+ )
+ flush := func() {
+ if addr == next {
+ // PC-relative addresses are translated to absolute addresses based on PC by GNU objdump
+ // Following logical rewrites the absolute addresses back to PC-relative ones for comparing
+ // with our disassembler output which are PC-relative
+ if text == "undefined" && len(enc) == 4 {
+ text = "error: unknown instruction"
+ enc = nil
+ }
+ if len(enc) == 4 {
+ // prints as word but we want to record bytes
+ enc[0], enc[3] = enc[3], enc[0]
+ enc[1], enc[2] = enc[2], enc[1]
+ }
+ ext.Dec <- ExtInst{addr, encbuf, len(enc), text}
+ encbuf = [4]byte{}
+ enc = nil
+ next += 4
+ }
+ }
+ var textangle = []byte("<.text>:")
+ for {
+ line, err := b.ReadSlice('\n')
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ return fmt.Errorf("reading objdump output: %v", err)
+ }
+ if bytes.Contains(line, textangle) {
+ reading = true
+ continue
+ }
+ if !reading {
+ continue
+ }
+ if debug {
+ os.Stdout.Write(line)
+ }
+ if enc1 := parseContinuation(line, encbuf[:len(enc)]); enc1 != nil {
+ enc = enc1
+ continue
+ }
+ flush()
+ nmatch++
+ addr, enc, text = parseLine(line, encbuf[:0])
+ if addr > next {
+ return fmt.Errorf("address out of sync expected <= %#x at %q in:\n%s", next, line, line)
+ }
+ }
+ flush()
+ if next != start+uint64(ext.Size) {
+ return fmt.Errorf("not enough results found [%d %d]", next, start+ext.Size)
+ }
+ if err := ext.Wait(); err != nil {
+ return fmt.Errorf("exec: %v", err)
+ }
+
+ return nil
+}
+
+var (
+ undefined = []byte("undefined")
+ unpredictable = []byte("unpredictable")
+ slashslash = []byte("//")
+)
+
+func parseLine(line []byte, encstart []byte) (addr uint64, enc []byte, text string) {
+ ok := false
+ oline := line
+ i := index(line, ":\t")
+ if i < 0 {
+ log.Fatalf("cannot parse disassembly: %q", oline)
+ }
+ x, err := strconv.ParseUint(string(bytes.TrimSpace(line[:i])), 16, 32)
+ if err != nil {
+ log.Fatalf("cannot parse disassembly: %q", oline)
+ }
+ addr = uint64(x)
+ line = line[i+2:]
+ i = bytes.IndexByte(line, '\t')
+ if i < 0 {
+ log.Fatalf("cannot parse disassembly: %q", oline)
+ }
+ enc, ok = parseHex(line[:i], encstart)
+ if !ok {
+ log.Fatalf("cannot parse disassembly: %q", oline)
+ }
+ line = bytes.TrimSpace(line[i:])
+ if bytes.Contains(line, undefined) {
+ text = "undefined"
+ return
+ }
+ if false && bytes.Contains(line, unpredictable) {
+ text = "unpredictable"
+ return
+ }
+ // Strip trailing comment starting with '#'
+ if i := bytes.IndexByte(line, '#'); i >= 0 {
+ line = bytes.TrimSpace(line[:i])
+ }
+ // Strip trailing comment starting with "//"
+ if i := bytes.Index(line, slashslash); i >= 0 {
+ line = bytes.TrimSpace(line[:i])
+ }
+ text = string(fixSpace(line))
+ return
+}
+
+func parseContinuation(line []byte, enc []byte) []byte {
+ i := index(line, ":\t")
+ if i < 0 {
+ return nil
+ }
+ line = line[i+1:]
+ enc, _ = parseHex(line, enc)
+ return enc
+}
+
+// writeELF64 writes an ELF64 header to the file, describing a text
+// segment that starts at start (0x8000) and extends for size bytes.
+func writeELF64(f *os.File, size int) error {
+ f.Seek(0, io.SeekStart)
+ var hdr elf.Header64
+ var prog elf.Prog64
+ var sect elf.Section64
+ var buf bytes.Buffer
+ binary.Write(&buf, binary.LittleEndian, &hdr)
+ off1 := buf.Len()
+ binary.Write(&buf, binary.LittleEndian, &prog)
+ off2 := buf.Len()
+ binary.Write(&buf, binary.LittleEndian, §)
+ off3 := buf.Len()
+ buf.Reset()
+ data := byte(elf.ELFDATA2LSB)
+ hdr = elf.Header64{
+ Ident: [16]byte{0x7F, 'E', 'L', 'F', 2, data, 1},
+ Type: 2,
+ Machine: uint16(elf.EM_LOONGARCH),
+ Version: 1,
+ Entry: start,
+ Phoff: uint64(off1),
+ Shoff: uint64(off2),
+ Flags: 0x3,
+ Ehsize: uint16(off1),
+ Phentsize: uint16(off2 - off1),
+ Phnum: 1,
+ Shentsize: uint16(off3 - off2),
+ Shnum: 3,
+ Shstrndx: 2,
+ }
+ binary.Write(&buf, binary.LittleEndian, &hdr)
+ prog = elf.Prog64{
+ Type: 1,
+ Off: start,
+ Vaddr: start,
+ Paddr: start,
+ Filesz: uint64(size),
+ Memsz: uint64(size),
+ Flags: 5,
+ Align: start,
+ }
+ binary.Write(&buf, binary.LittleEndian, &prog)
+ binary.Write(&buf, binary.LittleEndian, §) // NULL section
+ sect = elf.Section64{
+ Name: 1,
+ Type: uint32(elf.SHT_PROGBITS),
+ Addr: start,
+ Off: start,
+ Size: uint64(size),
+ Flags: uint64(elf.SHF_ALLOC | elf.SHF_EXECINSTR),
+ Addralign: 4,
+ }
+ binary.Write(&buf, binary.LittleEndian, §) // .text
+ sect = elf.Section64{
+ Name: uint32(len("\x00.text\x00")),
+ Type: uint32(elf.SHT_STRTAB),
+ Addr: 0,
+ Off: uint64(off2 + (off3-off2)*3),
+ Size: uint64(len("\x00.text\x00.shstrtab\x00")),
+ Addralign: 1,
+ }
+ binary.Write(&buf, binary.LittleEndian, §)
+ buf.WriteString("\x00.text\x00.shstrtab\x00")
+ f.Write(buf.Bytes())
+ return nil
+}
diff --git a/loong64/loong64asm/plan9x.go b/loong64/loong64asm/plan9x.go
new file mode 100644
index 0000000..5db3290
--- /dev/null
+++ b/loong64/loong64asm/plan9x.go
@@ -0,0 +1,536 @@
+// 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"
+)
+
+// GoSyntax returns the Go assembler syntax for the instruction.
+// The syntax was originally defined by Plan 9.
+// The pc is the program counter of the instruction, used for
+// expanding PC-relative addresses into absolute ones.
+// The symname function queries the symbol table for the program
+// being disassembled. Given a target address it returns the name
+// and base address of the symbol containing the target, if any;
+// otherwise it returns "", 0.
+func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) string {
+ if symname == nil {
+ symname = func(uint64) (string, uint64) { return "", 0 }
+ }
+ if inst.Op == 0 && inst.Enc == 0 {
+ return "WORD $0"
+ } else if inst.Op == 0 {
+ return "?"
+ }
+
+ var args []string
+ for _, a := range inst.Args {
+ if a == nil {
+ break
+ }
+ args = append(args, plan9Arg(&inst, pc, symname, a))
+ }
+
+ var op string = plan9OpMap[inst.Op]
+ if op == "" {
+ op = "Unknown " + inst.Op.String()
+ }
+
+ switch inst.Op {
+ case BSTRPICK_W, BSTRPICK_D, BSTRINS_W, BSTRINS_D:
+ msbw, lsbw := inst.Args[2].(Uimm), inst.Args[3].(Uimm)
+ if inst.Op == BSTRPICK_D && msbw.Imm == 15 && lsbw.Imm == 0 {
+ op = "MOVHU"
+ args = append(args[1:2], args[0:1]...)
+ } else {
+ args[0], args[1], args[2], args[3] = args[2], args[1], args[3], args[0]
+ }
+
+ case BCNEZ, BCEQZ:
+ args = args[1:2]
+
+ case BEQ, BNE:
+ rj := inst.Args[0].(Reg)
+ rd := inst.Args[1].(Reg)
+ if rj == rd && inst.Op == BEQ {
+ op = "JMP"
+ args = args[2:]
+ } else if rj == R0 {
+ args = args[1:]
+ } else if rd == R0 {
+ args = append(args[:1], args[2:]...)
+ }
+
+ case BEQZ, BNEZ:
+ if inst.Args[0].(Reg) == R0 && inst.Op == BEQ {
+ op = "JMP"
+ args = args[1:]
+ }
+
+ case BLT, BLTU, BGE, BGEU:
+ rj := inst.Args[0].(Reg)
+ rd := inst.Args[1].(Reg)
+ if rj == rd && (inst.Op == BGE || inst.Op == BGEU) {
+ op = "JMP"
+ args = args[2:]
+ } else if rj == R0 {
+ switch inst.Op {
+ case BGE:
+ op = "BLEZ"
+ case BLT:
+ op = "BGTZ"
+ }
+ args = args[1:]
+ } else if rd == R0 {
+ if !strings.HasSuffix(op, "U") {
+ op += "Z"
+ }
+ args = append(args[:1], args[2:]...)
+ }
+
+ case JIRL:
+ rd := inst.Args[0].(Reg)
+ rj := inst.Args[1].(Reg)
+ regno := uint16(rj) & 31
+ if rd == R0 {
+ return fmt.Sprintf("JMP (R%d)", regno)
+ }
+ return fmt.Sprintf("CALL (R%d)", regno)
+
+ case LD_B, LD_H, LD_W, LD_D, LD_BU, LD_HU, LD_WU, LL_W, LL_D,
+ ST_B, ST_H, ST_W, ST_D, SC_W, SC_D, FLD_S, FLD_D, FST_S, FST_D:
+ var off int32
+ switch a := inst.Args[2].(type) {
+ case Simm16:
+ off = signumConvInt32(int32(a.Imm), a.Width)
+ case Simm32:
+ off = signumConvInt32(int32(a.Imm), a.Width) >> 2
+ }
+ Iop := strings.ToUpper(inst.Op.String())
+ if strings.HasPrefix(Iop, "L") || strings.HasPrefix(Iop, "FL") {
+ return fmt.Sprintf("%s %d(%s), %s", op, off, args[1], args[0])
+ }
+ return fmt.Sprintf("%s %s, %d(%s)", op, args[0], off, args[1])
+
+ case LDX_B, LDX_H, LDX_W, LDX_D, LDX_BU, LDX_HU, LDX_WU, FLDX_S, FLDX_D,
+ STX_B, STX_H, STX_W, STX_D, FSTX_S, FSTX_D:
+ Iop := strings.ToUpper(inst.Op.String())
+ if strings.HasPrefix(Iop, "L") || strings.HasPrefix(Iop, "FL") {
+ return fmt.Sprintf("%s (%s)(%s), %s", op, args[1], args[2], args[0])
+ }
+ return fmt.Sprintf("%s %s, (%s)(%s)", op, args[0], args[1], args[2])
+
+ case AMADD_B, AMADD_D, AMADD_DB_B, AMADD_DB_D, AMADD_DB_H, AMADD_DB_W, AMADD_H,
+ AMADD_W, AMAND_D, AMAND_DB_D, AMAND_DB_W, AMAND_W, AMCAS_B, AMCAS_D, AMCAS_DB_B,
+ AMCAS_DB_D, AMCAS_DB_H, AMCAS_DB_W, AMCAS_H, AMCAS_W, AMMAX_D, AMMAX_DB_D,
+ AMMAX_DB_DU, AMMAX_DB_W, AMMAX_DB_WU, AMMAX_DU, AMMAX_W, AMMAX_WU, AMMIN_D,
+ AMMIN_DB_D, AMMIN_DB_DU, AMMIN_DB_W, AMMIN_DB_WU, AMMIN_DU, AMMIN_W, AMMIN_WU,
+ AMOR_D, AMOR_DB_D, AMOR_DB_W, AMOR_W, AMSWAP_B, AMSWAP_D, AMSWAP_DB_B, AMSWAP_DB_D,
+ AMSWAP_DB_H, AMSWAP_DB_W, AMSWAP_H, AMSWAP_W, AMXOR_D, AMXOR_DB_D, AMXOR_DB_W, AMXOR_W:
+ return fmt.Sprintf("%s %s, (%s), %s", op, args[1], args[2], args[0])
+
+ default:
+ // Reverse args, placing dest last
+ for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
+ args[i], args[j] = args[j], args[i]
+ }
+ switch len(args) { // Special use cases
+ case 0, 1:
+ if inst.Op != B && inst.Op != BL {
+ return op
+ }
+
+ case 3:
+ switch a0 := inst.Args[0].(type) {
+ case Reg:
+ rj := inst.Args[1].(Reg)
+ if a0 == rj && a0 != R0 {
+ args = args[0:2]
+ }
+ }
+ switch inst.Op {
+ case SUB_W, SUB_D, ADDI_W, ADDI_D, ORI:
+ rj := inst.Args[1].(Reg)
+ if rj == R0 {
+ args = append(args[0:1], args[2:]...)
+ if inst.Op == SUB_W {
+ op = "NEGW"
+ } else if inst.Op == SUB_D {
+ op = "NEGV"
+ } else {
+ op = "MOVW"
+ }
+ }
+
+ case ANDI:
+ ui12 := inst.Args[2].(Uimm)
+ if ui12.Imm == uint32(0xff) {
+ op = "MOVBU"
+ args = args[1:]
+ } else if ui12.Imm == 0 && inst.Args[0].(Reg) == R0 && inst.Args[1].(Reg) == R0 {
+ return "NOOP"
+ }
+
+ case SLL_W, OR:
+ rk := inst.Args[2].(Reg)
+ if rk == R0 {
+ args = args[1:]
+ if inst.Op == SLL_W {
+ op = "MOVW"
+ } else {
+ op = "MOVV"
+ }
+ }
+ }
+ }
+ }
+
+ if args != nil {
+ op += " " + strings.Join(args, ", ")
+ }
+ return op
+}
+
+func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
+ // Reg: gpr[0, 31] and fpr[0, 31]
+ // Fcsr: fcsr[0, 3]
+ // Fcc: fcc[0, 7]
+ // Uimm: unsigned integer constant
+ // Simm16: si16
+ // Simm32: si32
+ // OffsetSimm: si32
+ switch a := arg.(type) {
+ case Reg:
+ regenum := uint16(a)
+ regno := uint16(a) & 0x1f
+ // General-purpose register
+ if regenum >= uint16(R0) && regenum <= uint16(R31) {
+ return fmt.Sprintf("R%d", regno)
+ } else { // Float point register
+ return fmt.Sprintf("F%d", regno)
+ }
+
+ case Fcsr:
+ regno := uint8(a) & 0x1f
+ return fmt.Sprintf("FCSR%d", regno)
+
+ case Fcc:
+ regno := uint8(a) & 0x1f
+ return fmt.Sprintf("FCC%d", regno)
+
+ case Uimm:
+ return fmt.Sprintf("$%d", a.Imm)
+
+ case Simm16:
+ si16 := signumConvInt32(int32(a.Imm), a.Width)
+ return fmt.Sprintf("$%d", si16)
+
+ case Simm32:
+ si32 := signumConvInt32(a.Imm, a.Width)
+ return fmt.Sprintf("$%d", si32)
+
+ case OffsetSimm:
+ offs := offsConvInt32(a.Imm, a.Width)
+ if inst.Op == B || inst.Op == BL {
+ addr := int64(pc) + int64(a.Imm)
+ if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base {
+ return fmt.Sprintf("%s(SB)", s)
+ }
+ }
+ return fmt.Sprintf("%d(PC)", offs>>2)
+
+ case SaSimm:
+ return fmt.Sprintf("$%d", a)
+
+ case CodeSimm:
+ return fmt.Sprintf("$%d", a)
+
+ }
+ return strings.ToUpper(arg.String())
+}
+
+func signumConvInt32(imm int32, width uint8) int32 {
+ active := uint32(1<<width) - 1
+ signum := uint32(imm) & active
+ if ((signum >> (width - 1)) & 0x1) == 1 {
+ signum |= ^active
+ }
+ return int32(signum)
+}
+
+func offsConvInt32(imm int32, width uint8) int32 {
+ relWidth := width + 2
+ return signumConvInt32(imm, relWidth)
+}
+
+var plan9OpMap = map[Op]string{
+ ADD_W: "ADD",
+ ADD_D: "ADDV",
+ SUB_W: "SUB",
+ SUB_D: "SUBV",
+ ADDI_W: "ADD",
+ ADDI_D: "ADDV",
+ LU12I_W: "LU12IW",
+ LU32I_D: "LU32ID",
+ LU52I_D: "LU52ID",
+ SLT: "SGT",
+ SLTU: "SGTU",
+ SLTI: "SGT",
+ SLTUI: "SGTU",
+ PCADDU12I: "PCADDU12I",
+ PCALAU12I: "PCALAU12I",
+ AND: "AND",
+ OR: "OR",
+ NOR: "NOR",
+ XOR: "XOR",
+ ANDI: "AND",
+ ORI: "OR",
+ XORI: "XOR",
+ MUL_W: "MUL",
+ MULH_W: "MULH",
+ MULH_WU: "MULHU",
+ MUL_D: "MULV",
+ MULH_D: "MULHV",
+ MULH_DU: "MULHVU",
+ DIV_W: "DIV",
+ DIV_WU: "DIVU",
+ DIV_D: "DIVV",
+ DIV_DU: "DIVVU",
+ MOD_W: "REM",
+ MOD_WU: "REMU",
+ MOD_D: "REMV",
+ MOD_DU: "REMVU",
+ SLL_W: "SLL",
+ SRL_W: "SRL",
+ SRA_W: "SRA",
+ ROTR_W: "ROTR",
+ SLL_D: "SLLV",
+ SRL_D: "SRLV",
+ SRA_D: "SRAV",
+ ROTR_D: "ROTRV",
+ SLLI_W: "SLL",
+ SRLI_W: "SRL",
+ SRAI_W: "SRA",
+ ROTRI_W: "ROTR",
+ SLLI_D: "SLLV",
+ SRLI_D: "SRLV",
+ SRAI_D: "SRAV",
+ ROTRI_D: "ROTRV",
+ EXT_W_B: "?",
+ EXT_W_H: "?",
+ BITREV_W: "BITREVW",
+ BITREV_D: "BITREVV",
+ CLO_W: "CLOW",
+ CLO_D: "CLOV",
+ CLZ_W: "CLZW",
+ CLZ_D: "CLZV",
+ CTO_W: "CTOW",
+ CTO_D: "CTOV",
+ CTZ_W: "CTZW",
+ CTZ_D: "CTZV",
+ REVB_2H: "REVB2H",
+ REVB_2W: "REVB2W",
+ REVB_4H: "REVB4H",
+ REVB_D: "REVBV",
+ BSTRPICK_W: "BSTRPICKW",
+ BSTRPICK_D: "BSTRPICKV",
+ BSTRINS_W: "BSTRINSW",
+ BSTRINS_D: "BSTRINSV",
+ MASKEQZ: "MASKEQZ",
+ MASKNEZ: "MASKNEZ",
+ BCNEZ: "BFPT",
+ BCEQZ: "BFPF",
+ BEQ: "BEQ",
+ BNE: "BNE",
+ BEQZ: "BEQ",
+ BNEZ: "BNE",
+ BLT: "BLT",
+ BLTU: "BLTU",
+ BGE: "BGE",
+ BGEU: "BGEU",
+ B: "JMP",
+ BL: "CALL",
+ LD_B: "MOVB",
+ LD_H: "MOVH",
+ LD_W: "MOVW",
+ LD_D: "MOVV",
+ LD_BU: "MOVBU",
+ LD_HU: "MOVHU",
+ LD_WU: "MOVWU",
+ ST_B: "MOVB",
+ ST_H: "MOVH",
+ ST_W: "MOVW",
+ ST_D: "MOVV",
+ LDX_B: "MOVB",
+ LDX_BU: "MOVBU",
+ LDX_D: "MOVV",
+ LDX_H: "MOVH",
+ LDX_HU: "MOVHU",
+ LDX_W: "MOVW",
+ LDX_WU: "MOVWU",
+ STX_B: "MOVB",
+ STX_D: "MOVV",
+ STX_H: "MOVH",
+ STX_W: "MOVW",
+ AMADD_B: "AMADDB",
+ AMADD_D: "AMADDV",
+ AMADD_DB_B: "AMADDDBB",
+ AMADD_DB_D: "AMADDDBV",
+ AMADD_DB_H: "AMADDDBH",
+ AMADD_DB_W: "AMADDDBW",
+ AMADD_H: "AMADDH",
+ AMADD_W: "AMADDW",
+ AMAND_D: "AMANDV",
+ AMAND_DB_D: "AMANDDBV",
+ AMAND_DB_W: "AMANDDBW",
+ AMAND_W: "AMANDW",
+ AMCAS_B: "AMCASB",
+ AMCAS_D: "AMCASV",
+ AMCAS_DB_B: "AMCASDBB",
+ AMCAS_DB_D: "AMCASDBV",
+ AMCAS_DB_H: "AMCASDBH",
+ AMCAS_DB_W: "AMCASDBW",
+ AMCAS_H: "AMCASH",
+ AMCAS_W: "AMCASW",
+ AMMAX_D: "AMMAXV",
+ AMMAX_DB_D: "AMMAXDBV",
+ AMMAX_DB_DU: "AMMAXDBVU",
+ AMMAX_DB_W: "AMMAXDBW",
+ AMMAX_DB_WU: "AMMAXDBWU",
+ AMMAX_DU: "AMMAXVU",
+ AMMAX_W: "AMMAXW",
+ AMMAX_WU: "AMMAXWU",
+ AMMIN_D: "AMMINV",
+ AMMIN_DB_D: "AMMINDBV",
+ AMMIN_DB_DU: "AMMINDBVU",
+ AMMIN_DB_W: "AMMINDBW",
+ AMMIN_DB_WU: "AMMINDBWU",
+ AMMIN_DU: "AMMINVU",
+ AMMIN_W: "AMMINW",
+ AMMIN_WU: "AMMINWU",
+ AMOR_D: "AMORV",
+ AMOR_DB_D: "AMORDBV",
+ AMOR_DB_W: "AMORDBW",
+ AMOR_W: "AMORW",
+ AMSWAP_B: "AMSWAPB",
+ AMSWAP_D: "AMSWAPV",
+ AMSWAP_DB_B: "AMSWAPDBB",
+ AMSWAP_DB_D: "AMSWAPDBV",
+ AMSWAP_DB_H: "AMSWAPDBH",
+ AMSWAP_DB_W: "AMSWAPDBW",
+ AMSWAP_H: "AMSWAPH",
+ AMSWAP_W: "AMSWAPW",
+ AMXOR_D: "AMXORV",
+ AMXOR_DB_D: "AMXORDBV",
+ AMXOR_DB_W: "AMXORDBW",
+ AMXOR_W: "AMXORW",
+ LL_W: "LL",
+ LL_D: "LLV",
+ SC_W: "SC",
+ SC_D: "SCV",
+ CRCC_W_B_W: "CRCCWBW",
+ CRCC_W_D_W: "CRCCWVW",
+ CRCC_W_H_W: "CRCCWHW",
+ CRCC_W_W_W: "CRCCWWW",
+ CRC_W_B_W: "CRCWBW",
+ CRC_W_D_W: "CRCWVW",
+ CRC_W_H_W: "CRCWHW",
+ CRC_W_W_W: "CRCWWW",
+ DBAR: "DBAR",
+ SYSCALL: "SYSCALL",
+ BREAK: "BREAK",
+ RDTIMEL_W: "RDTIMELW",
+ RDTIMEH_W: "RDTIMEHW",
+ RDTIME_D: "RDTIMED",
+ CPUCFG: "CPUCFG",
+
+ // Floating-point instructions
+ FADD_S: "ADDF",
+ FADD_D: "ADDD",
+ FSUB_S: "SUBF",
+ FSUB_D: "SUBD",
+ FMUL_S: "MULF",
+ FMUL_D: "MULD",
+ FDIV_S: "DIVF",
+ FDIV_D: "DIVD",
+ FMSUB_S: "FMSUBF",
+ FMSUB_D: "FMSUBD",
+ FMADD_S: "FMADDF",
+ FMADD_D: "FMADDD",
+ FNMADD_S: "FNMADDF",
+ FNMADD_D: "FNMADDD",
+ FNMSUB_S: "FNMSUBF",
+ FNMSUB_D: "FNMSUBD",
+ FABS_S: "ABSF",
+ FABS_D: "ABSD",
+ FNEG_S: "NEGF",
+ FNEG_D: "NEGD",
+ FSQRT_S: "SQRTF",
+ FSQRT_D: "SQRTD",
+ FCOPYSIGN_S: "FCOPYSGF",
+ FCOPYSIGN_D: "FCOPYSGD",
+ FMAX_S: "FMAXF",
+ FMAX_D: "FMAXD",
+ FMIN_S: "FMINF",
+ FMIN_D: "FMIND",
+ FCLASS_S: "FCLASSF",
+ FCLASS_D: "FCLASSD",
+ FCMP_CEQ_S: "CMPEQF",
+ FCMP_CEQ_D: "CMPEQD",
+ FCMP_SLE_S: "CMPGEF",
+ FCMP_SLE_D: "CMPGED",
+ FCMP_SLT_S: "CMPGTF",
+ FCMP_SLT_D: "CMPGTD",
+ FCVT_D_S: "MOVFD",
+ FCVT_S_D: "MOVDF",
+ FFINT_S_W: "FFINTFW",
+ FFINT_S_L: "FFINTFV",
+ FFINT_D_W: "FFINTDW",
+ FFINT_D_L: "FFINTDV",
+ FTINTRM_L_D: "FTINTRMVD",
+ FTINTRM_L_S: "FTINTRMVF",
+ FTINTRM_W_D: "FTINTRMWD",
+ FTINTRM_W_S: "FTINTRMWF",
+ FTINTRNE_L_D: "FTINTRNEVD",
+ FTINTRNE_L_S: "FTINTRNEVF",
+ FTINTRNE_W_D: "FTINTRNEWD",
+ FTINTRNE_W_S: "FTINTRNEWF",
+ FTINTRP_L_D: "FTINTRPVD",
+ FTINTRP_L_S: "FTINTRPVF",
+ FTINTRP_W_D: "FTINTRPWD",
+ FTINTRP_W_S: "FTINTRPWF",
+ FTINTRZ_L_D: "FTINTRZVD",
+ FTINTRZ_L_S: "FTINTRZVF",
+ FTINTRZ_W_D: "FTINTRZWD",
+ FTINTRZ_W_S: "FTINTRZWF",
+ FTINT_L_D: "FTINTVD",
+ FTINT_L_S: "FTINTVF",
+ FTINT_W_D: "FTINTWD",
+ FTINT_W_S: "FTINTWF",
+ FRINT_S: "FRINTS",
+ FRINT_D: "FRINTD",
+ FMOV_S: "MOVF",
+ FMOV_D: "MOVD",
+ MOVGR2FR_W: "MOVW",
+ MOVGR2FR_D: "MOVV",
+ MOVFR2GR_S: "MOVW",
+ MOVFR2GR_D: "MOVV",
+ MOVGR2CF: "MOVV",
+ MOVCF2GR: "MOVV",
+ MOVFCSR2GR: "MOVV",
+ MOVGR2FCSR: "MOVV",
+ MOVFR2CF: "MOVV",
+ MOVCF2FR: "MOVV",
+ FLD_S: "MOVF",
+ FLD_D: "MOVD",
+ FST_S: "MOVF",
+ FST_D: "MOVD",
+ FLDX_S: "MOVF",
+ FLDX_D: "MOVD",
+ FSTX_S: "MOVF",
+ FSTX_D: "MOVD",
+}
diff --git a/loong64/loong64asm/tables.go b/loong64/loong64asm/tables.go
new file mode 100644
index 0000000..c85d47c
--- /dev/null
+++ b/loong64/loong64asm/tables.go
@@ -0,0 +1,1613 @@
+// Generated by loong64spec LoongArch-Vol1-EN.pdf, DO NOT EDIT.
+
+// 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
+
+const (
+ _ Op = iota
+ ADDI_D
+ ADDI_W
+ ADDU16I_D
+ ADD_D
+ ADD_W
+ ALSL_D
+ ALSL_W
+ ALSL_WU
+ AMADD_B
+ AMADD_D
+ AMADD_DB_B
+ AMADD_DB_D
+ AMADD_DB_H
+ AMADD_DB_W
+ AMADD_H
+ AMADD_W
+ AMAND_D
+ AMAND_DB_D
+ AMAND_DB_W
+ AMAND_W
+ AMCAS_B
+ AMCAS_D
+ AMCAS_DB_B
+ AMCAS_DB_D
+ AMCAS_DB_H
+ AMCAS_DB_W
+ AMCAS_H
+ AMCAS_W
+ AMMAX_D
+ AMMAX_DB_D
+ AMMAX_DB_DU
+ AMMAX_DB_W
+ AMMAX_DB_WU
+ AMMAX_DU
+ AMMAX_W
+ AMMAX_WU
+ AMMIN_D
+ AMMIN_DB_D
+ AMMIN_DB_DU
+ AMMIN_DB_W
+ AMMIN_DB_WU
+ AMMIN_DU
+ AMMIN_W
+ AMMIN_WU
+ AMOR_D
+ AMOR_DB_D
+ AMOR_DB_W
+ AMOR_W
+ AMSWAP_B
+ AMSWAP_D
+ AMSWAP_DB_B
+ AMSWAP_DB_D
+ AMSWAP_DB_H
+ AMSWAP_DB_W
+ AMSWAP_H
+ AMSWAP_W
+ AMXOR_D
+ AMXOR_DB_D
+ AMXOR_DB_W
+ AMXOR_W
+ AND
+ ANDI
+ ANDN
+ ASRTGT_D
+ ASRTLE_D
+ B
+ BCEQZ
+ BCNEZ
+ BEQ
+ BEQZ
+ BGE
+ BGEU
+ BITREV_4B
+ BITREV_8B
+ BITREV_D
+ BITREV_W
+ BL
+ BLT
+ BLTU
+ BNE
+ BNEZ
+ BREAK
+ BSTRINS_D
+ BSTRINS_W
+ BSTRPICK_D
+ BSTRPICK_W
+ BYTEPICK_D
+ BYTEPICK_W
+ CACOP
+ CLO_D
+ CLO_W
+ CLZ_D
+ CLZ_W
+ CPUCFG
+ CRCC_W_B_W
+ CRCC_W_D_W
+ CRCC_W_H_W
+ CRCC_W_W_W
+ CRC_W_B_W
+ CRC_W_D_W
+ CRC_W_H_W
+ CRC_W_W_W
+ CSRRD
+ CSRWR
+ CSRXCHG
+ CTO_D
+ CTO_W
+ CTZ_D
+ CTZ_W
+ DBAR
+ DBCL
+ DIV_D
+ DIV_DU
+ DIV_W
+ DIV_WU
+ ERTN
+ EXT_W_B
+ EXT_W_H
+ FABS_D
+ FABS_S
+ FADD_D
+ FADD_S
+ FCLASS_D
+ FCLASS_S
+ FCMP_CAF_D
+ FCMP_CAF_S
+ FCMP_CEQ_D
+ FCMP_CEQ_S
+ FCMP_CLE_D
+ FCMP_CLE_S
+ FCMP_CLT_D
+ FCMP_CLT_S
+ FCMP_CNE_D
+ FCMP_CNE_S
+ FCMP_COR_D
+ FCMP_COR_S
+ FCMP_CUEQ_D
+ FCMP_CUEQ_S
+ FCMP_CULE_D
+ FCMP_CULE_S
+ FCMP_CULT_D
+ FCMP_CULT_S
+ FCMP_CUNE_D
+ FCMP_CUNE_S
+ FCMP_CUN_D
+ FCMP_CUN_S
+ FCMP_SAF_D
+ FCMP_SAF_S
+ FCMP_SEQ_D
+ FCMP_SEQ_S
+ FCMP_SLE_D
+ FCMP_SLE_S
+ FCMP_SLT_D
+ FCMP_SLT_S
+ FCMP_SNE_D
+ FCMP_SNE_S
+ FCMP_SOR_D
+ FCMP_SOR_S
+ FCMP_SUEQ_D
+ FCMP_SUEQ_S
+ FCMP_SULE_D
+ FCMP_SULE_S
+ FCMP_SULT_D
+ FCMP_SULT_S
+ FCMP_SUNE_D
+ FCMP_SUNE_S
+ FCMP_SUN_D
+ FCMP_SUN_S
+ FCOPYSIGN_D
+ FCOPYSIGN_S
+ FCVT_D_S
+ FCVT_S_D
+ FDIV_D
+ FDIV_S
+ FFINT_D_L
+ FFINT_D_W
+ FFINT_S_L
+ FFINT_S_W
+ FLDGT_D
+ FLDGT_S
+ FLDLE_D
+ FLDLE_S
+ FLDX_D
+ FLDX_S
+ FLD_D
+ FLD_S
+ FLOGB_D
+ FLOGB_S
+ FMADD_D
+ FMADD_S
+ FMAXA_D
+ FMAXA_S
+ FMAX_D
+ FMAX_S
+ FMINA_D
+ FMINA_S
+ FMIN_D
+ FMIN_S
+ FMOV_D
+ FMOV_S
+ FMSUB_D
+ FMSUB_S
+ FMUL_D
+ FMUL_S
+ FNEG_D
+ FNEG_S
+ FNMADD_D
+ FNMADD_S
+ FNMSUB_D
+ FNMSUB_S
+ FRECIPE_D
+ FRECIPE_S
+ FRECIP_D
+ FRECIP_S
+ FRINT_D
+ FRINT_S
+ FRSQRTE_D
+ FRSQRTE_S
+ FRSQRT_D
+ FRSQRT_S
+ FSCALEB_D
+ FSCALEB_S
+ FSEL
+ FSQRT_D
+ FSQRT_S
+ FSTGT_D
+ FSTGT_S
+ FSTLE_D
+ FSTLE_S
+ FSTX_D
+ FSTX_S
+ FST_D
+ FST_S
+ FSUB_D
+ FSUB_S
+ FTINTRM_L_D
+ FTINTRM_L_S
+ FTINTRM_W_D
+ FTINTRM_W_S
+ FTINTRNE_L_D
+ FTINTRNE_L_S
+ FTINTRNE_W_D
+ FTINTRNE_W_S
+ FTINTRP_L_D
+ FTINTRP_L_S
+ FTINTRP_W_D
+ FTINTRP_W_S
+ FTINTRZ_L_D
+ FTINTRZ_L_S
+ FTINTRZ_W_D
+ FTINTRZ_W_S
+ FTINT_L_D
+ FTINT_L_S
+ FTINT_W_D
+ FTINT_W_S
+ IBAR
+ IDLE
+ INVTLB
+ IOCSRRD_B
+ IOCSRRD_D
+ IOCSRRD_H
+ IOCSRRD_W
+ IOCSRWR_B
+ IOCSRWR_D
+ IOCSRWR_H
+ IOCSRWR_W
+ JIRL
+ LDDIR
+ LDGT_B
+ LDGT_D
+ LDGT_H
+ LDGT_W
+ LDLE_B
+ LDLE_D
+ LDLE_H
+ LDLE_W
+ LDPTE
+ LDPTR_D
+ LDPTR_W
+ LDX_B
+ LDX_BU
+ LDX_D
+ LDX_H
+ LDX_HU
+ LDX_W
+ LDX_WU
+ LD_B
+ LD_BU
+ LD_D
+ LD_H
+ LD_HU
+ LD_W
+ LD_WU
+ LLACQ_D
+ LLACQ_W
+ LL_D
+ LL_W
+ LU12I_W
+ LU32I_D
+ LU52I_D
+ MASKEQZ
+ MASKNEZ
+ MOD_D
+ MOD_DU
+ MOD_W
+ MOD_WU
+ MOVCF2FR
+ MOVCF2GR
+ MOVFCSR2GR
+ MOVFR2CF
+ MOVFR2GR_D
+ MOVFR2GR_S
+ MOVFRH2GR_S
+ MOVGR2CF
+ MOVGR2FCSR
+ MOVGR2FRH_W
+ MOVGR2FR_D
+ MOVGR2FR_W
+ MULH_D
+ MULH_DU
+ MULH_W
+ MULH_WU
+ MULW_D_W
+ MULW_D_WU
+ MUL_D
+ MUL_W
+ NOR
+ OR
+ ORI
+ ORN
+ PCADDI
+ PCADDU12I
+ PCADDU18I
+ PCALAU12I
+ PRELD
+ PRELDX
+ RDTIMEH_W
+ RDTIMEL_W
+ RDTIME_D
+ REVB_2H
+ REVB_2W
+ REVB_4H
+ REVB_D
+ REVH_2W
+ REVH_D
+ ROTRI_D
+ ROTRI_W
+ ROTR_D
+ ROTR_W
+ SCREL_D
+ SCREL_W
+ SC_D
+ SC_Q
+ SC_W
+ SLLI_D
+ SLLI_W
+ SLL_D
+ SLL_W
+ SLT
+ SLTI
+ SLTU
+ SLTUI
+ SRAI_D
+ SRAI_W
+ SRA_D
+ SRA_W
+ SRLI_D
+ SRLI_W
+ SRL_D
+ SRL_W
+ STGT_B
+ STGT_D
+ STGT_H
+ STGT_W
+ STLE_B
+ STLE_D
+ STLE_H
+ STLE_W
+ STPTR_D
+ STPTR_W
+ STX_B
+ STX_D
+ STX_H
+ STX_W
+ ST_B
+ ST_D
+ ST_H
+ ST_W
+ SUB_D
+ SUB_W
+ SYSCALL
+ TLBCLR
+ TLBFILL
+ TLBFLUSH
+ TLBRD
+ TLBSRCH
+ TLBWR
+ XOR
+ XORI
+)
+
+var opstr = [...]string{
+ ADDI_D: "ADDI.D",
+ ADDI_W: "ADDI.W",
+ ADDU16I_D: "ADDU16I.D",
+ ADD_D: "ADD.D",
+ ADD_W: "ADD.W",
+ ALSL_D: "ALSL.D",
+ ALSL_W: "ALSL.W",
+ ALSL_WU: "ALSL.WU",
+ AMADD_B: "AMADD.B",
+ AMADD_D: "AMADD.D",
+ AMADD_DB_B: "AMADD_DB.B",
+ AMADD_DB_D: "AMADD_DB.D",
+ AMADD_DB_H: "AMADD_DB.H",
+ AMADD_DB_W: "AMADD_DB.W",
+ AMADD_H: "AMADD.H",
+ AMADD_W: "AMADD.W",
+ AMAND_D: "AMAND.D",
+ AMAND_DB_D: "AMAND_DB.D",
+ AMAND_DB_W: "AMAND_DB.W",
+ AMAND_W: "AMAND.W",
+ AMCAS_B: "AMCAS.B",
+ AMCAS_D: "AMCAS.D",
+ AMCAS_DB_B: "AMCAS_DB.B",
+ AMCAS_DB_D: "AMCAS_DB.D",
+ AMCAS_DB_H: "AMCAS_DB.H",
+ AMCAS_DB_W: "AMCAS_DB.W",
+ AMCAS_H: "AMCAS.H",
+ AMCAS_W: "AMCAS.W",
+ AMMAX_D: "AMMAX.D",
+ AMMAX_DB_D: "AMMAX_DB.D",
+ AMMAX_DB_DU: "AMMAX_DB.DU",
+ AMMAX_DB_W: "AMMAX_DB.W",
+ AMMAX_DB_WU: "AMMAX_DB.WU",
+ AMMAX_DU: "AMMAX.DU",
+ AMMAX_W: "AMMAX.W",
+ AMMAX_WU: "AMMAX.WU",
+ AMMIN_D: "AMMIN.D",
+ AMMIN_DB_D: "AMMIN_DB.D",
+ AMMIN_DB_DU: "AMMIN_DB.DU",
+ AMMIN_DB_W: "AMMIN_DB.W",
+ AMMIN_DB_WU: "AMMIN_DB.WU",
+ AMMIN_DU: "AMMIN.DU",
+ AMMIN_W: "AMMIN.W",
+ AMMIN_WU: "AMMIN.WU",
+ AMOR_D: "AMOR.D",
+ AMOR_DB_D: "AMOR_DB.D",
+ AMOR_DB_W: "AMOR_DB.W",
+ AMOR_W: "AMOR.W",
+ AMSWAP_B: "AMSWAP.B",
+ AMSWAP_D: "AMSWAP.D",
+ AMSWAP_DB_B: "AMSWAP_DB.B",
+ AMSWAP_DB_D: "AMSWAP_DB.D",
+ AMSWAP_DB_H: "AMSWAP_DB.H",
+ AMSWAP_DB_W: "AMSWAP_DB.W",
+ AMSWAP_H: "AMSWAP.H",
+ AMSWAP_W: "AMSWAP.W",
+ AMXOR_D: "AMXOR.D",
+ AMXOR_DB_D: "AMXOR_DB.D",
+ AMXOR_DB_W: "AMXOR_DB.W",
+ AMXOR_W: "AMXOR.W",
+ AND: "AND",
+ ANDI: "ANDI",
+ ANDN: "ANDN",
+ ASRTGT_D: "ASRTGT.D",
+ ASRTLE_D: "ASRTLE.D",
+ B: "B",
+ BCEQZ: "BCEQZ",
+ BCNEZ: "BCNEZ",
+ BEQ: "BEQ",
+ BEQZ: "BEQZ",
+ BGE: "BGE",
+ BGEU: "BGEU",
+ BITREV_4B: "BITREV.4B",
+ BITREV_8B: "BITREV.8B",
+ BITREV_D: "BITREV.D",
+ BITREV_W: "BITREV.W",
+ BL: "BL",
+ BLT: "BLT",
+ BLTU: "BLTU",
+ BNE: "BNE",
+ BNEZ: "BNEZ",
+ BREAK: "BREAK",
+ BSTRINS_D: "BSTRINS.D",
+ BSTRINS_W: "BSTRINS.W",
+ BSTRPICK_D: "BSTRPICK.D",
+ BSTRPICK_W: "BSTRPICK.W",
+ BYTEPICK_D: "BYTEPICK.D",
+ BYTEPICK_W: "BYTEPICK.W",
+ CACOP: "CACOP",
+ CLO_D: "CLO.D",
+ CLO_W: "CLO.W",
+ CLZ_D: "CLZ.D",
+ CLZ_W: "CLZ.W",
+ CPUCFG: "CPUCFG",
+ CRCC_W_B_W: "CRCC.W.B.W",
+ CRCC_W_D_W: "CRCC.W.D.W",
+ CRCC_W_H_W: "CRCC.W.H.W",
+ CRCC_W_W_W: "CRCC.W.W.W",
+ CRC_W_B_W: "CRC.W.B.W",
+ CRC_W_D_W: "CRC.W.D.W",
+ CRC_W_H_W: "CRC.W.H.W",
+ CRC_W_W_W: "CRC.W.W.W",
+ CSRRD: "CSRRD",
+ CSRWR: "CSRWR",
+ CSRXCHG: "CSRXCHG",
+ CTO_D: "CTO.D",
+ CTO_W: "CTO.W",
+ CTZ_D: "CTZ.D",
+ CTZ_W: "CTZ.W",
+ DBAR: "DBAR",
+ DBCL: "DBCL",
+ DIV_D: "DIV.D",
+ DIV_DU: "DIV.DU",
+ DIV_W: "DIV.W",
+ DIV_WU: "DIV.WU",
+ ERTN: "ERTN",
+ EXT_W_B: "EXT.W.B",
+ EXT_W_H: "EXT.W.H",
+ FABS_D: "FABS.D",
+ FABS_S: "FABS.S",
+ FADD_D: "FADD.D",
+ FADD_S: "FADD.S",
+ FCLASS_D: "FCLASS.D",
+ FCLASS_S: "FCLASS.S",
+ FCMP_CAF_D: "FCMP.CAF.D",
+ FCMP_CAF_S: "FCMP.CAF.S",
+ FCMP_CEQ_D: "FCMP.CEQ.D",
+ FCMP_CEQ_S: "FCMP.CEQ.S",
+ FCMP_CLE_D: "FCMP.CLE.D",
+ FCMP_CLE_S: "FCMP.CLE.S",
+ FCMP_CLT_D: "FCMP.CLT.D",
+ FCMP_CLT_S: "FCMP.CLT.S",
+ FCMP_CNE_D: "FCMP.CNE.D",
+ FCMP_CNE_S: "FCMP.CNE.S",
+ FCMP_COR_D: "FCMP.COR.D",
+ FCMP_COR_S: "FCMP.COR.S",
+ FCMP_CUEQ_D: "FCMP.CUEQ.D",
+ FCMP_CUEQ_S: "FCMP.CUEQ.S",
+ FCMP_CULE_D: "FCMP.CULE.D",
+ FCMP_CULE_S: "FCMP.CULE.S",
+ FCMP_CULT_D: "FCMP.CULT.D",
+ FCMP_CULT_S: "FCMP.CULT.S",
+ FCMP_CUNE_D: "FCMP.CUNE.D",
+ FCMP_CUNE_S: "FCMP.CUNE.S",
+ FCMP_CUN_D: "FCMP.CUN.D",
+ FCMP_CUN_S: "FCMP.CUN.S",
+ FCMP_SAF_D: "FCMP.SAF.D",
+ FCMP_SAF_S: "FCMP.SAF.S",
+ FCMP_SEQ_D: "FCMP.SEQ.D",
+ FCMP_SEQ_S: "FCMP.SEQ.S",
+ FCMP_SLE_D: "FCMP.SLE.D",
+ FCMP_SLE_S: "FCMP.SLE.S",
+ FCMP_SLT_D: "FCMP.SLT.D",
+ FCMP_SLT_S: "FCMP.SLT.S",
+ FCMP_SNE_D: "FCMP.SNE.D",
+ FCMP_SNE_S: "FCMP.SNE.S",
+ FCMP_SOR_D: "FCMP.SOR.D",
+ FCMP_SOR_S: "FCMP.SOR.S",
+ FCMP_SUEQ_D: "FCMP.SUEQ.D",
+ FCMP_SUEQ_S: "FCMP.SUEQ.S",
+ FCMP_SULE_D: "FCMP.SULE.D",
+ FCMP_SULE_S: "FCMP.SULE.S",
+ FCMP_SULT_D: "FCMP.SULT.D",
+ FCMP_SULT_S: "FCMP.SULT.S",
+ FCMP_SUNE_D: "FCMP.SUNE.D",
+ FCMP_SUNE_S: "FCMP.SUNE.S",
+ FCMP_SUN_D: "FCMP.SUN.D",
+ FCMP_SUN_S: "FCMP.SUN.S",
+ FCOPYSIGN_D: "FCOPYSIGN.D",
+ FCOPYSIGN_S: "FCOPYSIGN.S",
+ FCVT_D_S: "FCVT.D.S",
+ FCVT_S_D: "FCVT.S.D",
+ FDIV_D: "FDIV.D",
+ FDIV_S: "FDIV.S",
+ FFINT_D_L: "FFINT.D.L",
+ FFINT_D_W: "FFINT.D.W",
+ FFINT_S_L: "FFINT.S.L",
+ FFINT_S_W: "FFINT.S.W",
+ FLDGT_D: "FLDGT.D",
+ FLDGT_S: "FLDGT.S",
+ FLDLE_D: "FLDLE.D",
+ FLDLE_S: "FLDLE.S",
+ FLDX_D: "FLDX.D",
+ FLDX_S: "FLDX.S",
+ FLD_D: "FLD.D",
+ FLD_S: "FLD.S",
+ FLOGB_D: "FLOGB.D",
+ FLOGB_S: "FLOGB.S",
+ FMADD_D: "FMADD.D",
+ FMADD_S: "FMADD.S",
+ FMAXA_D: "FMAXA.D",
+ FMAXA_S: "FMAXA.S",
+ FMAX_D: "FMAX.D",
+ FMAX_S: "FMAX.S",
+ FMINA_D: "FMINA.D",
+ FMINA_S: "FMINA.S",
+ FMIN_D: "FMIN.D",
+ FMIN_S: "FMIN.S",
+ FMOV_D: "FMOV.D",
+ FMOV_S: "FMOV.S",
+ FMSUB_D: "FMSUB.D",
+ FMSUB_S: "FMSUB.S",
+ FMUL_D: "FMUL.D",
+ FMUL_S: "FMUL.S",
+ FNEG_D: "FNEG.D",
+ FNEG_S: "FNEG.S",
+ FNMADD_D: "FNMADD.D",
+ FNMADD_S: "FNMADD.S",
+ FNMSUB_D: "FNMSUB.D",
+ FNMSUB_S: "FNMSUB.S",
+ FRECIPE_D: "FRECIPE.D",
+ FRECIPE_S: "FRECIPE.S",
+ FRECIP_D: "FRECIP.D",
+ FRECIP_S: "FRECIP.S",
+ FRINT_D: "FRINT.D",
+ FRINT_S: "FRINT.S",
+ FRSQRTE_D: "FRSQRTE.D",
+ FRSQRTE_S: "FRSQRTE.S",
+ FRSQRT_D: "FRSQRT.D",
+ FRSQRT_S: "FRSQRT.S",
+ FSCALEB_D: "FSCALEB.D",
+ FSCALEB_S: "FSCALEB.S",
+ FSEL: "FSEL",
+ FSQRT_D: "FSQRT.D",
+ FSQRT_S: "FSQRT.S",
+ FSTGT_D: "FSTGT.D",
+ FSTGT_S: "FSTGT.S",
+ FSTLE_D: "FSTLE.D",
+ FSTLE_S: "FSTLE.S",
+ FSTX_D: "FSTX.D",
+ FSTX_S: "FSTX.S",
+ FST_D: "FST.D",
+ FST_S: "FST.S",
+ FSUB_D: "FSUB.D",
+ FSUB_S: "FSUB.S",
+ FTINTRM_L_D: "FTINTRM.L.D",
+ FTINTRM_L_S: "FTINTRM.L.S",
+ FTINTRM_W_D: "FTINTRM.W.D",
+ FTINTRM_W_S: "FTINTRM.W.S",
+ FTINTRNE_L_D: "FTINTRNE.L.D",
+ FTINTRNE_L_S: "FTINTRNE.L.S",
+ FTINTRNE_W_D: "FTINTRNE.W.D",
+ FTINTRNE_W_S: "FTINTRNE.W.S",
+ FTINTRP_L_D: "FTINTRP.L.D",
+ FTINTRP_L_S: "FTINTRP.L.S",
+ FTINTRP_W_D: "FTINTRP.W.D",
+ FTINTRP_W_S: "FTINTRP.W.S",
+ FTINTRZ_L_D: "FTINTRZ.L.D",
+ FTINTRZ_L_S: "FTINTRZ.L.S",
+ FTINTRZ_W_D: "FTINTRZ.W.D",
+ FTINTRZ_W_S: "FTINTRZ.W.S",
+ FTINT_L_D: "FTINT.L.D",
+ FTINT_L_S: "FTINT.L.S",
+ FTINT_W_D: "FTINT.W.D",
+ FTINT_W_S: "FTINT.W.S",
+ IBAR: "IBAR",
+ IDLE: "IDLE",
+ INVTLB: "INVTLB",
+ IOCSRRD_B: "IOCSRRD.B",
+ IOCSRRD_D: "IOCSRRD.D",
+ IOCSRRD_H: "IOCSRRD.H",
+ IOCSRRD_W: "IOCSRRD.W",
+ IOCSRWR_B: "IOCSRWR.B",
+ IOCSRWR_D: "IOCSRWR.D",
+ IOCSRWR_H: "IOCSRWR.H",
+ IOCSRWR_W: "IOCSRWR.W",
+ JIRL: "JIRL",
+ LDDIR: "LDDIR",
+ LDGT_B: "LDGT.B",
+ LDGT_D: "LDGT.D",
+ LDGT_H: "LDGT.H",
+ LDGT_W: "LDGT.W",
+ LDLE_B: "LDLE.B",
+ LDLE_D: "LDLE.D",
+ LDLE_H: "LDLE.H",
+ LDLE_W: "LDLE.W",
+ LDPTE: "LDPTE",
+ LDPTR_D: "LDPTR.D",
+ LDPTR_W: "LDPTR.W",
+ LDX_B: "LDX.B",
+ LDX_BU: "LDX.BU",
+ LDX_D: "LDX.D",
+ LDX_H: "LDX.H",
+ LDX_HU: "LDX.HU",
+ LDX_W: "LDX.W",
+ LDX_WU: "LDX.WU",
+ LD_B: "LD.B",
+ LD_BU: "LD.BU",
+ LD_D: "LD.D",
+ LD_H: "LD.H",
+ LD_HU: "LD.HU",
+ LD_W: "LD.W",
+ LD_WU: "LD.WU",
+ LLACQ_D: "LLACQ.D",
+ LLACQ_W: "LLACQ.W",
+ LL_D: "LL.D",
+ LL_W: "LL.W",
+ LU12I_W: "LU12I.W",
+ LU32I_D: "LU32I.D",
+ LU52I_D: "LU52I.D",
+ MASKEQZ: "MASKEQZ",
+ MASKNEZ: "MASKNEZ",
+ MOD_D: "MOD.D",
+ MOD_DU: "MOD.DU",
+ MOD_W: "MOD.W",
+ MOD_WU: "MOD.WU",
+ MOVCF2FR: "MOVCF2FR",
+ MOVCF2GR: "MOVCF2GR",
+ MOVFCSR2GR: "MOVFCSR2GR",
+ MOVFR2CF: "MOVFR2CF",
+ MOVFR2GR_D: "MOVFR2GR.D",
+ MOVFR2GR_S: "MOVFR2GR.S",
+ MOVFRH2GR_S: "MOVFRH2GR.S",
+ MOVGR2CF: "MOVGR2CF",
+ MOVGR2FCSR: "MOVGR2FCSR",
+ MOVGR2FRH_W: "MOVGR2FRH.W",
+ MOVGR2FR_D: "MOVGR2FR.D",
+ MOVGR2FR_W: "MOVGR2FR.W",
+ MULH_D: "MULH.D",
+ MULH_DU: "MULH.DU",
+ MULH_W: "MULH.W",
+ MULH_WU: "MULH.WU",
+ MULW_D_W: "MULW.D.W",
+ MULW_D_WU: "MULW.D.WU",
+ MUL_D: "MUL.D",
+ MUL_W: "MUL.W",
+ NOR: "NOR",
+ OR: "OR",
+ ORI: "ORI",
+ ORN: "ORN",
+ PCADDI: "PCADDI",
+ PCADDU12I: "PCADDU12I",
+ PCADDU18I: "PCADDU18I",
+ PCALAU12I: "PCALAU12I",
+ PRELD: "PRELD",
+ PRELDX: "PRELDX",
+ RDTIMEH_W: "RDTIMEH.W",
+ RDTIMEL_W: "RDTIMEL.W",
+ RDTIME_D: "RDTIME.D",
+ REVB_2H: "REVB.2H",
+ REVB_2W: "REVB.2W",
+ REVB_4H: "REVB.4H",
+ REVB_D: "REVB.D",
+ REVH_2W: "REVH.2W",
+ REVH_D: "REVH.D",
+ ROTRI_D: "ROTRI.D",
+ ROTRI_W: "ROTRI.W",
+ ROTR_D: "ROTR.D",
+ ROTR_W: "ROTR.W",
+ SCREL_D: "SCREL.D",
+ SCREL_W: "SCREL.W",
+ SC_D: "SC.D",
+ SC_Q: "SC.Q",
+ SC_W: "SC.W",
+ SLLI_D: "SLLI.D",
+ SLLI_W: "SLLI.W",
+ SLL_D: "SLL.D",
+ SLL_W: "SLL.W",
+ SLT: "SLT",
+ SLTI: "SLTI",
+ SLTU: "SLTU",
+ SLTUI: "SLTUI",
+ SRAI_D: "SRAI.D",
+ SRAI_W: "SRAI.W",
+ SRA_D: "SRA.D",
+ SRA_W: "SRA.W",
+ SRLI_D: "SRLI.D",
+ SRLI_W: "SRLI.W",
+ SRL_D: "SRL.D",
+ SRL_W: "SRL.W",
+ STGT_B: "STGT.B",
+ STGT_D: "STGT.D",
+ STGT_H: "STGT.H",
+ STGT_W: "STGT.W",
+ STLE_B: "STLE.B",
+ STLE_D: "STLE.D",
+ STLE_H: "STLE.H",
+ STLE_W: "STLE.W",
+ STPTR_D: "STPTR.D",
+ STPTR_W: "STPTR.W",
+ STX_B: "STX.B",
+ STX_D: "STX.D",
+ STX_H: "STX.H",
+ STX_W: "STX.W",
+ ST_B: "ST.B",
+ ST_D: "ST.D",
+ ST_H: "ST.H",
+ ST_W: "ST.W",
+ SUB_D: "SUB.D",
+ SUB_W: "SUB.W",
+ SYSCALL: "SYSCALL",
+ TLBCLR: "TLBCLR",
+ TLBFILL: "TLBFILL",
+ TLBFLUSH: "TLBFLUSH",
+ TLBRD: "TLBRD",
+ TLBSRCH: "TLBSRCH",
+ TLBWR: "TLBWR",
+ XOR: "XOR",
+ XORI: "XORI",
+}
+
+var instFormats = [...]instFormat{
+ // ADDI.D rd, rj, si12
+ {mask: 0xffc00000, value: 0x02c00000, op: ADDI_D, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}},
+ // ADDI.W rd, rj, si12
+ {mask: 0xffc00000, value: 0x02800000, op: ADDI_W, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}},
+ // ADDU16I.D rd, rj, si16
+ {mask: 0xfc000000, value: 0x10000000, op: ADDU16I_D, args: instArgs{arg_rd, arg_rj, arg_si16_25_10}},
+ // ADD.D rd, rj, rk
+ {mask: 0xffff8000, value: 0x00108000, op: ADD_D, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // ADD.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x00100000, op: ADD_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // ALSL.D rd, rj, rk, sa2
+ {mask: 0xfffe0000, value: 0x002c0000, op: ALSL_D, args: instArgs{arg_rd, arg_rj, arg_rk, arg_sa2_16_15}},
+ // ALSL.W rd, rj, rk, sa2
+ {mask: 0xfffe0000, value: 0x00040000, op: ALSL_W, args: instArgs{arg_rd, arg_rj, arg_rk, arg_sa2_16_15}},
+ // ALSL.WU rd, rj, rk, sa2
+ {mask: 0xfffe0000, value: 0x00060000, op: ALSL_WU, args: instArgs{arg_rd, arg_rj, arg_rk, arg_sa2_16_15}},
+ // AMADD.B rd, rk, rj
+ {mask: 0xffff8000, value: 0x385d0000, op: AMADD_B, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMADD.D rd, rk, rj
+ {mask: 0xffff8000, value: 0x38618000, op: AMADD_D, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMADD_DB.B rd, rk, rj
+ {mask: 0xffff8000, value: 0x385f0000, op: AMADD_DB_B, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMADD_DB.D rd, rk, rj
+ {mask: 0xffff8000, value: 0x386a8000, op: AMADD_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMADD_DB.H rd, rk, rj
+ {mask: 0xffff8000, value: 0x385f8000, op: AMADD_DB_H, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMADD_DB.W rd, rk, rj
+ {mask: 0xffff8000, value: 0x386a0000, op: AMADD_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMADD.H rd, rk, rj
+ {mask: 0xffff8000, value: 0x385d8000, op: AMADD_H, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMADD.W rd, rk, rj
+ {mask: 0xffff8000, value: 0x38610000, op: AMADD_W, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMAND.D rd, rk, rj
+ {mask: 0xffff8000, value: 0x38628000, op: AMAND_D, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMAND_DB.D rd, rk, rj
+ {mask: 0xffff8000, value: 0x386b8000, op: AMAND_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMAND_DB.W rd, rk, rj
+ {mask: 0xffff8000, value: 0x386b0000, op: AMAND_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMAND.W rd, rk, rj
+ {mask: 0xffff8000, value: 0x38620000, op: AMAND_W, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMCAS.B rd, rk, rj
+ {mask: 0xffff8000, value: 0x38580000, op: AMCAS_B, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMCAS.D rd, rk, rj
+ {mask: 0xffff8000, value: 0x38598000, op: AMCAS_D, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMCAS_DB.B rd, rk, rj
+ {mask: 0xffff8000, value: 0x385a0000, op: AMCAS_DB_B, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMCAS_DB.D rd, rk, rj
+ {mask: 0xffff8000, value: 0x385b8000, op: AMCAS_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMCAS_DB.H rd, rk, rj
+ {mask: 0xffff8000, value: 0x385a8000, op: AMCAS_DB_H, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMCAS_DB.W rd, rk, rj
+ {mask: 0xffff8000, value: 0x385b0000, op: AMCAS_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMCAS.H rd, rk, rj
+ {mask: 0xffff8000, value: 0x38588000, op: AMCAS_H, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMCAS.W rd, rk, rj
+ {mask: 0xffff8000, value: 0x38590000, op: AMCAS_W, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMMAX.D rd, rk, rj
+ {mask: 0xffff8000, value: 0x38658000, op: AMMAX_D, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMMAX_DB.D rd, rk, rj
+ {mask: 0xffff8000, value: 0x386e8000, op: AMMAX_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMMAX_DB.DU rd, rk, rj
+ {mask: 0xffff8000, value: 0x38708000, op: AMMAX_DB_DU, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMMAX_DB.W rd, rk, rj
+ {mask: 0xffff8000, value: 0x386e0000, op: AMMAX_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMMAX_DB.WU rd, rk, rj
+ {mask: 0xffff8000, value: 0x38700000, op: AMMAX_DB_WU, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMMAX.DU rd, rk, rj
+ {mask: 0xffff8000, value: 0x38678000, op: AMMAX_DU, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMMAX.W rd, rk, rj
+ {mask: 0xffff8000, value: 0x38650000, op: AMMAX_W, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMMAX.WU rd, rk, rj
+ {mask: 0xffff8000, value: 0x38670000, op: AMMAX_WU, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMMIN.D rd, rk, rj
+ {mask: 0xffff8000, value: 0x38668000, op: AMMIN_D, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMMIN_DB.D rd, rk, rj
+ {mask: 0xffff8000, value: 0x386f8000, op: AMMIN_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMMIN_DB.DU rd, rk, rj
+ {mask: 0xffff8000, value: 0x38718000, op: AMMIN_DB_DU, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMMIN_DB.W rd, rk, rj
+ {mask: 0xffff8000, value: 0x386f0000, op: AMMIN_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMMIN_DB.WU rd, rk, rj
+ {mask: 0xffff8000, value: 0x38710000, op: AMMIN_DB_WU, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMMIN.DU rd, rk, rj
+ {mask: 0xffff8000, value: 0x38688000, op: AMMIN_DU, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMMIN.W rd, rk, rj
+ {mask: 0xffff8000, value: 0x38660000, op: AMMIN_W, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMMIN.WU rd, rk, rj
+ {mask: 0xffff8000, value: 0x38680000, op: AMMIN_WU, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMOR.D rd, rk, rj
+ {mask: 0xffff8000, value: 0x38638000, op: AMOR_D, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMOR_DB.D rd, rk, rj
+ {mask: 0xffff8000, value: 0x386c8000, op: AMOR_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMOR_DB.W rd, rk, rj
+ {mask: 0xffff8000, value: 0x386c0000, op: AMOR_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMOR.W rd, rk, rj
+ {mask: 0xffff8000, value: 0x38630000, op: AMOR_W, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMSWAP.B rd, rk, rj
+ {mask: 0xffff8000, value: 0x385c0000, op: AMSWAP_B, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMSWAP.D rd, rk, rj
+ {mask: 0xffff8000, value: 0x38608000, op: AMSWAP_D, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMSWAP_DB.B rd, rk, rj
+ {mask: 0xffff8000, value: 0x385e0000, op: AMSWAP_DB_B, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMSWAP_DB.D rd, rk, rj
+ {mask: 0xffff8000, value: 0x38698000, op: AMSWAP_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMSWAP_DB.H rd, rk, rj
+ {mask: 0xffff8000, value: 0x385e8000, op: AMSWAP_DB_H, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMSWAP_DB.W rd, rk, rj
+ {mask: 0xffff8000, value: 0x38690000, op: AMSWAP_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMSWAP.H rd, rk, rj
+ {mask: 0xffff8000, value: 0x385c8000, op: AMSWAP_H, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMSWAP.W rd, rk, rj
+ {mask: 0xffff8000, value: 0x38600000, op: AMSWAP_W, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMXOR.D rd, rk, rj
+ {mask: 0xffff8000, value: 0x38648000, op: AMXOR_D, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMXOR_DB.D rd, rk, rj
+ {mask: 0xffff8000, value: 0x386d8000, op: AMXOR_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMXOR_DB.W rd, rk, rj
+ {mask: 0xffff8000, value: 0x386d0000, op: AMXOR_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AMXOR.W rd, rk, rj
+ {mask: 0xffff8000, value: 0x38640000, op: AMXOR_W, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // AND rd, rj, rk
+ {mask: 0xffff8000, value: 0x00148000, op: AND, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // ANDI rd, rj, ui12
+ {mask: 0xffc00000, value: 0x03400000, op: ANDI, args: instArgs{arg_rd, arg_rj, arg_ui12_21_10}},
+ // ANDN rd, rj, rk
+ {mask: 0xffff8000, value: 0x00168000, op: ANDN, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // ASRTGT.D rj, rk
+ {mask: 0xffff801f, value: 0x00018000, op: ASRTGT_D, args: instArgs{arg_rj, arg_rk}},
+ // ASRTLE.D rj, rk
+ {mask: 0xffff801f, value: 0x00010000, op: ASRTLE_D, args: instArgs{arg_rj, arg_rk}},
+ // B offs
+ {mask: 0xfc000000, value: 0x50000000, op: B, args: instArgs{arg_offset_25_0}},
+ // BCEQZ cj, offs
+ {mask: 0xfc000300, value: 0x48000000, op: BCEQZ, args: instArgs{arg_cj, arg_offset_20_0}},
+ // BCNEZ cj, offs
+ {mask: 0xfc000300, value: 0x48000100, op: BCNEZ, args: instArgs{arg_cj, arg_offset_20_0}},
+ // BEQ rj, rd, offs
+ {mask: 0xfc000000, value: 0x58000000, op: BEQ, args: instArgs{arg_rj, arg_rd, arg_offset_15_0}},
+ // BEQZ rj, offs
+ {mask: 0xfc000000, value: 0x40000000, op: BEQZ, args: instArgs{arg_rj, arg_offset_20_0}},
+ // BGE rj, rd, offs
+ {mask: 0xfc000000, value: 0x64000000, op: BGE, args: instArgs{arg_rj, arg_rd, arg_offset_15_0}},
+ // BGEU rj, rd, offs
+ {mask: 0xfc000000, value: 0x6c000000, op: BGEU, args: instArgs{arg_rj, arg_rd, arg_offset_15_0}},
+ // BITREV.4B rd, rj
+ {mask: 0xfffffc00, value: 0x00004800, op: BITREV_4B, args: instArgs{arg_rd, arg_rj}},
+ // BITREV.8B rd, rj
+ {mask: 0xfffffc00, value: 0x00004c00, op: BITREV_8B, args: instArgs{arg_rd, arg_rj}},
+ // BITREV.D rd, rj
+ {mask: 0xfffffc00, value: 0x00005400, op: BITREV_D, args: instArgs{arg_rd, arg_rj}},
+ // BITREV.W rd, rj
+ {mask: 0xfffffc00, value: 0x00005000, op: BITREV_W, args: instArgs{arg_rd, arg_rj}},
+ // BL offs
+ {mask: 0xfc000000, value: 0x54000000, op: BL, args: instArgs{arg_offset_25_0}},
+ // BLT rj, rd, offs
+ {mask: 0xfc000000, value: 0x60000000, op: BLT, args: instArgs{arg_rj, arg_rd, arg_offset_15_0}},
+ // BLTU rj, rd, offs
+ {mask: 0xfc000000, value: 0x68000000, op: BLTU, args: instArgs{arg_rj, arg_rd, arg_offset_15_0}},
+ // BNE rj, rd, offs
+ {mask: 0xfc000000, value: 0x5c000000, op: BNE, args: instArgs{arg_rj, arg_rd, arg_offset_15_0}},
+ // BNEZ rj, offs
+ {mask: 0xfc000000, value: 0x44000000, op: BNEZ, args: instArgs{arg_rj, arg_offset_20_0}},
+ // BREAK code
+ {mask: 0xffff8000, value: 0x002a0000, op: BREAK, args: instArgs{arg_code_14_0}},
+ // BSTRINS.D rd, rj, msbd, lsbd
+ {mask: 0xffc00000, value: 0x00800000, op: BSTRINS_D, args: instArgs{arg_rd, arg_rj, arg_msbd, arg_lsbd}},
+ // BSTRINS.W rd, rj, msbw, lsbw
+ {mask: 0xffe08000, value: 0x00600000, op: BSTRINS_W, args: instArgs{arg_rd, arg_rj, arg_msbw, arg_lsbw}},
+ // BSTRPICK.D rd, rj, msbd, lsbd
+ {mask: 0xffc00000, value: 0x00c00000, op: BSTRPICK_D, args: instArgs{arg_rd, arg_rj, arg_msbd, arg_lsbd}},
+ // BSTRPICK.W rd, rj, msbw, lsbw
+ {mask: 0xffe08000, value: 0x00608000, op: BSTRPICK_W, args: instArgs{arg_rd, arg_rj, arg_msbw, arg_lsbw}},
+ // BYTEPICK.D rd, rj, rk, sa3
+ {mask: 0xfffc0000, value: 0x000c0000, op: BYTEPICK_D, args: instArgs{arg_rd, arg_rj, arg_rk, arg_sa3_17_15}},
+ // BYTEPICK.W rd, rj, rk, sa2
+ {mask: 0xfffe0000, value: 0x00080000, op: BYTEPICK_W, args: instArgs{arg_rd, arg_rj, arg_rk, arg_sa2_16_15}},
+ // CACOP code, rj, si12
+ {mask: 0xffc00000, value: 0x06000000, op: CACOP, args: instArgs{arg_code_4_0, arg_rj, arg_si12_21_10}},
+ // CLO.D rd, rj
+ {mask: 0xfffffc00, value: 0x00002000, op: CLO_D, args: instArgs{arg_rd, arg_rj}},
+ // CLO.W rd, rj
+ {mask: 0xfffffc00, value: 0x00001000, op: CLO_W, args: instArgs{arg_rd, arg_rj}},
+ // CLZ.D rd, rj
+ {mask: 0xfffffc00, value: 0x00002400, op: CLZ_D, args: instArgs{arg_rd, arg_rj}},
+ // CLZ.W rd, rj
+ {mask: 0xfffffc00, value: 0x00001400, op: CLZ_W, args: instArgs{arg_rd, arg_rj}},
+ // CPUCFG rd, rj
+ {mask: 0xfffffc00, value: 0x00006c00, op: CPUCFG, args: instArgs{arg_rd, arg_rj}},
+ // CRCC.W.B.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x00260000, op: CRCC_W_B_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // CRCC.W.D.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x00278000, op: CRCC_W_D_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // CRCC.W.H.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x00268000, op: CRCC_W_H_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // CRCC.W.W.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x00270000, op: CRCC_W_W_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // CRC.W.B.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x00240000, op: CRC_W_B_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // CRC.W.D.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x00258000, op: CRC_W_D_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // CRC.W.H.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x00248000, op: CRC_W_H_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // CRC.W.W.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x00250000, op: CRC_W_W_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // CSRRD rd, csr
+ {mask: 0xff0003e0, value: 0x04000000, op: CSRRD, args: instArgs{arg_rd, arg_csr_23_10}},
+ // CSRWR rd, csr
+ {mask: 0xff0003e0, value: 0x04000020, op: CSRWR, args: instArgs{arg_rd, arg_csr_23_10}},
+ // CSRXCHG rd, rj, csr
+ {mask: 0xff000000, value: 0x04000000, op: CSRXCHG, args: instArgs{arg_rd, arg_rj, arg_csr_23_10}},
+ // CTO.D rd, rj
+ {mask: 0xfffffc00, value: 0x00002800, op: CTO_D, args: instArgs{arg_rd, arg_rj}},
+ // CTO.W rd, rj
+ {mask: 0xfffffc00, value: 0x00001800, op: CTO_W, args: instArgs{arg_rd, arg_rj}},
+ // CTZ.D rd, rj
+ {mask: 0xfffffc00, value: 0x00002c00, op: CTZ_D, args: instArgs{arg_rd, arg_rj}},
+ // CTZ.W rd, rj
+ {mask: 0xfffffc00, value: 0x00001c00, op: CTZ_W, args: instArgs{arg_rd, arg_rj}},
+ // DBAR hint
+ {mask: 0xffff8000, value: 0x38720000, op: DBAR, args: instArgs{arg_hint_14_0}},
+ // DBCL code
+ {mask: 0xffff8000, value: 0x002a8000, op: DBCL, args: instArgs{arg_code_14_0}},
+ // DIV.D rd, rj, rk
+ {mask: 0xffff8000, value: 0x00220000, op: DIV_D, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // DIV.DU rd, rj, rk
+ {mask: 0xffff8000, value: 0x00230000, op: DIV_DU, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // DIV.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x00200000, op: DIV_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // DIV.WU rd, rj, rk
+ {mask: 0xffff8000, value: 0x00210000, op: DIV_WU, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // ERTN
+ {mask: 0xffffffff, value: 0x06483800, op: ERTN, args: instArgs{}},
+ // EXT.W.B rd, rj
+ {mask: 0xfffffc00, value: 0x00005c00, op: EXT_W_B, args: instArgs{arg_rd, arg_rj}},
+ // EXT.W.H rd, rj
+ {mask: 0xfffffc00, value: 0x00005800, op: EXT_W_H, args: instArgs{arg_rd, arg_rj}},
+ // FABS.D fd, fj
+ {mask: 0xfffffc00, value: 0x01140800, op: FABS_D, args: instArgs{arg_fd, arg_fj}},
+ // FABS.S fd, fj
+ {mask: 0xfffffc00, value: 0x01140400, op: FABS_S, args: instArgs{arg_fd, arg_fj}},
+ // FADD.D fd, fj, fk
+ {mask: 0xffff8000, value: 0x01010000, op: FADD_D, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FADD.S fd, fj, fk
+ {mask: 0xffff8000, value: 0x01008000, op: FADD_S, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FCLASS.D fd, fj
+ {mask: 0xfffffc00, value: 0x01143800, op: FCLASS_D, args: instArgs{arg_fd, arg_fj}},
+ // FCLASS.S fd, fj
+ {mask: 0xfffffc00, value: 0x01143400, op: FCLASS_S, args: instArgs{arg_fd, arg_fj}},
+ // FCMP.CAF.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c200000, op: FCMP_CAF_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CAF.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c100000, op: FCMP_CAF_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CEQ.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c220000, op: FCMP_CEQ_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CEQ.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c120000, op: FCMP_CEQ_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CLE.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c230000, op: FCMP_CLE_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CLE.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c130000, op: FCMP_CLE_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CLT.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c210000, op: FCMP_CLT_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CLT.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c110000, op: FCMP_CLT_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CNE.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c280000, op: FCMP_CNE_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CNE.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c180000, op: FCMP_CNE_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.COR.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c2a0000, op: FCMP_COR_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.COR.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c1a0000, op: FCMP_COR_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CUEQ.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c260000, op: FCMP_CUEQ_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CUEQ.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c160000, op: FCMP_CUEQ_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CULE.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c270000, op: FCMP_CULE_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CULE.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c170000, op: FCMP_CULE_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CULT.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c250000, op: FCMP_CULT_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CULT.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c150000, op: FCMP_CULT_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CUNE.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c2c0000, op: FCMP_CUNE_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CUNE.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c1c0000, op: FCMP_CUNE_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CUN.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c240000, op: FCMP_CUN_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.CUN.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c140000, op: FCMP_CUN_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SAF.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c208000, op: FCMP_SAF_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SAF.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c108000, op: FCMP_SAF_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SEQ.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c228000, op: FCMP_SEQ_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SEQ.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c128000, op: FCMP_SEQ_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SLE.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c238000, op: FCMP_SLE_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SLE.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c138000, op: FCMP_SLE_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SLT.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c218000, op: FCMP_SLT_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SLT.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c118000, op: FCMP_SLT_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SNE.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c288000, op: FCMP_SNE_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SNE.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c188000, op: FCMP_SNE_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SOR.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c2a8000, op: FCMP_SOR_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SOR.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c1a8000, op: FCMP_SOR_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SUEQ.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c268000, op: FCMP_SUEQ_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SUEQ.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c168000, op: FCMP_SUEQ_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SULE.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c278000, op: FCMP_SULE_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SULE.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c178000, op: FCMP_SULE_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SULT.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c258000, op: FCMP_SULT_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SULT.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c158000, op: FCMP_SULT_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SUNE.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c2c8000, op: FCMP_SUNE_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SUNE.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c1c8000, op: FCMP_SUNE_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SUN.D cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c248000, op: FCMP_SUN_D, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCMP.SUN.S cd, fj, fk
+ {mask: 0xffff8018, value: 0x0c148000, op: FCMP_SUN_S, args: instArgs{arg_cd, arg_fj, arg_fk}},
+ // FCOPYSIGN.D fd, fj, fk
+ {mask: 0xffff8000, value: 0x01130000, op: FCOPYSIGN_D, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FCOPYSIGN.S fd, fj, fk
+ {mask: 0xffff8000, value: 0x01128000, op: FCOPYSIGN_S, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FCVT.D.S fd, fj
+ {mask: 0xfffffc00, value: 0x01192400, op: FCVT_D_S, args: instArgs{arg_fd, arg_fj}},
+ // FCVT.S.D fd, fj
+ {mask: 0xfffffc00, value: 0x01191800, op: FCVT_S_D, args: instArgs{arg_fd, arg_fj}},
+ // FDIV.D fd, fj, fk
+ {mask: 0xffff8000, value: 0x01070000, op: FDIV_D, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FDIV.S fd, fj, fk
+ {mask: 0xffff8000, value: 0x01068000, op: FDIV_S, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FFINT.D.L fd, fj
+ {mask: 0xfffffc00, value: 0x011d2800, op: FFINT_D_L, args: instArgs{arg_fd, arg_fj}},
+ // FFINT.D.W fd, fj
+ {mask: 0xfffffc00, value: 0x011d2000, op: FFINT_D_W, args: instArgs{arg_fd, arg_fj}},
+ // FFINT.S.L fd, fj
+ {mask: 0xfffffc00, value: 0x011d1800, op: FFINT_S_L, args: instArgs{arg_fd, arg_fj}},
+ // FFINT.S.W fd, fj
+ {mask: 0xfffffc00, value: 0x011d1000, op: FFINT_S_W, args: instArgs{arg_fd, arg_fj}},
+ // FLDGT.D fd, rj, rk
+ {mask: 0xffff8000, value: 0x38748000, op: FLDGT_D, args: instArgs{arg_fd, arg_rj, arg_rk}},
+ // FLDGT.S fd, rj, rk
+ {mask: 0xffff8000, value: 0x38740000, op: FLDGT_S, args: instArgs{arg_fd, arg_rj, arg_rk}},
+ // FLDLE.D fd, rj, rk
+ {mask: 0xffff8000, value: 0x38758000, op: FLDLE_D, args: instArgs{arg_fd, arg_rj, arg_rk}},
+ // FLDLE.S fd, rj, rk
+ {mask: 0xffff8000, value: 0x38750000, op: FLDLE_S, args: instArgs{arg_fd, arg_rj, arg_rk}},
+ // FLDX.D fd, rj, rk
+ {mask: 0xffff8000, value: 0x38340000, op: FLDX_D, args: instArgs{arg_fd, arg_rj, arg_rk}},
+ // FLDX.S fd, rj, rk
+ {mask: 0xffff8000, value: 0x38300000, op: FLDX_S, args: instArgs{arg_fd, arg_rj, arg_rk}},
+ // FLD.D fd, rj, si12
+ {mask: 0xffc00000, value: 0x2b800000, op: FLD_D, args: instArgs{arg_fd, arg_rj, arg_si12_21_10}},
+ // FLD.S fd, rj, si12
+ {mask: 0xffc00000, value: 0x2b000000, op: FLD_S, args: instArgs{arg_fd, arg_rj, arg_si12_21_10}},
+ // FLOGB.D fd, fj
+ {mask: 0xfffffc00, value: 0x01142800, op: FLOGB_D, args: instArgs{arg_fd, arg_fj}},
+ // FLOGB.S fd, fj
+ {mask: 0xfffffc00, value: 0x01142400, op: FLOGB_S, args: instArgs{arg_fd, arg_fj}},
+ // FMADD.D fd, fj, fk, fa
+ {mask: 0xfff00000, value: 0x08200000, op: FMADD_D, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}},
+ // FMADD.S fd, fj, fk, fa
+ {mask: 0xfff00000, value: 0x08100000, op: FMADD_S, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}},
+ // FMAXA.D fd, fj, fk
+ {mask: 0xffff8000, value: 0x010d0000, op: FMAXA_D, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FMAXA.S fd, fj, fk
+ {mask: 0xffff8000, value: 0x010c8000, op: FMAXA_S, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FMAX.D fd, fj, fk
+ {mask: 0xffff8000, value: 0x01090000, op: FMAX_D, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FMAX.S fd, fj, fk
+ {mask: 0xffff8000, value: 0x01088000, op: FMAX_S, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FMINA.D fd, fj, fk
+ {mask: 0xffff8000, value: 0x010f0000, op: FMINA_D, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FMINA.S fd, fj, fk
+ {mask: 0xffff8000, value: 0x010e8000, op: FMINA_S, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FMIN.D fd, fj, fk
+ {mask: 0xffff8000, value: 0x010b0000, op: FMIN_D, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FMIN.S fd, fj, fk
+ {mask: 0xffff8000, value: 0x010a8000, op: FMIN_S, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FMOV.D fd, fj
+ {mask: 0xfffffc00, value: 0x01149800, op: FMOV_D, args: instArgs{arg_fd, arg_fj}},
+ // FMOV.S fd, fj
+ {mask: 0xfffffc00, value: 0x01149400, op: FMOV_S, args: instArgs{arg_fd, arg_fj}},
+ // FMSUB.D fd, fj, fk, fa
+ {mask: 0xfff00000, value: 0x08600000, op: FMSUB_D, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}},
+ // FMSUB.S fd, fj, fk, fa
+ {mask: 0xfff00000, value: 0x08500000, op: FMSUB_S, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}},
+ // FMUL.D fd, fj, fk
+ {mask: 0xffff8000, value: 0x01050000, op: FMUL_D, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FMUL.S fd, fj, fk
+ {mask: 0xffff8000, value: 0x01048000, op: FMUL_S, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FNEG.D fd, fj
+ {mask: 0xfffffc00, value: 0x01141800, op: FNEG_D, args: instArgs{arg_fd, arg_fj}},
+ // FNEG.S fd, fj
+ {mask: 0xfffffc00, value: 0x01141400, op: FNEG_S, args: instArgs{arg_fd, arg_fj}},
+ // FNMADD.D fd, fj, fk, fa
+ {mask: 0xfff00000, value: 0x08a00000, op: FNMADD_D, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}},
+ // FNMADD.S fd, fj, fk, fa
+ {mask: 0xfff00000, value: 0x08900000, op: FNMADD_S, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}},
+ // FNMSUB.D fd, fj, fk, fa
+ {mask: 0xfff00000, value: 0x08e00000, op: FNMSUB_D, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}},
+ // FNMSUB.S fd, fj, fk, fa
+ {mask: 0xfff00000, value: 0x08d00000, op: FNMSUB_S, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}},
+ // FRECIPE.D fd, fj
+ {mask: 0xfffffc00, value: 0x01147800, op: FRECIPE_D, args: instArgs{arg_fd, arg_fj}},
+ // FRECIPE.S fd, fj
+ {mask: 0xfffffc00, value: 0x01147400, op: FRECIPE_S, args: instArgs{arg_fd, arg_fj}},
+ // FRECIP.D fd, fj
+ {mask: 0xfffffc00, value: 0x01145800, op: FRECIP_D, args: instArgs{arg_fd, arg_fj}},
+ // FRECIP.S fd, fj
+ {mask: 0xfffffc00, value: 0x01145400, op: FRECIP_S, args: instArgs{arg_fd, arg_fj}},
+ // FRINT.D fd, fj
+ {mask: 0xfffffc00, value: 0x011e4800, op: FRINT_D, args: instArgs{arg_fd, arg_fj}},
+ // FRINT.S fd, fj
+ {mask: 0xfffffc00, value: 0x011e4400, op: FRINT_S, args: instArgs{arg_fd, arg_fj}},
+ // FRSQRTE.D fd, fj
+ {mask: 0xfffffc00, value: 0x01148800, op: FRSQRTE_D, args: instArgs{arg_fd, arg_fj}},
+ // FRSQRTE.S fd, fj
+ {mask: 0xfffffc00, value: 0x01148400, op: FRSQRTE_S, args: instArgs{arg_fd, arg_fj}},
+ // FRSQRT.D fd, fj
+ {mask: 0xfffffc00, value: 0x01146800, op: FRSQRT_D, args: instArgs{arg_fd, arg_fj}},
+ // FRSQRT.S fd, fj
+ {mask: 0xfffffc00, value: 0x01146400, op: FRSQRT_S, args: instArgs{arg_fd, arg_fj}},
+ // FSCALEB.D fd, fj, fk
+ {mask: 0xffff8000, value: 0x01110000, op: FSCALEB_D, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FSCALEB.S fd, fj, fk
+ {mask: 0xffff8000, value: 0x01108000, op: FSCALEB_S, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FSEL fd, fj, fk, ca
+ {mask: 0xfffc0000, value: 0x0d000000, op: FSEL, args: instArgs{arg_fd, arg_fj, arg_fk, arg_ca}},
+ // FSQRT.D fd, fj
+ {mask: 0xfffffc00, value: 0x01144800, op: FSQRT_D, args: instArgs{arg_fd, arg_fj}},
+ // FSQRT.S fd, fj
+ {mask: 0xfffffc00, value: 0x01144400, op: FSQRT_S, args: instArgs{arg_fd, arg_fj}},
+ // FSTGT.D fd, rj, rk
+ {mask: 0xffff8000, value: 0x38768000, op: FSTGT_D, args: instArgs{arg_fd, arg_rj, arg_rk}},
+ // FSTGT.S fd, rj, rk
+ {mask: 0xffff8000, value: 0x38760000, op: FSTGT_S, args: instArgs{arg_fd, arg_rj, arg_rk}},
+ // FSTLE.D fd, rj, rk
+ {mask: 0xffff8000, value: 0x38778000, op: FSTLE_D, args: instArgs{arg_fd, arg_rj, arg_rk}},
+ // FSTLE.S fd, rj, rk
+ {mask: 0xffff8000, value: 0x38770000, op: FSTLE_S, args: instArgs{arg_fd, arg_rj, arg_rk}},
+ // FSTX.D fd, rj, rk
+ {mask: 0xffff8000, value: 0x383c0000, op: FSTX_D, args: instArgs{arg_fd, arg_rj, arg_rk}},
+ // FSTX.S fd, rj, rk
+ {mask: 0xffff8000, value: 0x38380000, op: FSTX_S, args: instArgs{arg_fd, arg_rj, arg_rk}},
+ // FST.D fd, rj, si12
+ {mask: 0xffc00000, value: 0x2bc00000, op: FST_D, args: instArgs{arg_fd, arg_rj, arg_si12_21_10}},
+ // FST.S fd, rj, si12
+ {mask: 0xffc00000, value: 0x2b400000, op: FST_S, args: instArgs{arg_fd, arg_rj, arg_si12_21_10}},
+ // FSUB.D fd, fj, fk
+ {mask: 0xffff8000, value: 0x01030000, op: FSUB_D, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FSUB.S fd, fj, fk
+ {mask: 0xffff8000, value: 0x01028000, op: FSUB_S, args: instArgs{arg_fd, arg_fj, arg_fk}},
+ // FTINTRM.L.D fd, fj
+ {mask: 0xfffffc00, value: 0x011a2800, op: FTINTRM_L_D, args: instArgs{arg_fd, arg_fj}},
+ // FTINTRM.L.S fd, fj
+ {mask: 0xfffffc00, value: 0x011a2400, op: FTINTRM_L_S, args: instArgs{arg_fd, arg_fj}},
+ // FTINTRM.W.D fd, fj
+ {mask: 0xfffffc00, value: 0x011a0800, op: FTINTRM_W_D, args: instArgs{arg_fd, arg_fj}},
+ // FTINTRM.W.S fd, fj
+ {mask: 0xfffffc00, value: 0x011a0400, op: FTINTRM_W_S, args: instArgs{arg_fd, arg_fj}},
+ // FTINTRNE.L.D fd, fj
+ {mask: 0xfffffc00, value: 0x011ae800, op: FTINTRNE_L_D, args: instArgs{arg_fd, arg_fj}},
+ // FTINTRNE.L.S fd, fj
+ {mask: 0xfffffc00, value: 0x011ae400, op: FTINTRNE_L_S, args: instArgs{arg_fd, arg_fj}},
+ // FTINTRNE.W.D fd, fj
+ {mask: 0xfffffc00, value: 0x011ac800, op: FTINTRNE_W_D, args: instArgs{arg_fd, arg_fj}},
+ // FTINTRNE.W.S fd, fj
+ {mask: 0xfffffc00, value: 0x011ac400, op: FTINTRNE_W_S, args: instArgs{arg_fd, arg_fj}},
+ // FTINTRP.L.D fd, fj
+ {mask: 0xfffffc00, value: 0x011a6800, op: FTINTRP_L_D, args: instArgs{arg_fd, arg_fj}},
+ // FTINTRP.L.S fd, fj
+ {mask: 0xfffffc00, value: 0x011a6400, op: FTINTRP_L_S, args: instArgs{arg_fd, arg_fj}},
+ // FTINTRP.W.D fd, fj
+ {mask: 0xfffffc00, value: 0x011a4800, op: FTINTRP_W_D, args: instArgs{arg_fd, arg_fj}},
+ // FTINTRP.W.S fd, fj
+ {mask: 0xfffffc00, value: 0x011a4400, op: FTINTRP_W_S, args: instArgs{arg_fd, arg_fj}},
+ // FTINTRZ.L.D fd, fj
+ {mask: 0xfffffc00, value: 0x011aa800, op: FTINTRZ_L_D, args: instArgs{arg_fd, arg_fj}},
+ // FTINTRZ.L.S fd, fj
+ {mask: 0xfffffc00, value: 0x011aa400, op: FTINTRZ_L_S, args: instArgs{arg_fd, arg_fj}},
+ // FTINTRZ.W.D fd, fj
+ {mask: 0xfffffc00, value: 0x011a8800, op: FTINTRZ_W_D, args: instArgs{arg_fd, arg_fj}},
+ // FTINTRZ.W.S fd, fj
+ {mask: 0xfffffc00, value: 0x011a8400, op: FTINTRZ_W_S, args: instArgs{arg_fd, arg_fj}},
+ // FTINT.L.D fd, fj
+ {mask: 0xfffffc00, value: 0x011b2800, op: FTINT_L_D, args: instArgs{arg_fd, arg_fj}},
+ // FTINT.L.S fd, fj
+ {mask: 0xfffffc00, value: 0x011b2400, op: FTINT_L_S, args: instArgs{arg_fd, arg_fj}},
+ // FTINT.W.D fd, fj
+ {mask: 0xfffffc00, value: 0x011b0800, op: FTINT_W_D, args: instArgs{arg_fd, arg_fj}},
+ // FTINT.W.S fd, fj
+ {mask: 0xfffffc00, value: 0x011b0400, op: FTINT_W_S, args: instArgs{arg_fd, arg_fj}},
+ // IBAR hint
+ {mask: 0xffff8000, value: 0x38728000, op: IBAR, args: instArgs{arg_hint_14_0}},
+ // IDLE level
+ {mask: 0xffff8000, value: 0x06488000, op: IDLE, args: instArgs{arg_level_14_0}},
+ // INVTLB op, rj, rk
+ {mask: 0xffff8000, value: 0x06498000, op: INVTLB, args: instArgs{arg_op_4_0, arg_rj, arg_rk}},
+ // IOCSRRD.B rd, rj
+ {mask: 0xfffffc00, value: 0x06480000, op: IOCSRRD_B, args: instArgs{arg_rd, arg_rj}},
+ // IOCSRRD.D rd, rj
+ {mask: 0xfffffc00, value: 0x06480c00, op: IOCSRRD_D, args: instArgs{arg_rd, arg_rj}},
+ // IOCSRRD.H rd, rj
+ {mask: 0xfffffc00, value: 0x06480400, op: IOCSRRD_H, args: instArgs{arg_rd, arg_rj}},
+ // IOCSRRD.W rd, rj
+ {mask: 0xfffffc00, value: 0x06480800, op: IOCSRRD_W, args: instArgs{arg_rd, arg_rj}},
+ // IOCSRWR.B rd, rj
+ {mask: 0xfffffc00, value: 0x06481000, op: IOCSRWR_B, args: instArgs{arg_rd, arg_rj}},
+ // IOCSRWR.D rd, rj
+ {mask: 0xfffffc00, value: 0x06481c00, op: IOCSRWR_D, args: instArgs{arg_rd, arg_rj}},
+ // IOCSRWR.H rd, rj
+ {mask: 0xfffffc00, value: 0x06481400, op: IOCSRWR_H, args: instArgs{arg_rd, arg_rj}},
+ // IOCSRWR.W rd, rj
+ {mask: 0xfffffc00, value: 0x06481800, op: IOCSRWR_W, args: instArgs{arg_rd, arg_rj}},
+ // JIRL rd, rj, offs
+ {mask: 0xfc000000, value: 0x4c000000, op: JIRL, args: instArgs{arg_rd, arg_rj, arg_offset_15_0}},
+ // LDDIR rd, rj, level
+ {mask: 0xfffc0000, value: 0x06400000, op: LDDIR, args: instArgs{arg_rd, arg_rj, arg_level_17_10}},
+ // LDGT.B rd, rj, rk
+ {mask: 0xffff8000, value: 0x38780000, op: LDGT_B, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // LDGT.D rd, rj, rk
+ {mask: 0xffff8000, value: 0x38798000, op: LDGT_D, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // LDGT.H rd, rj, rk
+ {mask: 0xffff8000, value: 0x38788000, op: LDGT_H, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // LDGT.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x38790000, op: LDGT_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // LDLE.B rd, rj, rk
+ {mask: 0xffff8000, value: 0x387a0000, op: LDLE_B, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // LDLE.D rd, rj, rk
+ {mask: 0xffff8000, value: 0x387b8000, op: LDLE_D, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // LDLE.H rd, rj, rk
+ {mask: 0xffff8000, value: 0x387a8000, op: LDLE_H, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // LDLE.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x387b0000, op: LDLE_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // LDPTE rj, seq
+ {mask: 0xfffc001f, value: 0x06440000, op: LDPTE, args: instArgs{arg_rj, arg_seq_17_10}},
+ // LDPTR.D rd, rj, si14
+ {mask: 0xff000000, value: 0x26000000, op: LDPTR_D, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}},
+ // LDPTR.W rd, rj, si14
+ {mask: 0xff000000, value: 0x24000000, op: LDPTR_W, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}},
+ // LDX.B rd, rj, rk
+ {mask: 0xffff8000, value: 0x38000000, op: LDX_B, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // LDX.BU rd, rj, rk
+ {mask: 0xffff8000, value: 0x38200000, op: LDX_BU, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // LDX.D rd, rj, rk
+ {mask: 0xffff8000, value: 0x380c0000, op: LDX_D, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // LDX.H rd, rj, rk
+ {mask: 0xffff8000, value: 0x38040000, op: LDX_H, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // LDX.HU rd, rj, rk
+ {mask: 0xffff8000, value: 0x38240000, op: LDX_HU, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // LDX.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x38080000, op: LDX_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // LDX.WU rd, rj, rk
+ {mask: 0xffff8000, value: 0x38280000, op: LDX_WU, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // LD.B rd, rj, si12
+ {mask: 0xffc00000, value: 0x28000000, op: LD_B, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}},
+ // LD.BU rd, rj, si12
+ {mask: 0xffc00000, value: 0x2a000000, op: LD_BU, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}},
+ // LD.D rd, rj, si12
+ {mask: 0xffc00000, value: 0x28c00000, op: LD_D, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}},
+ // LD.H rd, rj, si12
+ {mask: 0xffc00000, value: 0x28400000, op: LD_H, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}},
+ // LD.HU rd, rj, si12
+ {mask: 0xffc00000, value: 0x2a400000, op: LD_HU, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}},
+ // LD.W rd, rj, si12
+ {mask: 0xffc00000, value: 0x28800000, op: LD_W, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}},
+ // LD.WU rd, rj, si12
+ {mask: 0xffc00000, value: 0x2a800000, op: LD_WU, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}},
+ // LLACQ.D rd, rj
+ {mask: 0xfffffc00, value: 0x38578800, op: LLACQ_D, args: instArgs{arg_rd, arg_rj}},
+ // LLACQ.W rd, rj
+ {mask: 0xfffffc00, value: 0x38578000, op: LLACQ_W, args: instArgs{arg_rd, arg_rj}},
+ // LL.D rd, rj, si14
+ {mask: 0xff000000, value: 0x22000000, op: LL_D, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}},
+ // LL.W rd, rj, si14
+ {mask: 0xff000000, value: 0x20000000, op: LL_W, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}},
+ // LU12I.W rd, si20
+ {mask: 0xfe000000, value: 0x14000000, op: LU12I_W, args: instArgs{arg_rd, arg_si20_24_5}},
+ // LU32I.D rd, si20
+ {mask: 0xfe000000, value: 0x16000000, op: LU32I_D, args: instArgs{arg_rd, arg_si20_24_5}},
+ // LU52I.D rd, rj, si12
+ {mask: 0xffc00000, value: 0x03000000, op: LU52I_D, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}},
+ // MASKEQZ rd, rj, rk
+ {mask: 0xffff8000, value: 0x00130000, op: MASKEQZ, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // MASKNEZ rd, rj, rk
+ {mask: 0xffff8000, value: 0x00138000, op: MASKNEZ, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // MOD.D rd, rj, rk
+ {mask: 0xffff8000, value: 0x00228000, op: MOD_D, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // MOD.DU rd, rj, rk
+ {mask: 0xffff8000, value: 0x00238000, op: MOD_DU, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // MOD.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x00208000, op: MOD_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // MOD.WU rd, rj, rk
+ {mask: 0xffff8000, value: 0x00218000, op: MOD_WU, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // MOVCF2FR fd, cj
+ {mask: 0xffffff00, value: 0x0114d400, op: MOVCF2FR, args: instArgs{arg_fd, arg_cj}},
+ // MOVCF2GR rd, cj
+ {mask: 0xffffff00, value: 0x0114dc00, op: MOVCF2GR, args: instArgs{arg_rd, arg_cj}},
+ // MOVFCSR2GR rd, fcsr
+ {mask: 0xfffffc00, value: 0x0114c800, op: MOVFCSR2GR, args: instArgs{arg_rd, arg_fcsr_9_5}},
+ // MOVFR2CF cd, fj
+ {mask: 0xfffffc18, value: 0x0114d000, op: MOVFR2CF, args: instArgs{arg_cd, arg_fj}},
+ // MOVFR2GR.D rd, fj
+ {mask: 0xfffffc00, value: 0x0114b800, op: MOVFR2GR_D, args: instArgs{arg_rd, arg_fj}},
+ // MOVFR2GR.S rd, fj
+ {mask: 0xfffffc00, value: 0x0114b400, op: MOVFR2GR_S, args: instArgs{arg_rd, arg_fj}},
+ // MOVFRH2GR.S rd, fj
+ {mask: 0xfffffc00, value: 0x0114bc00, op: MOVFRH2GR_S, args: instArgs{arg_rd, arg_fj}},
+ // MOVGR2CF cd, rj
+ {mask: 0xfffffc18, value: 0x0114d800, op: MOVGR2CF, args: instArgs{arg_cd, arg_rj}},
+ // MOVGR2FCSR fcsr, rj
+ {mask: 0xfffffc00, value: 0x0114c000, op: MOVGR2FCSR, args: instArgs{arg_fcsr_4_0, arg_rj}},
+ // MOVGR2FRH.W fd, rj
+ {mask: 0xfffffc00, value: 0x0114ac00, op: MOVGR2FRH_W, args: instArgs{arg_fd, arg_rj}},
+ // MOVGR2FR.D fd, rj
+ {mask: 0xfffffc00, value: 0x0114a800, op: MOVGR2FR_D, args: instArgs{arg_fd, arg_rj}},
+ // MOVGR2FR.W fd, rj
+ {mask: 0xfffffc00, value: 0x0114a400, op: MOVGR2FR_W, args: instArgs{arg_fd, arg_rj}},
+ // MULH.D rd, rj, rk
+ {mask: 0xffff8000, value: 0x001e0000, op: MULH_D, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // MULH.DU rd, rj, rk
+ {mask: 0xffff8000, value: 0x001e8000, op: MULH_DU, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // MULH.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x001c8000, op: MULH_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // MULH.WU rd, rj, rk
+ {mask: 0xffff8000, value: 0x001d0000, op: MULH_WU, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // MULW.D.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x001f0000, op: MULW_D_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // MULW.D.WU rd, rj, rk
+ {mask: 0xffff8000, value: 0x001f8000, op: MULW_D_WU, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // MUL.D rd, rj, rk
+ {mask: 0xffff8000, value: 0x001d8000, op: MUL_D, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // MUL.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x001c0000, op: MUL_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // NOR rd, rj, rk
+ {mask: 0xffff8000, value: 0x00140000, op: NOR, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // OR rd, rj, rk
+ {mask: 0xffff8000, value: 0x00150000, op: OR, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // ORI rd, rj, ui12
+ {mask: 0xffc00000, value: 0x03800000, op: ORI, args: instArgs{arg_rd, arg_rj, arg_ui12_21_10}},
+ // ORN rd, rj, rk
+ {mask: 0xffff8000, value: 0x00160000, op: ORN, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // PCADDI rd, si20
+ {mask: 0xfe000000, value: 0x18000000, op: PCADDI, args: instArgs{arg_rd, arg_si20_24_5}},
+ // PCADDU12I rd, si20
+ {mask: 0xfe000000, value: 0x1c000000, op: PCADDU12I, args: instArgs{arg_rd, arg_si20_24_5}},
+ // PCADDU18I rd, si20
+ {mask: 0xfe000000, value: 0x1e000000, op: PCADDU18I, args: instArgs{arg_rd, arg_si20_24_5}},
+ // PCALAU12I rd, si20
+ {mask: 0xfe000000, value: 0x1a000000, op: PCALAU12I, args: instArgs{arg_rd, arg_si20_24_5}},
+ // PRELD hint, rj, si12
+ {mask: 0xffc00000, value: 0x2ac00000, op: PRELD, args: instArgs{arg_hint_4_0, arg_rj, arg_si12_21_10}},
+ // PRELDX hint, rj, rk
+ {mask: 0xffff8000, value: 0x382c0000, op: PRELDX, args: instArgs{arg_hint_4_0, arg_rj, arg_rk}},
+ // RDTIMEH.W rd, rj
+ {mask: 0xfffffc00, value: 0x00006400, op: RDTIMEH_W, args: instArgs{arg_rd, arg_rj}},
+ // RDTIMEL.W rd, rj
+ {mask: 0xfffffc00, value: 0x00006000, op: RDTIMEL_W, args: instArgs{arg_rd, arg_rj}},
+ // RDTIME.D rd, rj
+ {mask: 0xfffffc00, value: 0x00006800, op: RDTIME_D, args: instArgs{arg_rd, arg_rj}},
+ // REVB.2H rd, rj
+ {mask: 0xfffffc00, value: 0x00003000, op: REVB_2H, args: instArgs{arg_rd, arg_rj}},
+ // REVB.2W rd, rj
+ {mask: 0xfffffc00, value: 0x00003800, op: REVB_2W, args: instArgs{arg_rd, arg_rj}},
+ // REVB.4H rd, rj
+ {mask: 0xfffffc00, value: 0x00003400, op: REVB_4H, args: instArgs{arg_rd, arg_rj}},
+ // REVB.D rd, rj
+ {mask: 0xfffffc00, value: 0x00003c00, op: REVB_D, args: instArgs{arg_rd, arg_rj}},
+ // REVH.2W rd, rj
+ {mask: 0xfffffc00, value: 0x00004000, op: REVH_2W, args: instArgs{arg_rd, arg_rj}},
+ // REVH.D rd, rj
+ {mask: 0xfffffc00, value: 0x00004400, op: REVH_D, args: instArgs{arg_rd, arg_rj}},
+ // ROTRI.D rd, rj, ui6
+ {mask: 0xffff0000, value: 0x004d0000, op: ROTRI_D, args: instArgs{arg_rd, arg_rj, arg_ui6_15_10}},
+ // ROTRI.W rd, rj, ui5
+ {mask: 0xffff8000, value: 0x004c8000, op: ROTRI_W, args: instArgs{arg_rd, arg_rj, arg_ui5_14_10}},
+ // ROTR.D rd, rj, rk
+ {mask: 0xffff8000, value: 0x001b8000, op: ROTR_D, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // ROTR.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x001b0000, op: ROTR_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // SCREL.D rd, rj
+ {mask: 0xfffffc00, value: 0x38578c00, op: SCREL_D, args: instArgs{arg_rd, arg_rj}},
+ // SCREL.W rd, rj
+ {mask: 0xfffffc00, value: 0x38578400, op: SCREL_W, args: instArgs{arg_rd, arg_rj}},
+ // SC.D rd, rj, si14
+ {mask: 0xff000000, value: 0x23000000, op: SC_D, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}},
+ // SC.Q rd, rk, rj
+ {mask: 0xffff8000, value: 0x38570000, op: SC_Q, args: instArgs{arg_rd, arg_rk, arg_rj}},
+ // SC.W rd, rj, si14
+ {mask: 0xff000000, value: 0x21000000, op: SC_W, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}},
+ // SLLI.D rd, rj, ui6
+ {mask: 0xffff0000, value: 0x00410000, op: SLLI_D, args: instArgs{arg_rd, arg_rj, arg_ui6_15_10}},
+ // SLLI.W rd, rj, ui5
+ {mask: 0xffff8000, value: 0x00408000, op: SLLI_W, args: instArgs{arg_rd, arg_rj, arg_ui5_14_10}},
+ // SLL.D rd, rj, rk
+ {mask: 0xffff8000, value: 0x00188000, op: SLL_D, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // SLL.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x00170000, op: SLL_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // SLT rd, rj, rk
+ {mask: 0xffff8000, value: 0x00120000, op: SLT, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // SLTI rd, rj, si12
+ {mask: 0xffc00000, value: 0x02000000, op: SLTI, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}},
+ // SLTU rd, rj, rk
+ {mask: 0xffff8000, value: 0x00128000, op: SLTU, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // SLTUI rd, rj, si12
+ {mask: 0xffc00000, value: 0x02400000, op: SLTUI, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}},
+ // SRAI.D rd, rj, ui6
+ {mask: 0xffff0000, value: 0x00490000, op: SRAI_D, args: instArgs{arg_rd, arg_rj, arg_ui6_15_10}},
+ // SRAI.W rd, rj, ui5
+ {mask: 0xffff8000, value: 0x00488000, op: SRAI_W, args: instArgs{arg_rd, arg_rj, arg_ui5_14_10}},
+ // SRA.D rd, rj, rk
+ {mask: 0xffff8000, value: 0x00198000, op: SRA_D, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // SRA.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x00180000, op: SRA_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // SRLI.D rd, rj, ui6
+ {mask: 0xffff0000, value: 0x00450000, op: SRLI_D, args: instArgs{arg_rd, arg_rj, arg_ui6_15_10}},
+ // SRLI.W rd, rj, ui5
+ {mask: 0xffff8000, value: 0x00448000, op: SRLI_W, args: instArgs{arg_rd, arg_rj, arg_ui5_14_10}},
+ // SRL.D rd, rj, rk
+ {mask: 0xffff8000, value: 0x00190000, op: SRL_D, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // SRL.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x00178000, op: SRL_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // STGT.B rd, rj, rk
+ {mask: 0xffff8000, value: 0x387c0000, op: STGT_B, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // STGT.D rd, rj, rk
+ {mask: 0xffff8000, value: 0x387d8000, op: STGT_D, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // STGT.H rd, rj, rk
+ {mask: 0xffff8000, value: 0x387c8000, op: STGT_H, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // STGT.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x387d0000, op: STGT_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // STLE.B rd, rj, rk
+ {mask: 0xffff8000, value: 0x387e0000, op: STLE_B, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // STLE.D rd, rj, rk
+ {mask: 0xffff8000, value: 0x387f8000, op: STLE_D, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // STLE.H rd, rj, rk
+ {mask: 0xffff8000, value: 0x387e8000, op: STLE_H, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // STLE.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x387f0000, op: STLE_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // STPTR.D rd, rj, si14
+ {mask: 0xff000000, value: 0x27000000, op: STPTR_D, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}},
+ // STPTR.W rd, rj, si14
+ {mask: 0xff000000, value: 0x25000000, op: STPTR_W, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}},
+ // STX.B rd, rj, rk
+ {mask: 0xffff8000, value: 0x38100000, op: STX_B, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // STX.D rd, rj, rk
+ {mask: 0xffff8000, value: 0x381c0000, op: STX_D, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // STX.H rd, rj, rk
+ {mask: 0xffff8000, value: 0x38140000, op: STX_H, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // STX.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x38180000, op: STX_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // ST.B rd, rj, si12
+ {mask: 0xffc00000, value: 0x29000000, op: ST_B, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}},
+ // ST.D rd, rj, si12
+ {mask: 0xffc00000, value: 0x29c00000, op: ST_D, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}},
+ // ST.H rd, rj, si12
+ {mask: 0xffc00000, value: 0x29400000, op: ST_H, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}},
+ // ST.W rd, rj, si12
+ {mask: 0xffc00000, value: 0x29800000, op: ST_W, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}},
+ // SUB.D rd, rj, rk
+ {mask: 0xffff8000, value: 0x00118000, op: SUB_D, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // SUB.W rd, rj, rk
+ {mask: 0xffff8000, value: 0x00110000, op: SUB_W, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // SYSCALL code
+ {mask: 0xffff8000, value: 0x002b0000, op: SYSCALL, args: instArgs{arg_code_14_0}},
+ // TLBCLR
+ {mask: 0xffffffff, value: 0x06482000, op: TLBCLR, args: instArgs{}},
+ // TLBFILL
+ {mask: 0xffffffff, value: 0x06483400, op: TLBFILL, args: instArgs{}},
+ // TLBFLUSH
+ {mask: 0xffffffff, value: 0x06482400, op: TLBFLUSH, args: instArgs{}},
+ // TLBRD
+ {mask: 0xffffffff, value: 0x06482c00, op: TLBRD, args: instArgs{}},
+ // TLBSRCH
+ {mask: 0xffffffff, value: 0x06482800, op: TLBSRCH, args: instArgs{}},
+ // TLBWR
+ {mask: 0xffffffff, value: 0x06483000, op: TLBWR, args: instArgs{}},
+ // XOR rd, rj, rk
+ {mask: 0xffff8000, value: 0x00158000, op: XOR, args: instArgs{arg_rd, arg_rj, arg_rk}},
+ // XORI rd, rj, ui12
+ {mask: 0xffc00000, value: 0x03c00000, op: XORI, args: instArgs{arg_rd, arg_rj, arg_ui12_21_10}},
+}
diff --git a/loong64/loong64asm/testdata/gnucases.txt b/loong64/loong64asm/testdata/gnucases.txt
new file mode 100644
index 0000000..2cfd5ea
--- /dev/null
+++ b/loong64/loong64asm/testdata/gnucases.txt
@@ -0,0 +1,415 @@
+ac391000| add.w $t0, $t1, $t2
+acb91000| add.d $t0, $t1, $t2
+ac41c002| addi.d $t0, $t1, 16
+ac01e002| addi.d $t0, $t1, -2048
+acfdff02| addi.d $t0, $t1, -1
+ac05e002| addi.d $t0, $t1, -2047
+acf9ff02| addi.d $t0, $t1, -2
+acfdff02| addi.d $t0, $t1, -1
+ac418002| addi.w $t0, $t1, 16
+ac410010| addu16i.d $t0, $t1, 16
+a4fcff13| addu16i.d $a0, $a1, -1
+acb92c00| alsl.d $t0, $t1, $t2, 0x2
+acb90400| alsl.w $t0, $t1, $t2, 0x2
+acb90600| alsl.wu $t0, $t1, $t2, 0x2
+ccb56138| amadd.d $t0, $t1, $t2
+cc356138| amadd.w $t0, $t1, $t2
+ccb56a38| amadd_db.d $t0, $t1, $t2
+cc356a38| amadd_db.w $t0, $t1, $t2
+ccb56238| amand.d $t0, $t1, $t2
+cc356238| amand.w $t0, $t1, $t2
+ccb56b38| amand_db.d $t0, $t1, $t2
+cc356b38| amand_db.w $t0, $t1, $t2
+ccb56538| ammax.d $t0, $t1, $t2
+ccb56738| ammax.du $t0, $t1, $t2
+cc356538| ammax.w $t0, $t1, $t2
+cc356738| ammax.wu $t0, $t1, $t2
+ccb56e38| ammax_db.d $t0, $t1, $t2
+ccb57038| ammax_db.du $t0, $t1, $t2
+cc356e38| ammax_db.w $t0, $t1, $t2
+cc357038| ammax_db.wu $t0, $t1, $t2
+ccb56638| ammin.d $t0, $t1, $t2
+ccb56838| ammin.du $t0, $t1, $t2
+cc356638| ammin.w $t0, $t1, $t2
+cc356838| ammin.wu $t0, $t1, $t2
+ccb56f38| ammin_db.d $t0, $t1, $t2
+ccb57138| ammin_db.du $t0, $t1, $t2
+cc356f38| ammin_db.w $t0, $t1, $t2
+cc357138| ammin_db.wu $t0, $t1, $t2
+ccb56338| amor.d $t0, $t1, $t2
+cc356338| amor.w $t0, $t1, $t2
+ccb56c38| amor_db.d $t0, $t1, $t2
+cc356c38| amor_db.w $t0, $t1, $t2
+ccb56038| amswap.d $t0, $t1, $t2
+cc356038| amswap.w $t0, $t1, $t2
+ccb56938| amswap_db.d $t0, $t1, $t2
+cc356938| amswap_db.w $t0, $t1, $t2
+ccb56438| amxor.d $t0, $t1, $t2
+cc356438| amxor.w $t0, $t1, $t2
+ccb56d38| amxor_db.d $t0, $t1, $t2
+cc356d38| amxor_db.w $t0, $t1, $t2
+acb91400| and $t0, $t1, $t2
+ac414003| andi $t0, $t1, 0x10
+acb91600| andn $t0, $t1, $t2
+00004003| nop
+a0b90100| asrtgt.d $t1, $t2
+a0390100| asrtle.d $t1, $t2
+00100050| b 16
+20100048| bceqz $fcc1, 16
+20110048| bcnez $fcc1, 16
+1ff1ff4b| bcnez $fcc0, -16
+8d110058| beq $t0, $t1, 16
+a0110040| beqz $t1, 16
+9ff1ff43| beqz $t0, -16
+8d110064| bge $t0, $t1, 16
+8d11006c| bgeu $t0, $t1, 16
+ac490000| bitrev.4b $t0, $t1
+ac4d0000| bitrev.8b $t0, $t1
+ac550000| bitrev.d $t0, $t1
+ac510000| bitrev.w $t0, $t1
+00100054| bl 16
+8d110060| blt $t0, $t1, 16
+8d110068| bltu $t0, $t1, 16
+8d11005c| bne $t0, $t1, 16
+a0110044| bnez $t1, 16
+00002a00| break 0x0
+ac158a00| bstrins.d $t0, $t1, 0xa, 0x5
+ac156a00| bstrins.w $t0, $t1, 0xa, 0x5
+ac15ca00| bstrpick.d $t0, $t1, 0xa, 0x5
+ac956a00| bstrpick.w $t0, $t1, 0xa, 0x5
+ac390d00| bytepick.d $t0, $t1, $t2, 0x2
+ac390900| bytepick.w $t0, $t1, $t2, 0x2
+84010406| cacop 0x4, $t0, 256
+ac210000| clo.d $t0, $t1
+ac110000| clo.w $t0, $t1
+ac250000| clz.d $t0, $t1
+ac150000| clz.w $t0, $t1
+ac6d0000| cpucfg $t0, $t1
+ac392400| crc.w.b.w $t0, $t1, $t2
+acb92500| crc.w.d.w $t0, $t1, $t2
+acb92400| crc.w.h.w $t0, $t1, $t2
+ac392500| crc.w.w.w $t0, $t1, $t2
+ac392600| crcc.w.b.w $t0, $t1, $t2
+acb92700| crcc.w.d.w $t0, $t1, $t2
+acb92600| crcc.w.h.w $t0, $t1, $t2
+ac392700| crcc.w.w.w $t0, $t1, $t2
+0c040004| csrrd $t0, 0x1
+2c040004| csrwr $t0, 0x1
+ac050004| csrxchg $t0, $t1, 0x1
+ac290000| cto.d $t0, $t1
+ac190000| cto.w $t0, $t1
+ac2d0000| ctz.d $t0, $t1
+ac1d0000| ctz.w $t0, $t1
+00007238| dbar 0x0
+10802a00| dbcl 0x10
+ac392200| div.d $t0, $t1, $t2
+ac392300| div.du $t0, $t1, $t2
+ac392000| div.w $t0, $t1, $t2
+ac392100| div.wu $t0, $t1, $t2
+00384806| ertn
+ac5d0000| ext.w.b $t0, $t1
+ac590000| ext.w.h $t0, $t1
+28091401| fabs.d $ft0, $ft1
+28051401| fabs.s $ft0, $ft1
+28250101| fadd.d $ft0, $ft1, $ft1
+28a50001| fadd.s $ft0, $ft1, $ft1
+28391401| fclass.d $ft0, $ft1
+28351401| fclass.s $ft0, $ft1
+2029200c| fcmp.caf.d $fcc0, $ft1, $ft2
+2029100c| fcmp.caf.s $fcc0, $ft1, $ft2
+2029220c| fcmp.ceq.d $fcc0, $ft1, $ft2
+2029120c| fcmp.ceq.s $fcc0, $ft1, $ft2
+2029230c| fcmp.cle.d $fcc0, $ft1, $ft2
+2029130c| fcmp.cle.s $fcc0, $ft1, $ft2
+2029210c| fcmp.clt.d $fcc0, $ft1, $ft2
+2029110c| fcmp.clt.s $fcc0, $ft1, $ft2
+2029280c| fcmp.cne.d $fcc0, $ft1, $ft2
+2029180c| fcmp.cne.s $fcc0, $ft1, $ft2
+20292a0c| fcmp.cor.d $fcc0, $ft1, $ft2
+20291a0c| fcmp.cor.s $fcc0, $ft1, $ft2
+2029260c| fcmp.cueq.d $fcc0, $ft1, $ft2
+2029160c| fcmp.cueq.s $fcc0, $ft1, $ft2
+2029270c| fcmp.cule.d $fcc0, $ft1, $ft2
+2029170c| fcmp.cule.s $fcc0, $ft1, $ft2
+2029250c| fcmp.cult.d $fcc0, $ft1, $ft2
+2029150c| fcmp.cult.s $fcc0, $ft1, $ft2
+20292c0c| fcmp.cune.d $fcc0, $ft1, $ft2
+20291c0c| fcmp.cune.s $fcc0, $ft1, $ft2
+2029240c| fcmp.cun.d $fcc0, $ft1, $ft2
+2029140c| fcmp.cun.s $fcc0, $ft1, $ft2
+20a9200c| fcmp.saf.d $fcc0, $ft1, $ft2
+20a9100c| fcmp.saf.s $fcc0, $ft1, $ft2
+20a9220c| fcmp.seq.d $fcc0, $ft1, $ft2
+20a9120c| fcmp.seq.s $fcc0, $ft1, $ft2
+20a9230c| fcmp.sle.d $fcc0, $ft1, $ft2
+20a9130c| fcmp.sle.s $fcc0, $ft1, $ft2
+20a9210c| fcmp.slt.d $fcc0, $ft1, $ft2
+20a9110c| fcmp.slt.s $fcc0, $ft1, $ft2
+20a9280c| fcmp.sne.d $fcc0, $ft1, $ft2
+20a9180c| fcmp.sne.s $fcc0, $ft1, $ft2
+20a92a0c| fcmp.sor.d $fcc0, $ft1, $ft2
+20a91a0c| fcmp.sor.s $fcc0, $ft1, $ft2
+20a9260c| fcmp.sueq.d $fcc0, $ft1, $ft2
+20a9160c| fcmp.sueq.s $fcc0, $ft1, $ft2
+20a9270c| fcmp.sule.d $fcc0, $ft1, $ft2
+20a9170c| fcmp.sule.s $fcc0, $ft1, $ft2
+20a9250c| fcmp.sult.d $fcc0, $ft1, $ft2
+20a9150c| fcmp.sult.s $fcc0, $ft1, $ft2
+20a92c0c| fcmp.sune.d $fcc0, $ft1, $ft2
+20a91c0c| fcmp.sune.s $fcc0, $ft1, $ft2
+20a9240c| fcmp.sun.d $fcc0, $ft1, $ft2
+20a9140c| fcmp.sun.s $fcc0, $ft1, $ft2
+28291301| fcopysign.d $ft0, $ft1, $ft2
+28a91201| fcopysign.s $ft0, $ft1, $ft2
+28251901| fcvt.d.s $ft0, $ft1
+28191901| fcvt.s.d $ft0, $ft1
+28290701| fdiv.d $ft0, $ft1, $ft2
+28a90601| fdiv.s $ft0, $ft1, $ft2
+28291d01| ffint.d.l $ft0, $ft1
+28211d01| ffint.d.w $ft0, $ft1
+28191d01| ffint.s.l $ft0, $ft1
+28111d01| ffint.s.w $ft0, $ft1
+a841802b| fld.d $ft0, $t1, 16
+a841002b| fld.s $ft0, $t1, 16
+a8b97438| fldgt.d $ft0, $t1, $t2
+a8397438| fldgt.s $ft0, $t1, $t2
+a8b97538| fldle.d $ft0, $t1, $t2
+a8397538| fldle.s $ft0, $t1, $t2
+a8393438| fldx.d $ft0, $t1, $t2
+a8393038| fldx.s $ft0, $t1, $t2
+28291401| flogb.d $ft0, $ft1
+28251401| flogb.s $ft0, $ft1
+28a92508| fmadd.d $ft0, $ft1, $ft2, $ft3
+28a91508| fmadd.s $ft0, $ft1, $ft2, $ft3
+28290901| fmax.d $ft0, $ft1, $ft2
+28a90801| fmax.s $ft0, $ft1, $ft2
+28290d01| fmaxa.d $ft0, $ft1, $ft2
+28a90c01| fmaxa.s $ft0, $ft1, $ft2
+28290b01| fmin.d $ft0, $ft1, $ft2
+28a90a01| fmin.s $ft0, $ft1, $ft2
+28290f01| fmina.d $ft0, $ft1, $ft2
+28a90e01| fmina.s $ft0, $ft1, $ft2
+48991401| fmov.d $ft0, $ft2
+48951401| fmov.s $ft0, $ft2
+28a96508| fmsub.d $ft0, $ft1, $ft2, $ft3
+28a95508| fmsub.s $ft0, $ft1, $ft2, $ft3
+28290501| fmul.d $ft0, $ft1, $ft2
+28a90401| fmul.s $ft0, $ft1, $ft2
+28191401| fneg.d $ft0, $ft1
+28151401| fneg.s $ft0, $ft1
+28a9a508| fnmadd.d $ft0, $ft1, $ft2, $ft3
+28a99508| fnmadd.s $ft0, $ft1, $ft2, $ft3
+28a9e508| fnmsub.d $ft0, $ft1, $ft2, $ft3
+28a9d508| fnmsub.s $ft0, $ft1, $ft2, $ft3
+28591401| frecip.d $ft0, $ft1
+28551401| frecip.s $ft0, $ft1
+28491e01| frint.d $ft0, $ft1
+28451e01| frint.s $ft0, $ft1
+28691401| frsqrt.d $ft0, $ft1
+28651401| frsqrt.s $ft0, $ft1
+28291101| fscaleb.d $ft0, $ft1, $ft2
+28a91001| fscaleb.s $ft0, $ft1, $ft2
+28a9000d| fsel $ft0, $ft1, $ft2, $fcc1
+28491401| fsqrt.d $ft0, $ft1
+28451401| fsqrt.s $ft0, $ft1
+a841c02b| fst.d $ft0, $t1, 16
+a841402b| fst.s $ft0, $t1, 16
+a8b97638| fstgt.d $ft0, $t1, $t2
+a8397638| fstgt.s $ft0, $t1, $t2
+a8b97738| fstle.d $ft0, $t1, $t2
+a8397738| fstle.s $ft0, $t1, $t2
+a8393c38| fstx.d $ft0, $t1, $t2
+a8393838| fstx.s $ft0, $t1, $t2
+28290301| fsub.d $ft0, $ft1, $ft2
+28a90201| fsub.s $ft0, $ft1, $ft2
+28291b01| ftint.l.d $ft0, $ft1
+28251b01| ftint.l.s $ft0, $ft1
+28091b01| ftint.w.d $ft0, $ft1
+28051b01| ftint.w.s $ft0, $ft1
+28291a01| ftintrm.l.d $ft0, $ft1
+28251a01| ftintrm.l.s $ft0, $ft1
+28091a01| ftintrm.w.d $ft0, $ft1
+28051a01| ftintrm.w.s $ft0, $ft1
+28e91a01| ftintrne.l.d $ft0, $ft1
+28e51a01| ftintrne.l.s $ft0, $ft1
+28c91a01| ftintrne.w.d $ft0, $ft1
+28c51a01| ftintrne.w.s $ft0, $ft1
+28691a01| ftintrp.l.d $ft0, $ft1
+28651a01| ftintrp.l.s $ft0, $ft1
+28491a01| ftintrp.w.d $ft0, $ft1
+28451a01| ftintrp.w.s $ft0, $ft1
+28a91a01| ftintrz.l.d $ft0, $ft1
+28a51a01| ftintrz.l.s $ft0, $ft1
+28891a01| ftintrz.w.d $ft0, $ft1
+28851a01| ftintrz.w.s $ft0, $ft1
+00807238| ibar 0x0
+10804806| idle 0x10
+ac014806| iocsrrd.b $t0, $t1
+ac054806| iocsrrd.h $t0, $t1
+ac094806| iocsrrd.w $t0, $t1
+ac0d4806| iocsrrd.d $t0, $t1
+ac114806| iocsrwr.b $t0, $t1
+ac154806| iocsrwr.h $t0, $t1
+ac194806| iocsrwr.w $t0, $t1
+ac1d4806| iocsrwr.d $t0, $t1
+82b54906| invtlb 0x2, $t0, $t1
+ac11004c| jirl $t0, $t1, 16
+ac410028| ld.b $t0, $t1, 16
+ac41002a| ld.bu $t0, $t1, 16
+ac41c028| ld.d $t0, $t1, 16
+ac414028| ld.h $t0, $t1, 16
+ac41402a| ld.hu $t0, $t1, 16
+ac418028| ld.w $t0, $t1, 16
+ac41802a| ld.wu $t0, $t1, 16
+ac414006| lddir $t0, $t1, 0x10
+ac397838| ldgt.b $t0, $t1, $t2
+acb97938| ldgt.d $t0, $t1, $t2
+acb97838| ldgt.h $t0, $t1, $t2
+ac397938| ldgt.w $t0, $t1, $t2
+ac397a38| ldle.b $t0, $t1, $t2
+acb97b38| ldle.d $t0, $t1, $t2
+acb97a38| ldle.h $t0, $t1, $t2
+ac397b38| ldle.w $t0, $t1, $t2
+ac110026| ldptr.d $t0, $t1, 16
+ac01e024| ldptr.w $t0, $t1, -8192
+ac05f024| ldptr.w $t0, $t1, -4092
+acfd1f24| ldptr.w $t0, $t1, 8188
+acfdff24| ldptr.w $t0, $t1, -4
+ac050024| ldptr.w $t0, $t1, 4
+ac110024| ldptr.w $t0, $t1, 16
+80094406| ldpte $t0, 0x2
+ac390038| ldx.b $t0, $t1, $t2
+ac392038| ldx.bu $t0, $t1, $t2
+ac390c38| ldx.d $t0, $t1, $t2
+ac390438| ldx.h $t0, $t1, $t2
+ac392438| ldx.hu $t0, $t1, $t2
+ac390838| ldx.w $t0, $t1, $t2
+ac392838| ldx.wu $t0, $t1, $t2
+ac110022| ll.d $t0, $t1, 16
+ac110020| ll.w $t0, $t1, 16
+0c020014| lu12i.w $t0, 16
+0c000015| lu12i.w $t0, -524288
+ecffff15| lu12i.w $t0, -1
+ecffff14| lu12i.w $t0, 524287
+0c020016| lu32i.d $t0, 16
+ac410003| lu52i.d $t0, $t1, 16
+ac391300| maskeqz $t0, $t1, $t2
+acb91300| masknez $t0, $t1, $t2
+acb92200| mod.d $t0, $t1, $t2
+acb92300| mod.du $t0, $t1, $t2
+acb92000| mod.w $t0, $t1, $t2
+acb92100| mod.wu $t0, $t1, $t2
+28d41401| movcf2fr $ft0, $fcc1
+2cdc1401| movcf2gr $t0, $fcc1
+0cc81401| movfcsr2gr $t0, $fcsr0
+20d11401| movfr2cf $fcc0, $ft1
+2cb91401| movfr2gr.d $t0, $ft1
+2cb51401| movfr2gr.s $t0, $ft1
+2cbd1401| movfrh2gr.s $t0, $ft1
+a0d91401| movgr2cf $fcc0, $t1
+80c11401| movgr2fcsr $fcsr0, $t0
+a8a91401| movgr2fr.d $ft0, $t1
+a8a51401| movgr2fr.w $ft0, $t1
+a8ad1401| movgr2frh.w $ft0, $t1
+acb91d00| mul.d $t0, $t1, $t2
+ac391c00| mul.w $t0, $t1, $t2
+ac391e00| mulh.d $t0, $t1, $t2
+acb91e00| mulh.du $t0, $t1, $t2
+acb91c00| mulh.w $t0, $t1, $t2
+ac391d00| mulh.wu $t0, $t1, $t2
+ac391f00| mulw.d.w $t0, $t1, $t2
+acb91f00| mulw.d.wu $t0, $t1, $t2
+ac391400| nor $t0, $t1, $t2
+ac391500| or $t0, $t1, $t2
+ac418003| ori $t0, $t1, 0x10
+ac391600| orn $t0, $t1, $t2
+0c020018| pcaddi $t0, 16
+0c02001c| pcaddu12i $t0, 16
+0c02001e| pcaddu18i $t0, 16
+0c02001a| pcalau12i $t0, 16
+a041c02a| preld 0x0, $t1, 16
+a0392c38| preldx 0x0, $t1, $t2
+ac690000| rdtime.d $t0, $t1
+ac650000| rdtimeh.w $t0, $t1
+ac610000| rdtimel.w $t0, $t1
+ac310000| revb.2h $t0, $t1
+ac390000| revb.2w $t0, $t1
+ac350000| revb.4h $t0, $t1
+ac3d0000| revb.d $t0, $t1
+ac410000| revh.2w $t0, $t1
+ac450000| revh.d $t0, $t1
+acb91b00| rotr.d $t0, $t1, $t2
+ac391b00| rotr.w $t0, $t1, $t2
+ac414d00| rotri.d $t0, $t1, 0x10
+acc14c00| rotri.w $t0, $t1, 0x10
+ac110023| sc.d $t0, $t1, 16
+ac110021| sc.w $t0, $t1, 16
+acb91800| sll.d $t0, $t1, $t2
+ac391700| sll.w $t0, $t1, $t2
+ac414100| slli.d $t0, $t1, 0x10
+acc14000| slli.w $t0, $t1, 0x10
+ac391200| slt $t0, $t1, $t2
+ac410002| slti $t0, $t1, 16
+acb91200| sltu $t0, $t1, $t2
+ac414002| sltui $t0, $t1, 16
+acb91900| sra.d $t0, $t1, $t2
+ac391800| sra.w $t0, $t1, $t2
+ac414900| srai.d $t0, $t1, 0x10
+acc14800| srai.w $t0, $t1, 0x10
+ac391900| srl.d $t0, $t1, $t2
+acb91700| srl.w $t0, $t1, $t2
+ac414500| srli.d $t0, $t1, 0x10
+acc14400| srli.w $t0, $t1, 0x10
+ac410029| st.b $t0, $t1, 16
+ac41c029| st.d $t0, $t1, 16
+ac414029| st.h $t0, $t1, 16
+ac418029| st.w $t0, $t1, 16
+ac397c38| stgt.b $t0, $t1, $t2
+acb97d38| stgt.d $t0, $t1, $t2
+acb97c38| stgt.h $t0, $t1, $t2
+ac397d38| stgt.w $t0, $t1, $t2
+ac397e38| stle.b $t0, $t1, $t2
+acb97f38| stle.d $t0, $t1, $t2
+acb97e38| stle.h $t0, $t1, $t2
+ac397f38| stle.w $t0, $t1, $t2
+ac110027| stptr.d $t0, $t1, 16
+ac110025| stptr.w $t0, $t1, 16
+ac391038| stx.b $t0, $t1, $t2
+ac391c38| stx.d $t0, $t1, $t2
+ac391438| stx.h $t0, $t1, $t2
+ac391838| stx.w $t0, $t1, $t2
+acb91100| sub.d $t0, $t1, $t2
+ac391100| sub.w $t0, $t1, $t2
+00002b00| syscall 0x0
+00204806| tlbclr
+00344806| tlbfill
+00244806| tlbflush
+002c4806| tlbrd
+00284806| tlbsrch
+00304806| tlbwr
+acb91500| xor $t0, $t1, $t2
+ac41c003| xori $t0, $t1, 0x10
+cc355d38| amadd.b $t0, $t1, $t2
+cc355f38| amadd_db.b $t0, $t1, $t2
+ccb55f38| amadd_db.h $t0, $t1, $t2
+ccb55d38| amadd.h $t0, $t1, $t2
+cc355838| amcas.b $t0, $t1, $t2
+ccb55938| amcas.d $t0, $t1, $t2
+cc355a38| amcas_db.b $t0, $t1, $t2
+ccb55b38| amcas_db.d $t0, $t1, $t2
+ccb55a38| amcas_db.h $t0, $t1, $t2
+cc355b38| amcas_db.w $t0, $t1, $t2
+ccb55838| amcas.h $t0, $t1, $t2
+cc355938| amcas.w $t0, $t1, $t2
+cc355c38| amswap.b $t0, $t1, $t2
+cc355e38| amswap_db.b $t0, $t1, $t2
+ccb55e38| amswap_db.h $t0, $t1, $t2
+ccb55c38| amswap.h $t0, $t1, $t2
+28791401| frecipe.d $ft0, $ft1
+28751401| frecipe.s $ft0, $ft1
+28891401| frsqrte.d $ft0, $ft1
+28851401| frsqrte.s $ft0, $ft1
+ac895738| llacq.d $t0, $t1
+ac815738| llacq.w $t0, $t1
+ac8d5738| screl.d $t0, $t1
+ac855738| screl.w $t0, $t1
diff --git a/loong64/loong64asm/testdata/plan9cases.txt b/loong64/loong64asm/testdata/plan9cases.txt
new file mode 100644
index 0000000..53f5d45
--- /dev/null
+++ b/loong64/loong64asm/testdata/plan9cases.txt
@@ -0,0 +1,365 @@
+a6101000| ADD R4, R5, R6
+a6901000| ADDV R4, R5, R6
+a5101000| ADD R4, R5
+a5901000| ADDV R4, R5
+85fcbf02| ADD $-1, R4, R5
+84fcbf02| ADD $-1, R4
+85fcff02| ADDV $-1, R4, R5
+84fcff02| ADDV $-1, R4
+ac391000| ADD R14, R13, R12
+acb91000| ADDV R14, R13, R12
+ac41c002| ADDV $16, R13, R12
+ac01e002| ADDV $-2048, R13, R12
+acfdff02| ADDV $-1, R13, R12
+ac05e002| ADDV $-2047, R13, R12
+acf9ff02| ADDV $-2, R13, R12
+ac418002| ADD $16, R13, R12
+a6101100| SUB R4, R5, R6
+a6901100| SUBV R4, R5, R6
+a5101100| SUB R4, R5
+a5901100| SUBV R4, R5
+05101100| NEGW R4, R5
+05901100| NEGV R4, R5
+84781200| SGT R30, R4
+85781200| SGT R30, R4, R5
+84f81200| SGTU R30, R4
+85f81200| SGTU R30, R4, R5
+a6901400| AND R4, R5, R6
+a5901400| AND R4, R5
+85044003| AND $1, R4, R5
+84044003| AND $1, R4
+a5101c00| MUL R4, R5
+a6101c00| MUL R4, R5, R6
+a5901d00| MULV R4, R5
+a6901d00| MULV R4, R5, R6
+a5101e00| MULHV R4, R5
+a6101e00| MULHV R4, R5, R6
+a5901e00| MULHVU R4, R5
+a6901e00| MULHVU R4, R5, R6
+28290501| MULD F10, F9, F8
+28a90401| MULF F10, F9, F8
+a5102000| DIV R4, R5
+a6102000| DIV R4, R5, R6
+a5102100| DIVU R4, R5
+a6102100| DIVU R4, R5, R6
+a5102200| DIVV R4, R5
+a6102200| DIVV R4, R5, R6
+a5102300| DIVVU R4, R5
+a6102300| DIVVU R4, R5, R6
+28290701| DIVD F10, F9, F8
+28a90601| DIVF F10, F9, F8
+a5902000| REM R4, R5
+a6902000| REM R4, R5, R6
+a5902100| REMU R4, R5
+a6902100| REMU R4, R5, R6
+a5902200| REMV R4, R5
+a6902200| REMV R4, R5, R6
+a5902300| REMVU R4, R5
+a6902300| REMVU R4, R5, R6
+04020014| LU12IW $16, R4
+24000014| LU12IW $1, R4
+85001700| MOVW R4, R5
+85001500| MOVV R4, R5
+85fc4303| MOVBU R4, R5
+1e020014| LU12IW $16, R30
+85781000| ADD R30, R4, R5
+de038003| OR $0, R30
+ac391400| NOR R14, R13, R12
+acb91500| XOR R14, R13, R12
+ac41c003| XOR $16, R13, R12
+85f81000| ADDV R30, R4, R5
+8500cf00| MOVHU R4, R5
+a5101700| SLL R4, R5
+a6101700| SLL R4, R5, R6
+a5901700| SRL R4, R5
+a6901700| SRL R4, R5, R6
+a5101800| SRA R4, R5
+a6101800| SRA R4, R5, R6
+a5101b00| ROTR R4, R5
+a6101b00| ROTR R4, R5, R6
+a5901800| SLLV R4, R5
+a6901800| SLLV R4, R5, R6
+a5901b00| ROTRV R4, R5
+a6901b00| ROTRV R4, R5, R6
+85904000| SLL $4, R4, R5
+84904000| SLL $4, R4
+85904400| SRL $4, R4, R5
+84904400| SRL $4, R4
+85904800| SRA $4, R4, R5
+84904800| SRA $4, R4
+85904c00| ROTR $4, R4, R5
+84904c00| ROTR $4, R4
+85104100| SLLV $4, R4, R5
+84104100| SLLV $4, R4
+85104d00| ROTRV $4, R4, R5
+84104d00| ROTRV $4, R4
+a6101300| MASKEQZ R4, R5, R6
+a6901300| MASKNEZ R4, R5, R6
+00050048| BFPT 1(PC)
+00040048| BFPF 1(PC)
+80040058| BEQ R4, 1(PC)
+8d110058| BEQ R12, R13, 4(PC)
+a0110040| BEQ R13, 4(PC)
+9ff1ff43| BEQ R12, -4(PC)
+8504005c| BNE R4, R5, 1(PC)
+8004005c| BNE R4, 1(PC)
+8004005c| BNE R4, 1(PC)
+a0140058| BEQ R5, 5(PC)
+a0110058| BEQ R13, 4(PC)
+00ebff5f| BNE R24, -6(PC)
+801d005c| BNE R12, 7(PC)
+85040060| BLT R4, R5, 1(PC)
+80fcff63| BLTZ R4, -1(PC)
+05040060| BGTZ R5, 1(PC)
+80040060| BLTZ R4, 1(PC)
+47d5ff6b| BLTU R10, R7, -11(PC)
+802c0068| BLTU R4, 11(PC)
+85040064| BGE R4, R5, 1(PC)
+80fcff67| BGEZ R4, -1(PC)
+47d5ff6f| BGEU R10, R7, -11(PC)
+802c006c| BGEU R4, 11(PC)
+04d8ff67| BLEZ R4, -10(PC)
+00040058| JMP 1(PC)
+8000004c| JMP (R4)
+00340050| JMP 13(PC)
+00100050| JMP 4(PC)
+00100054| CALL 4(PC)
+8100004c| CALL (R4)
+00140054| CALL 5(PC)
+a4048029| MOVW R4, 1(R5)
+a404c029| MOVV R4, 1(R5)
+a4040029| MOVB R4, 1(R5)
+ac410029| MOVB R12, 16(R13)
+a4040021| SC R4, 1(R5)
+a4040023| SCV R4, 1(R5)
+a4040028| MOVB 1(R5), R4
+a404002a| MOVBU 1(R5), R4
+a4044028| MOVH 1(R5), R4
+a404402a| MOVHU 1(R5), R4
+a4048028| MOVW 1(R5), R4
+a404802a| MOVWU 1(R5), R4
+a404c028| MOVV 1(R5), R4
+a4040020| LL 1(R5), R4
+a4040022| LLV 1(R5), R4
+a4fc3f20| LL -1(R5), R4
+a4fc3f22| LLV -1(R5), R4
+00002a00| BREAK
+00007238| DBAR
+00002b00| SYSCALL
+00004003| NOOP
+a5900001| ADDF F4, F5
+a6900001| ADDF F4, F5, F6
+28a50001| ADDF F9, F9, F8
+28250101| ADDD F9, F9, F8
+85041401| ABSF F4, F5
+85081401| ABSD F4, F5
+85141401| NEGF F4, F5
+85181401| NEGD F4, F5
+85441401| SQRTF F4, F5
+85481401| SQRTD F4, F5
+a090110c| CMPGTF F4, F5, FCC0
+a090210c| CMPGTD F4, F5, FCC0
+a090130c| CMPGEF F4, F5, FCC0
+a090230c| CMPGED F4, F5, FCC0
+a010220c| CMPEQD F4, F5, FCC0
+2029120c| CMPEQF F10, F9, FCC0
+85241901| MOVFD F4, F5
+85181901| MOVDF F4, F5
+85101d01| FFINTFW F4, F5
+85201d01| FFINTDW F4, F5
+85181d01| FFINTFV F4, F5
+85281d01| FFINTDV F4, F5
+85041b01| FTINTWF F4, F5
+85241b01| FTINTVF F4, F5
+85081b01| FTINTWD F4, F5
+85281b01| FTINTVD F4, F5
+85881a01| FTINTRZWD F4, F5
+85841a01| FTINTRZWF F4, F5
+85a81a01| FTINTRZVD F4, F5
+85a41a01| FTINTRZVF F4, F5
+85941401| MOVF F4, F5
+85981401| MOVD F4, F5
+85a41401| MOVW R4, F5
+85b41401| MOVW F4, R5
+85a81401| MOVV R4, F5
+85b81401| MOVV F4, R5
+04dc1401| MOVV FCC0, R4
+80d81401| MOVV R4, FCC0
+6440002b| MOVF 16(R3), F4
+6440802b| MOVD 16(R3), F4
+a404002b| MOVF 1(R5), F4
+a404802b| MOVD 1(R5), F4
+6460402b| MOVF F4, 24(R3)
+6460c02b| MOVD F4, 24(R3)
+a404402b| MOVF F4, 1(R5)
+a404c02b| MOVD F4, 1(R5)
+5e020014| LU12IW $18, R30
+64a95214| LU12IW $169291, R4
+84d08703| OR $500, R4
+84428614| LU12IW $274964, R4
+84848c03| OR $801, R4
+24640816| LU32ID $17185, R4
+84000003| LU52ID $0, R4
+24a93615| LU12IW $-412343, R4
+84849003| OR $1057, R4
+8464c817| LU32ID $-113884, R4
+848c0203| LU52ID $163, R4
+80600000| RDTIMELW R4, R0
+80640000| RDTIMEHW R4, R0
+85680000| RDTIMED R4, R5
+1e00001a| PCALAU12I $0, R30
+0c02001c| PCADDU12I $16, R12
+c4038029| MOVW R4, 0(R30)
+ac395c38| AMSWAPB R14, (R13), R12
+acb95c38| AMSWAPH R14, (R13), R12
+ac396038| AMSWAPW R14, (R13), R12
+acb96038| AMSWAPV R14, (R13), R12
+ac395838| AMCASB R14, (R13), R12
+acb95838| AMCASH R14, (R13), R12
+ac395938| AMCASW R14, (R13), R12
+acb95938| AMCASV R14, (R13), R12
+ac396138| AMADDW R14, (R13), R12
+acb96138| AMADDV R14, (R13), R12
+ac396238| AMANDW R14, (R13), R12
+acb96238| AMANDV R14, (R13), R12
+ac396338| AMORW R14, (R13), R12
+acb96338| AMORV R14, (R13), R12
+ac396438| AMXORW R14, (R13), R12
+acb96438| AMXORV R14, (R13), R12
+ac396538| AMMAXW R14, (R13), R12
+acb96538| AMMAXV R14, (R13), R12
+ac396638| AMMINW R14, (R13), R12
+acb96638| AMMINV R14, (R13), R12
+ac396738| AMMAXWU R14, (R13), R12
+acb96738| AMMAXVU R14, (R13), R12
+ac396838| AMMINWU R14, (R13), R12
+acb96838| AMMINVU R14, (R13), R12
+ac395e38| AMSWAPDBB R14, (R13), R12
+acb95e38| AMSWAPDBH R14, (R13), R12
+ac396938| AMSWAPDBW R14, (R13), R12
+acb96938| AMSWAPDBV R14, (R13), R12
+ac395a38| AMCASDBB R14, (R13), R12
+acb95a38| AMCASDBH R14, (R13), R12
+ac395b38| AMCASDBW R14, (R13), R12
+acb95b38| AMCASDBV R14, (R13), R12
+ac396a38| AMADDDBW R14, (R13), R12
+acb96a38| AMADDDBV R14, (R13), R12
+ac396b38| AMANDDBW R14, (R13), R12
+acb96b38| AMANDDBV R14, (R13), R12
+ac396c38| AMORDBW R14, (R13), R12
+acb96c38| AMORDBV R14, (R13), R12
+ac396d38| AMXORDBW R14, (R13), R12
+acb96d38| AMXORDBV R14, (R13), R12
+ac396e38| AMMAXDBW R14, (R13), R12
+acb96e38| AMMAXDBV R14, (R13), R12
+ac396f38| AMMINDBW R14, (R13), R12
+acb96f38| AMMINDBV R14, (R13), R12
+ac397038| AMMAXDBWU R14, (R13), R12
+acb97038| AMMAXDBVU R14, (R13), R12
+ac397138| AMMINDBWU R14, (R13), R12
+acb97138| AMMINDBVU R14, (R13), R12
+856c0000| CPUCFG R4, R5
+85481e01| FRINTD F4, F5
+83c01401| MOVV R4, FCSR3
+64c81401| MOVV FCSR3, R4
+80d01401| MOVV F4, FCC0
+04d41401| MOVV FCC0, F4
+a6901201| FCOPYSGF F4, F5, F6
+a6101301| FCOPYSGD F4, F5, F6
+85500000| BITREVW R4, R5
+85540000| BITREVV R4, R5
+a6102400| CRCWBW R4, R5, R6
+a6902400| CRCWHW R4, R5, R6
+a6102500| CRCWWW R4, R5, R6
+a6902500| CRCWVW R4, R5, R6
+a6102600| CRCCWBW R4, R5, R6
+a6902600| CRCCWHW R4, R5, R6
+a6102700| CRCCWWW R4, R5, R6
+a6902700| CRCCWVW R4, R5, R6
+cc350038| MOVB (R14)(R13), R12
+cc352038| MOVBU (R14)(R13), R12
+cc350438| MOVH (R14)(R13), R12
+cc352438| MOVHU (R14)(R13), R12
+cc350838| MOVW (R14)(R13), R12
+cc352838| MOVWU (R14)(R13), R12
+cc350c38| MOVV (R14)(R13), R12
+cc351038| MOVB R12, (R14)(R13)
+cc351438| MOVH R12, (R14)(R13)
+cc351838| MOVW R12, (R14)(R13)
+cc351c38| MOVV R12, (R14)(R13)
+c2353038| MOVF (R14)(R13), F2
+c2353438| MOVD (R14)(R13), F2
+c2353838| MOVF F2, (R14)(R13)
+c2353c38| MOVD F2, (R14)(R13)
+a010120c| CMPEQF F4, F5, FCC0
+a190110c| CMPGTF F4, F5, FCC1
+a290210c| CMPGTD F4, F5, FCC2
+a390130c| CMPGEF F4, F5, FCC3
+a490230c| CMPGED F4, F5, FCC4
+a510220c| CMPEQD F4, F5, FCC5
+85100000| CLOW R4, R5
+85200000| CLOV R4, R5
+85140000| CLZW R4, R5
+85240000| CLZV R4, R5
+85180000| CTOW R4, R5
+85280000| CTOV R4, R5
+851c0000| CTZW R4, R5
+852c0000| CTZV R4, R5
+853c0000| REVBV R4, R5
+85380000| REVB2W R4, R5
+85340000| REVB4H R4, R5
+85300000| REVB2H R4, R5
+a6900a01| FMINF F4, F5, F6
+a5900a01| FMINF F4, F5
+a6100b01| FMIND F4, F5, F6
+a5100b01| FMIND F4, F5
+a6900801| FMAXF F4, F5, F6
+a5900801| FMAXF F4, F5
+a6100901| FMAXD F4, F5, F6
+a5100901| FMAXD F4, F5
+85341401| FCLASSF F4, F5
+85381401| FCLASSD F4, F5
+02041a01| FTINTRMWF F0, F2
+02081a01| FTINTRMWD F0, F2
+02241a01| FTINTRMVF F0, F2
+02281a01| FTINTRMVD F0, F2
+02441a01| FTINTRPWF F0, F2
+02481a01| FTINTRPWD F0, F2
+02641a01| FTINTRPVF F0, F2
+02681a01| FTINTRPVD F0, F2
+02841a01| FTINTRZWF F0, F2
+02881a01| FTINTRZWD F0, F2
+02a41a01| FTINTRZVF F0, F2
+02a81a01| FTINTRZVD F0, F2
+02c41a01| FTINTRNEWF F0, F2
+02c81a01| FTINTRNEWD F0, F2
+02e41a01| FTINTRNEVF F0, F2
+02e81a01| FTINTRNEVD F0, F2
+01101d01| FFINTFW F0, F1
+01181d01| FFINTFV F0, F1
+01201d01| FFINTDW F0, F1
+01281d01| FFINTDV F0, F1
+01041b01| FTINTWF F0, F1
+01081b01| FTINTWD F0, F1
+01241b01| FTINTVF F0, F1
+01281b01| FTINTVD F0, F1
+c7901208| FMADDF F5, F4, F6, F7
+c7902208| FMADDD F5, F4, F6, F7
+c7905208| FMSUBF F5, F4, F6, F7
+c7906208| FMSUBD F5, F4, F6, F7
+c7909208| FNMADDF F5, F4, F6, F7
+c790a208| FNMADDD F5, F4, F6, F7
+c790d208| FNMSUBF F5, F4, F6, F7
+c790e208| FNMSUBD F5, F4, F6, F7
+85806000| BSTRPICKW $0, R4, $0, R5
+85807f00| BSTRPICKW $31, R4, $0, R5
+85986f00| BSTRPICKW $15, R4, $6, R5
+8500c000| BSTRPICKV $0, R4, $0, R5
+8500ff00| BSTRPICKV $63, R4, $0, R5
+8518cf00| BSTRPICKV $15, R4, $6, R5
+85006000| BSTRINSW $0, R4, $0, R5
+85007f00| BSTRINSW $31, R4, $0, R5
+85186f00| BSTRINSW $15, R4, $6, R5
+85008000| BSTRINSV $0, R4, $0, R5
+8500bf00| BSTRINSV $63, R4, $0, R5
+85188f00| BSTRINSV $15, R4, $6, R5
diff --git a/loong64/loong64spec/spec.go b/loong64/loong64spec/spec.go
new file mode 100644
index 0000000..4c32961
--- /dev/null
+++ b/loong64/loong64spec/spec.go
@@ -0,0 +1,528 @@
+// 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.
+
+// loong64spec reads the "LoongArch-Vol1-EN.pdf" [1] to collect instruction
+// encoding details and output to tables.go.
+//
+// usage: go run spec.go LoongArch-Vol1-EN.pdf
+//
+// [1]: https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.pdf
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "math"
+ "os"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+
+ "rsc.io/pdf"
+)
+
+func mergeMap(m1 map[string]string, m2 map[string]string) {
+ for k := range m2 {
+ m1[k] = m2[k]
+ }
+}
+
+func main() {
+ log.SetFlags(0)
+ log.SetPrefix("loong64spec: ")
+
+ if len(os.Args) != 2 {
+ fmt.Fprintf(os.Stderr, "usage: loong64spec LoongArch-Vol1-EN.pdf\n")
+ os.Exit(2)
+ }
+ f, err := pdf.Open(os.Args[1])
+ if err != nil {
+ log.Fatal(err)
+ }
+ var prologue bytes.Buffer
+ prologue.Write([]byte("// Generated by loong64spec LoongArch-Vol1-EN.pdf, DO NOT EDIT.\n\n// Copyright 2024 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage loong64asm\n\n"))
+
+ var op_f bytes.Buffer
+ op_f.Write([]byte("const (\n\t_ Op = iota\n"))
+
+ var opstr_f bytes.Buffer
+ opstr_f.Write([]byte("var opstr = [...]string{\n"))
+
+ var instFormats_f bytes.Buffer
+ instFormats_f.Write([]byte("var instFormats = [...]instFormat{\n"))
+
+ // Scan document looking for instructions.
+ n := f.NumPage()
+ var ops []string
+ opstrs := map[string]string{}
+ instFormatComments := map[string]string{}
+ instFormats := map[string]string{}
+ var fp int
+ for pageNum := 1; pageNum <= n; pageNum++ {
+ p := f.Page(pageNum)
+ if fp == 0 {
+ if !isFirstPage(p) {
+ continue
+ }
+ fp = pageNum
+ }
+ cPageOps, cPageOpstrs, cPageInstFormatComments, cPageInstFormats := parsePage(pageNum, p, fp == pageNum)
+ ops = append(ops, cPageOps...)
+ mergeMap(opstrs, cPageOpstrs)
+ mergeMap(instFormatComments, cPageInstFormatComments)
+ mergeMap(instFormats, cPageInstFormats)
+ }
+
+ sort.Strings(ops)
+
+ for _, op := range ops {
+ // 1. write op
+ op_f.Write([]byte(fmt.Sprintf("\t%s\n", op)))
+ // 2. write opstr
+ opstr_f.Write([]byte(fmt.Sprintf("\t%s\n", opstrs[op])))
+ // 3. write instFormat
+ instFormats_f.Write([]byte(fmt.Sprintf("\t%s\n\t%s\n", instFormatComments[op], instFormats[op])))
+ }
+
+ op_f.Write([]byte(")\n\n"))
+ opstr_f.Write([]byte("}\n\n"))
+ instFormats_f.Write([]byte("}\n"))
+
+ fileTables, err := os.Create("tables.go")
+ defer fileTables.Close()
+
+ fileTables.Write(prologue.Bytes())
+ fileTables.Write(op_f.Bytes())
+ fileTables.Write(opstr_f.Bytes())
+ fileTables.Write(instFormats_f.Bytes())
+
+ fileTables.Close()
+}
+
+func isFirstPage(page pdf.Page) bool {
+ content := page.Content()
+ appendixb := "AppendixB"
+ ct := ""
+ for _, t := range content.Text {
+ ct += t.S
+ if ct == "AppendixB" {
+ return true
+ }
+ if strings.HasPrefix(appendixb, ct) {
+ continue
+ } else {
+ return false
+ }
+ }
+ return false
+}
+
+func getArg(name string) (length int, argName string) {
+ switch {
+ case strings.Contains("arg_fd", name):
+ return 5, "arg_fd"
+ case strings.Contains("arg_fj", name):
+ return 5, "arg_fj"
+ case strings.Contains("arg_fk", name):
+ return 5, "arg_fk"
+ case strings.Contains("arg_fa", name):
+ return 5, "arg_fa"
+ case strings.Contains("arg_rd", name):
+ return 5, "arg_rd"
+ case strings.Contains("arg_rj", name) || name == "rj!=0,1":
+ return 5, "arg_rj"
+ case strings.Contains("arg_rk", name):
+ return 5, "arg_rk"
+ case name == "csr":
+ return 14, "arg_csr_23_10"
+ case strings.Contains("arg_cd", name):
+ return 5, "arg_cd"
+ case strings.Contains("arg_cj", name):
+ return 5, "arg_cj"
+ case strings.Contains("arg_ca", name):
+ return 5, "arg_ca"
+ case strings.Contains(name, "sa"):
+ length, _ := strconv.Atoi(strings.Split(name, "sa")[1])
+ if length == 2 {
+ argName = "arg_sa2_16_15"
+ } else {
+ argName = "arg_sa3_17_15"
+ }
+ return length, argName
+ case strings.Contains("arg_seq_17_10", name):
+ return 8, "arg_seq_17_10"
+ case strings.Contains("arg_op_4_0", name):
+ return 5, "arg_op_4_0"
+ case strings.Contains(name, "ui"):
+ length, _ := strconv.Atoi(strings.Split(name, "ui")[1])
+ if length == 5 {
+ argName = "arg_ui5_14_10"
+ } else if length == 6 {
+ argName = "arg_ui6_15_10"
+ } else {
+ argName = "arg_ui12_21_10"
+ }
+ return length, argName
+ case strings.Contains("arg_lsbw", name):
+ return 5, "arg_lsbw"
+ case strings.Contains("arg_msbw", name):
+ return 5, "arg_msbw"
+ case strings.Contains("arg_lsbd", name):
+ return 6, "arg_lsbd"
+ case strings.Contains("arg_msbd", name):
+ return 6, "arg_msbd"
+ case strings.Contains(name, "si"):
+ length, _ := strconv.Atoi(strings.Split(name, "si")[1])
+ if length == 12 {
+ argName = "arg_si12_21_10"
+ } else if length == 14 {
+ argName = "arg_si14_23_10"
+ } else if length == 16 {
+ argName = "arg_si16_25_10"
+ } else {
+ argName = "arg_si20_24_5"
+ }
+ return length, argName
+ case strings.Contains(name, "offs"):
+ splitName := strings.Split(name, ":")
+ left, _ := strconv.Atoi(strings.Split(splitName[0], "[")[1])
+ right, _ := strconv.Atoi(strings.Split(splitName[1], "]")[0])
+ return left - right + 1, "offs"
+ default:
+ return 0, ""
+ }
+}
+
+func binstrToHex(str string) string {
+ rst := 0
+ hex := "0x"
+ charArray := []byte(str)
+ for i := 0; i < 32; {
+ rst = 1*(int(charArray[i+3])-48) + 2*(int(charArray[i+2])-48) + 4*(int(charArray[i+1])-48) + 8*(int(charArray[i])-48)
+ switch rst {
+ case 10:
+ hex = hex + "a"
+ case 11:
+ hex = hex + "b"
+ case 12:
+ hex = hex + "c"
+ case 13:
+ hex = hex + "d"
+ case 14:
+ hex = hex + "e"
+ case 15:
+ hex = hex + "f"
+ default:
+ hex += strconv.Itoa(rst)
+ }
+
+ i = i + 4
+ }
+ return hex
+}
+
+/*
+Here we deal with the instruction FCMP.cond.S/D, which has the following format:
+
+ | 31 - 20 | 19 - 15 | 14 - 10 | 9 - 5 | 4 | 3 | 2 - 0 |
+ |---------|---------|---------|-------|---|---|-------|
+ | op | cond | fk | fj | 0 | 0 | cd |
+
+The `cond` field has these possible values:
+
+ "CAF": "00",
+ "CUN": "08",
+ "CEQ": "04",
+ "CUEQ": "0c",
+ "CLT": "02",
+ "CULT": "0a",
+ "CLE": "06",
+ "CULE": "0e",
+ "CNE": "10",
+ "COR": "14",
+ "CUNE": "18",
+ "SAF": "01",
+ "SUN": "09",
+ "SEQ": "05",
+ "SUEQ": "0d",
+ "SLT": "03",
+ "SULT": "0b",
+ "SLE": "07",
+ "SULE": "0f",
+ "SNE": "11",
+ "SOR": "15",
+ "SUNE": "19",
+
+These values are the hexadecimal numbers of bits 19 to 15, the same as
+described in the instruction set manual.
+
+The following code defines a map, the values in it represent the hexadecimal
+encoding of the cond field in the entire instruction. In this case, the upper
+4 bits and the lowest 1 bit are encoded separately, so the encoding is
+different from the encoding described above.
+*/
+func dealWithFcmp(ds string) (fcmpConditions map[string]map[string]string) {
+ conds := map[string]string{
+ "CAF": "00",
+ "CUN": "40",
+ "CEQ": "20",
+ "CUEQ": "60",
+ "CLT": "10",
+ "CULT": "50",
+ "CLE": "30",
+ "CULE": "70",
+ "CNE": "80",
+ "COR": "a0",
+ "CUNE": "c0",
+ "SAF": "08",
+ "SUN": "48",
+ "SEQ": "28",
+ "SUEQ": "68",
+ "SLT": "18",
+ "SULT": "58",
+ "SLE": "38",
+ "SULE": "78",
+ "SNE": "88",
+ "SOR": "a8",
+ "SUNE": "c8",
+ }
+ fcmpConditions = make(map[string]map[string]string)
+ for k, v := range conds {
+ op := fmt.Sprintf("FCMP_%s_%s", k, ds)
+ opstr := fmt.Sprintf("FCMP_%s_%s:\t\"FCMP.%s.%s\",", k, ds, k, ds)
+ instFormatComment := fmt.Sprintf("// FCMP.%s.%s cd, fj, fk", k, ds)
+ var instFormat string
+ if ds == "D" {
+ instFormat = fmt.Sprintf("{mask: 0xffff8018, value: 0x0c2%s000, op: FCMP_%s_%s, args: instArgs{arg_cd, arg_fj, arg_fk}},", v, k, ds)
+ } else {
+ instFormat = fmt.Sprintf("{mask: 0xffff8018, value: 0x0c1%s000, op: FCMP_%s_%s, args: instArgs{arg_cd, arg_fj, arg_fk}},", v, k, ds)
+ }
+
+ fcmpConditions[op] = make(map[string]string)
+ fcmpConditions[op]["op"] = op
+ fcmpConditions[op]["opstr"] = opstr
+ fcmpConditions[op]["instFormatComment"] = instFormatComment
+ fcmpConditions[op]["instFormat"] = instFormat
+ }
+ return
+}
+
+func findWords(chars []pdf.Text) (words []pdf.Text) {
+ for i := 0; i < len(chars); {
+ xRange := []float64{chars[i].X, chars[i].X}
+ j := i + 1
+
+ // Find all chars on one line.
+ for j < len(chars) && chars[j].Y == chars[i].Y {
+ xRange[1] = chars[j].X
+ j++
+ }
+
+ // we need to note that the word may change line(Y) but belong to one cell. So, after loop over all continued
+ // chars whose Y are same, check if the next char's X belong to the range of xRange, if true, means it should
+ // be contact to current word, because the next word's X should bigger than current one.
+ for j < len(chars) && chars[j].X >= xRange[0] && chars[j].X <= xRange[1] {
+ j++
+ }
+
+ var end float64
+ // Split line into words (really, phrases).
+ for k := i; k < j; {
+ ck := &chars[k]
+ s := ck.S
+ end = ck.X + ck.W
+ charSpace := ck.FontSize / 6
+ wordSpace := ck.FontSize * 2 / 3
+ l := k + 1
+ for l < j {
+ // Grow word.
+ cl := &chars[l]
+
+ if math.Abs(cl.FontSize-ck.FontSize) < 0.1 && cl.X <= end+charSpace {
+ s += cl.S
+ end = cl.X + cl.W
+ l++
+ continue
+ }
+ // Add space to phrase before next word.
+ if math.Abs(cl.FontSize-ck.FontSize) < 0.1 && cl.X <= end+wordSpace {
+ s += " " + cl.S
+ end = cl.X + cl.W
+ l++
+ continue
+ }
+ break
+ }
+ f := ck.Font
+ words = append(words, pdf.Text{f, ck.FontSize, ck.X, ck.Y, end - ck.X, s})
+ k = l
+ }
+ i = j
+ }
+
+ return words
+}
+
+func parsePage(num int, p pdf.Page, isFP bool) (ops []string, opstrs map[string]string, instFormatComments map[string]string, instFormats map[string]string) {
+ opstrs = make(map[string]string)
+ instFormatComments = make(map[string]string)
+ instFormats = make(map[string]string)
+
+ content := p.Content()
+
+ var text []pdf.Text
+ for _, t := range content.Text {
+ text = append(text, t)
+ }
+
+ // table name(70), table header(64), page num(3)
+ if isFP {
+ text = text[134 : len(text)-3]
+ } else {
+ text = text[64 : len(text)-3]
+ }
+
+ text = findWords(text)
+
+ for i := 0; i < len(text); {
+ var fcmpConditions map[string]map[string]string
+ if strings.HasPrefix(text[i].S, "FCMP") {
+ fcmpConditions = dealWithFcmp(strings.Split(text[i].S, ".")[2])
+
+ for fc, inst := range fcmpConditions {
+ ops = append(ops, inst["op"])
+ opstrs[fc] = inst["opstr"]
+ instFormatComments[fc] = inst["instFormatComment"]
+ instFormats[fc] = inst["instFormat"]
+ }
+ t := i + 1
+ for ; text[t].Y == text[i].Y; t++ {
+ continue
+ }
+ i = t
+ continue
+ }
+
+ op := strings.Replace(text[i].S, ".", "_", -1)
+ opstr := fmt.Sprintf("%s:\t\"%s\",", op, text[i].S)
+ instFormatComment := ""
+ binValue := ""
+ binMask := ""
+ instArgs := ""
+ offs := false
+ var offArgs []string
+
+ j := i + 1
+ for ; j < len(text) && text[j].Y == text[i].Y; j++ {
+
+ // Some instruction has no arguments, so the next word(text[j].S) is not the arguments string but 0/1 bit, it shouldn't be skipped.
+ if res, _ := regexp.MatchString("^\\d+$", text[j].S); j == i+1 && res == false {
+ instFormatComment = fmt.Sprintf("// %s %s", text[i].S, strings.Replace(text[j].S, ",", ", ", -1))
+ continue
+ }
+ if text[j].S == "0" || text[j].S == "1" {
+ binValue += text[j].S
+ binMask += "1"
+ } else {
+ argLen, argName := getArg(text[j].S)
+
+ // Get argument's length failed, compute it by other arguments.
+ if argLen == 0 {
+ left := 31 - len(binValue)
+ right := 0
+ l := j + 1
+ if l < len(text) && text[l].Y == text[j].Y {
+ for ; text[l].Y == text[j].Y; l++ {
+ if text[l].S == "0" || text[l].S == "1" {
+ right += 1
+ } else {
+ tArgLen, _ := getArg(text[l].S)
+ if tArgLen == 0 {
+ fmt.Fprintf(os.Stderr, "there are more than two args whose length is unknown.\n")
+ }
+ right += tArgLen
+ }
+ }
+ }
+ argLen = left - right + 1
+ argName = "arg_" + text[j].S + "_" + strconv.FormatInt(int64(left), 10) + "_" + strconv.FormatInt(int64(right), 10)
+ }
+
+ for k := 0; k < argLen; k++ {
+ binValue += "0"
+ binMask += "0"
+ }
+
+ if argName != "offs" {
+ if instArgs != "" {
+ instArgs = ", " + instArgs
+ }
+ instArgs = argName + instArgs
+ } else {
+ offs = true
+ offArgs = append(offArgs, text[j].S)
+ }
+ }
+ }
+
+ // The real offset is a combination of two offsets in the binary code of the instruction, for example: BEQZ
+ if offs && offArgs != nil {
+ var left int
+ var right int
+ if len(offArgs) == 1 {
+ left, _ = strconv.Atoi(strings.Split(strings.Split(offArgs[0], ":")[0], "[")[1])
+ right, _ = strconv.Atoi(strings.Split(strings.Split(offArgs[0], ":")[1], "]")[0])
+ } else if len(offArgs) == 2 {
+ left, _ = strconv.Atoi(strings.Split(strings.Split(offArgs[1], ":")[0], "[")[1])
+ right, _ = strconv.Atoi(strings.Split(strings.Split(offArgs[0], ":")[1], "]")[0])
+ }
+
+ if instArgs == "" {
+ instArgs = fmt.Sprintf("arg_offset_%d_%d", left, right)
+ } else {
+ instArgs += fmt.Sprintf(", arg_offset_%d_%d", left, right)
+ }
+ }
+
+ ops = append(ops, op)
+ opstrs[op] = opstr
+ if instFormatComment == "" {
+ instFormatComment = "// " + text[i].S
+ } else if strings.HasPrefix(op, "AM") {
+ instFormatComment = fmt.Sprintf("// %s rd, rk, rj", text[i].S)
+ }
+ instFormatComments[op] = instFormatComment
+ // The parameter order of some instructions is inconsistent in encoding and syntax, such as BSTRINS.*
+ if instArgs != "" {
+ args := strings.Split(instFormatComment, " ")[2:]
+ tInstArgs := strings.Split(instArgs, ", ")
+ newOrderedInstArgs := []string{}
+ for _, a := range args {
+ a = strings.Split(a, ",")[0]
+ for _, aa := range tInstArgs {
+ if strings.Contains(aa, a) {
+ newOrderedInstArgs = append(newOrderedInstArgs, aa)
+ break
+ } else if a == "rd" && aa == "arg_fd" {
+ newOrderedInstArgs = append(newOrderedInstArgs, "arg_rd")
+ break
+ }
+ }
+ }
+ instArgs = strings.Join(newOrderedInstArgs, ", ")
+ }
+ if strings.HasPrefix(op, "AM") {
+ instArgs = "arg_rd, arg_rk, arg_rj"
+ }
+ instFormat := fmt.Sprintf("{mask: %s, value: %s, op: %s, args: instArgs{%s}},", binstrToHex(binMask), binstrToHex(binValue), op, instArgs)
+ instFormats[op] = instFormat
+
+ i = j // next instruction
+ }
+
+ return
+}