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, &sect)
+	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, &sect) // 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, &sect) // .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, &sect)
+	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
+}