riscv64: add tests for riscv64asm

Add validation tests for riscv64asm GNU/Plan9 decoder, including
objdump test and external test.

Change-Id: Id7442704ea7e10c22ca4a799cdfc9f7d043f85c3
Reviewed-on: https://go-review.googlesource.com/c/arch/+/602916
Reviewed-by: Meng Zhuo <mengzhuo1203@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Mark Ryan <markdryan@rivosinc.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
diff --git a/riscv64/riscv64asm/decode_test.go b/riscv64/riscv64asm/decode_test.go
new file mode 100644
index 0000000..1590aaa
--- /dev/null
+++ b/riscv64/riscv64asm/decode_test.go
@@ -0,0 +1,80 @@
+// 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 riscv64asm
+
+import (
+	"bufio"
+	"encoding/hex"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+)
+
+func testDecode(t *testing.T, syntax string) {
+	input := filepath.Join("testdata", syntax+"cases.txt")
+	f, err := os.Open(input)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer f.Close()
+	scanner := bufio.NewScanner(f)
+	for scanner.Scan() {
+		line := strings.TrimSpace(scanner.Text())
+		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
+		}
+		asm0 := strings.Replace(f[1], "	", " ", -1)
+		asm := strings.TrimSpace(asm0)
+		inst, decodeErr := Decode(code)
+		if decodeErr != nil && decodeErr != errUnknown {
+			if asm == "illegalins" && decodeErr == errShort {
+				continue
+			}
+			// 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, nil)
+		default:
+			t.Errorf("unknown syntax %q", syntax)
+			continue
+		}
+
+		if asm != 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/riscv64/riscv64asm/ext_test.go b/riscv64/riscv64asm/ext_test.go
new file mode 100644
index 0000000..fa6961f
--- /dev/null
+++ b/riscv64/riscv64asm/ext_test.go
@@ -0,0 +1,330 @@
+// 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 riscv64asm
+
+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, 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("", "riscv64asm")
+	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, 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 src,
+// 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(src []byte, raw []byte) ([]byte, bool) {
+	src = bytes.TrimSpace(src)
+	raw, err := hex.AppendDecode(raw, src)
+	if err != nil {
+		return nil, false
+	}
+	return raw, true
+}
+
+// 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/riscv64/riscv64asm/objdump_test.go b/riscv64/riscv64asm/objdump_test.go
new file mode 100644
index 0000000..479301b
--- /dev/null
+++ b/riscv64/riscv64asm/objdump_test.go
@@ -0,0 +1,86 @@
+// 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 riscv64asm
+
+import (
+	"strings"
+	"testing"
+)
+
+func TestObjdumpRISCV64TestDecodeGNUSyntaxdata(t *testing.T) {
+	testObjdumpRISCV64(t, testdataCases(t, "gnu"))
+}
+func TestObjdumpRISCV64TestDecodeGoSyntaxdata(t *testing.T) {
+	testObjdumpRISCV64(t, testdataCases(t, "plan9"))
+}
+
+func TestObjdumpRISCV64Manual(t *testing.T) {
+	testObjdumpRISCV64(t, hexCases(t, objdumpManualTests))
+}
+
+// objdumpManualTests holds test cases that will be run by TestObjdumpRISCV64Manual.
+// 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 = `
+93020300
+13000000
+9b020300
+afb5b50e
+73b012c0
+73f01fc0
+73a012c0
+73e01fc0
+f3223000
+f3221000
+f3222000
+f3123300
+f3121300
+f3122300
+739012c0
+73d01fc0
+53a01022
+53a01020
+53801022
+53801020
+53901022
+53901020
+67800000
+67800200
+b3026040
+bb026040
+9342f3ff
+f32200c0
+f32200c8
+f32220c0
+f32220c8
+f32210c0
+f32210c8
+`
+
+// allowedMismatchObjdump reports whether the mismatch between text and dec
+// should be allowed by the test.
+func allowedMismatchObjdump(text string, inst *Inst, dec ExtInst) bool {
+	// Allow the mismatch of Branch/Jump instruction's offset.
+	decsp := strings.Split(dec.text, ",")
+
+	switch inst.Op {
+	case BEQ, BGE, BGEU, BLT, BLTU, BNE:
+		if inst.Args[2].(Simm).String() != decsp[len(decsp)-1] {
+			return true
+		}
+	case JAL:
+		if inst.Args[1].(Simm).String() != decsp[len(decsp)-1] {
+			return true
+		}
+	case JALR:
+		if inst.Args[1].(RegOffset).Ofs.String() != decsp[len(decsp)-1] {
+			return true
+		}
+	}
+
+	return false
+}
diff --git a/riscv64/riscv64asm/objdumpext_test.go b/riscv64/riscv64asm/objdumpext_test.go
new file mode 100644
index 0000000..4f1f21a
--- /dev/null
+++ b/riscv64/riscv64asm/objdumpext_test.go
@@ -0,0 +1,299 @@
+// 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 riscv64asm
+
+import (
+	"bytes"
+	"debug/elf"
+	"encoding/binary"
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"os/exec"
+	"strconv"
+	"strings"
+	"testing"
+)
+
+var objdumpPath = "riscv64-linux-gnu-objdump"
+
+func testObjdumpRISCV64(t *testing.T, generate func(func([]byte))) {
+	testObjdumpArch(t, generate)
+}
+
+func testObjdumpArch(t *testing.T, generate func(func([]byte))) {
+	checkObjdumpRISCV64(t)
+	testExtDis(t, "gnu", objdump, generate, allowedMismatchObjdump)
+	testExtDis(t, "plan9", objdump, generate, allowedMismatchObjdump)
+}
+
+func checkObjdumpRISCV64(t *testing.T) {
+	objdumpPath, err := exec.LookPath(objdumpPath)
+	if err != nil {
+		objdumpPath = "objdump"
+	}
+	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), "riscv") {
+		t.Skip("objdump does not have RISC-V 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, "-M numeric", "-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 := bytes.Index(line, []byte(":\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
+}
+
+// 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]
+}
+
+func parseContinuation(line []byte, enc []byte) []byte {
+	i := bytes.Index(line, []byte(":\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_RISCV),
+		Version:   1,
+		Entry:     start,
+		Phoff:     uint64(off1),
+		Shoff:     uint64(off2),
+		Flags:     0x5,
+		Ehsize:    uint16(off1),
+		Phentsize: uint16(off2 - off1),
+		Phnum:     1,
+		Shentsize: uint16(off3 - off2),
+		Shnum:     4,
+		Shstrndx:  3,
+	}
+	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
+	strtabsize := len("\x00.text\x00.riscv.attributes\x00.shstrtab\x00")
+	// RISC-V objdump needs the .riscv.attributes section to identify
+	// the RV64G (not include compressed) extensions.
+	sect = elf.Section64{
+		Name:      uint32(len("\x00.text\x00")),
+		Type:      uint32(0x70000003), // SHT_RISCV_ATTRIBUTES
+		Addr:      0,
+		Off:       uint64(off2 + (off3-off2)*4 + strtabsize),
+		Size:      102,
+		Addralign: 1,
+	}
+	binary.Write(&buf, binary.LittleEndian, &sect)
+	sect = elf.Section64{
+		Name:      uint32(len("\x00.text\x00.riscv.attributes\x00")),
+		Type:      uint32(elf.SHT_STRTAB),
+		Addr:      0,
+		Off:       uint64(off2 + (off3-off2)*4),
+		Size:      uint64(strtabsize),
+		Addralign: 1,
+	}
+	binary.Write(&buf, binary.LittleEndian, &sect)
+	buf.WriteString("\x00.text\x00.riscv.attributes\x00.shstrtab\x00")
+	// Contents of .riscv.attributes section
+	// which specify the extension and priv spec version. (1.11)
+	buf.WriteString("Ae\x00\x00\x00riscv\x00\x01[\x00\x00\x00\x05rv64i2p1_m2pp_a2p1_f2p2_d2p2_q2p2_zibsr2p0_zifencei2p0_zmmul1p0_zfh1p0_zfhmin1p0\x00\x08\x01\x0a\x0b")
+	f.Write(buf.Bytes())
+	return nil
+}
diff --git a/riscv64/riscv64asm/testdata/Makefile b/riscv64/riscv64asm/testdata/Makefile
new file mode 100644
index 0000000..8ac7835
--- /dev/null
+++ b/riscv64/riscv64asm/testdata/Makefile
@@ -0,0 +1,9 @@
+go test command:
+	cd ..; go generate
+	cd ..; go test -run 'ObjdumpRISCV64TestGUNSyntaxdata' -v -timeout 10h 2>&1 | tee -a log
+	cd ..; go test -run 'ObjdumpRISCV64TestGoSyntaxdata' -v -timeout 10h 2>&1 | tee -a log
+	cd ..; go test -run 'ObjdumpRISCV64' -v -timeout 10h 2>&1 | tee -a log
+	cd ..; go test -run 'ObjdumpRISCV64Manual' -v -timeout 10h 2>&1 | tee -a log
+	cd ..; go test -run 'TestDecodeGNUSyntax'
+	cd ..; go test -run 'TestDecodeGoSyntax'
+	cd ..; go test -run '.*'
diff --git a/riscv64/riscv64asm/testdata/gnucases.txt b/riscv64/riscv64asm/testdata/gnucases.txt
new file mode 100644
index 0000000..dad05a7
--- /dev/null
+++ b/riscv64/riscv64asm/testdata/gnucases.txt
@@ -0,0 +1,390 @@
+b3027300|	add x5,x6,x7
+9302f3ff|	addi x5,x6,-1
+9302f37f|	addi x5,x6,2047
+1305a000|	li x10,10
+13000000|	nop
+93870900|	mv x15,x19
+9b02f37f|	addiw x5,x6,2047
+1b830a00|	sext.w x6,x21
+bb027300|	addw x5,x6,x7
+afb26300|	amoadd.d x5,x6,(x7)
+afb26304|	amoadd.d.aq x5,x6,(x7)
+afb26302|	amoadd.d.rl x5,x6,(x7)
+afa26300|	amoadd.w x5,x6,(x7)
+afa26304|	amoadd.w.aq x5,x6,(x7)
+afa26302|	amoadd.w.rl x5,x6,(x7)
+afb26360|	amoand.d x5,x6,(x7)
+afb26364|	amoand.d.aq x5,x6,(x7)
+afb26362|	amoand.d.rl x5,x6,(x7)
+afa26360|	amoand.w x5,x6,(x7)
+afa26364|	amoand.w.aq x5,x6,(x7)
+afa26362|	amoand.w.rl x5,x6,(x7)
+afb263e0|	amomaxu.d x5,x6,(x7)
+afb263e4|	amomaxu.d.aq x5,x6,(x7)
+afb263e2|	amomaxu.d.rl x5,x6,(x7)
+afa263e0|	amomaxu.w x5,x6,(x7)
+afa263e4|	amomaxu.w.aq x5,x6,(x7)
+afa263e2|	amomaxu.w.rl x5,x6,(x7)
+afb263a0|	amomax.d x5,x6,(x7)
+afb263a4|	amomax.d.aq x5,x6,(x7)
+afb263a2|	amomax.d.rl x5,x6,(x7)
+afa263a0|	amomax.w x5,x6,(x7)
+afa263a4|	amomax.w.aq x5,x6,(x7)
+afa263a2|	amomax.w.rl x5,x6,(x7)
+afb263c0|	amominu.d x5,x6,(x7)
+afb263c4|	amominu.d.aq x5,x6,(x7)
+afb263c2|	amominu.d.rl x5,x6,(x7)
+afa263c0|	amominu.w x5,x6,(x7)
+afa263c4|	amominu.w.aq x5,x6,(x7)
+afa263c2|	amominu.w.rl x5,x6,(x7)
+afb26380|	amomin.d x5,x6,(x7)
+afb26384|	amomin.d.aq x5,x6,(x7)
+afb26382|	amomin.d.rl x5,x6,(x7)
+afa26380|	amomin.w x5,x6,(x7)
+afa26384|	amomin.w.aq x5,x6,(x7)
+afa26382|	amomin.w.rl x5,x6,(x7)
+afb26340|	amoor.d x5,x6,(x7)
+afb26344|	amoor.d.aq x5,x6,(x7)
+afb26342|	amoor.d.rl x5,x6,(x7)
+afa26340|	amoor.w x5,x6,(x7)
+afa26344|	amoor.w.aq x5,x6,(x7)
+afa26342|	amoor.w.rl x5,x6,(x7)
+afb26308|	amoswap.d x5,x6,(x7)
+afb2630c|	amoswap.d.aq x5,x6,(x7)
+afb2630a|	amoswap.d.rl x5,x6,(x7)
+afa26308|	amoswap.w x5,x6,(x7)
+afa2630c|	amoswap.w.aq x5,x6,(x7)
+afa2630a|	amoswap.w.rl x5,x6,(x7)
+afb26320|	amoxor.d x5,x6,(x7)
+afb26324|	amoxor.d.aq x5,x6,(x7)
+afb26322|	amoxor.d.rl x5,x6,(x7)
+afa26320|	amoxor.w x5,x6,(x7)
+afa26324|	amoxor.w.aq x5,x6,(x7)
+afa26322|	amoxor.w.rl x5,x6,(x7)
+b3727300|	and x5,x6,x7
+9372f3ff|	andi x5,x6,-1
+9372f37f|	andi x5,x6,2047
+97020000|	auipc x5,0x0
+97028000|	auipc x5,0x800
+e38062f0|	beq x5,x6,-256
+e3de62ee|	bge x5,x6,-260
+e3fc62ee|	bgeu x5,x6,-264
+e3ca62ee|	blt x5,x6,-268
+e3e862ee|	bltu x5,x6,-272
+e39662ee|	bne x5,x6,-276
+63940200|	bnez x5,8
+63c40400|	bltz x9,8
+63447000|	bgtz x7,8
+63d40900|	bgez x19,8
+6354d001|	blez x29,8
+63040800|	beqz x16,8
+f33213c0|	csrrc x5,time,x6
+f3f21fc0|	csrrci x5,time,31
+f32213c0|	csrrs x5,time,x6
+f3e21fc0|	csrrsi x5,time,31
+f31213c0|	csrrw x5,time,x6
+f3d21fc0|	csrrwi x5,time,31
+733015c0|	csrc time,x10
+73f010c0|	csrci time,1
+73253000|	frcsr x10
+f3251000|	frflags x11
+73262000|	frrm x12
+f32400c0|	rdcycle x9
+732920c0|	rdinstret x18
+f32910c0|	rdtime x19
+f3224014|	csrr x5,sip
+73201bc0|	csrs time,x22
+736014c8|	csrsi timeh,8
+73903700|	fscsr x15
+73101800|	fsflags x16
+73902800|	fsrm x17
+731014c0|	csrw time,x8
+735016c8|	csrwi timeh,12
+b3427302|	div x5,x6,x7
+b3527302|	divu x5,x6,x7
+bb527302|	divuw x5,x6,x7
+bb427302|	divw x5,x6,x7
+73001000|	ebreak
+73000000|	ecall
+0f00f00f|	fence
+53f02002|	fadd.d f0,f1,f2
+53f02004|	fadd.h f0,f1,f2
+53f02006|	fadd.q f0,f1,f2
+53f02000|	fadd.s f0,f1,f2
+d31200e2|	fclass.d x5,f0
+d31200e4|	fclass.h x5,f0
+d31200e6|	fclass.q x5,f0
+d31200e0|	fclass.s x5,f0
+53f022d2|	fcvt.d.l f0,x5
+53f032d2|	fcvt.d.lu f0,x5
+53f03042|	fcvt.d.q f0,f1
+53800042|	fcvt.d.s f0,f1
+538002d2|	fcvt.d.w f0,x5
+538012d2|	fcvt.d.wu f0,x5
+53f022d4|	fcvt.h.l f0,x5
+53f032d4|	fcvt.h.lu f0,x5
+53f00044|	fcvt.h.s f0,f1
+53f002d4|	fcvt.h.w f0,x5
+53f012d4|	fcvt.h.wu f0,x5
+d37230c2|	fcvt.lu.d x5,f0
+d37230c4|	fcvt.lu.h x5,f0
+d37230c6|	fcvt.lu.q x5,f0
+d37230c0|	fcvt.lu.s x5,f0
+d37220c2|	fcvt.l.d x5,f0
+d37220c4|	fcvt.l.h x5,f0
+d37220c6|	fcvt.l.q x5,f0
+d37220c0|	fcvt.l.s x5,f0
+53801046|	fcvt.q.d f0,f1
+538022d6|	fcvt.q.l f0,x5
+538032d6|	fcvt.q.lu f0,x5
+53800046|	fcvt.q.s f0,f1
+538002d6|	fcvt.q.w f0,x5
+538012d6|	fcvt.q.wu f0,x5
+53f01040|	fcvt.s.d f0,f1
+53802040|	fcvt.s.h f0,f1
+53f022d0|	fcvt.s.l f0,x5
+53f032d0|	fcvt.s.lu f0,x5
+53f03040|	fcvt.s.q f0,f1
+53f002d0|	fcvt.s.w f0,x5
+53f012d0|	fcvt.s.wu f0,x5
+d37210c2|	fcvt.wu.d x5,f0
+d37210c4|	fcvt.wu.h x5,f0
+d37210c6|	fcvt.wu.q x5,f0
+d37210c0|	fcvt.wu.s x5,f0
+d37200c2|	fcvt.w.d x5,f0
+d37200c4|	fcvt.w.h x5,f0
+d37200c6|	fcvt.w.q x5,f0
+d37200c0|	fcvt.w.s x5,f0
+53f0201a|	fdiv.d f0,f1,f2
+53f0201c|	fdiv.h f0,f1,f2
+53f0201e|	fdiv.q f0,f1,f2
+53f02018|	fdiv.s f0,f1,f2
+0f00f00f|	fence
+0f100000|	fence.i
+d32210a2|	feq.d x5,f0,f1
+d32210a4|	feq.h x5,f0,f1
+d32210a6|	feq.q x5,f0,f1
+d32210a0|	feq.s x5,f0,f1
+07b0f27f|	fld f0,2047(x5)
+d30210a2|	fle.d x5,f0,f1
+d30210a4|	fle.h x5,f0,f1
+d30210a6|	fle.q x5,f0,f1
+d30210a0|	fle.s x5,f0,f1
+0790f27f|	flh f0,2047(x5)
+07c0f27f|	flq f0,2047(x5)
+d31210a2|	flt.d x5,f0,f1
+d31210a4|	flt.h x5,f0,f1
+d31210a6|	flt.q x5,f0,f1
+d31210a0|	flt.s x5,f0,f1
+07a0f27f|	flw f0,2047(x5)
+43f0201a|	fmadd.d f0,f1,f2,f3
+43f0201c|	fmadd.h f0,f1,f2,f3
+43f0201e|	fmadd.q f0,f1,f2,f3
+43f02018|	fmadd.s f0,f1,f2,f3
+5390202a|	fmax.d f0,f1,f2
+5390202c|	fmax.h f0,f1,f2
+5390202e|	fmax.q f0,f1,f2
+53902028|	fmax.s f0,f1,f2
+5380202a|	fmin.d f0,f1,f2
+5380202c|	fmin.h f0,f1,f2
+5380202e|	fmin.q f0,f1,f2
+53802028|	fmin.s f0,f1,f2
+47f0201a|	fmsub.d f0,f1,f2,f3
+47f0201c|	fmsub.h f0,f1,f2,f3
+47f0201e|	fmsub.q f0,f1,f2,f3
+47f02018|	fmsub.s f0,f1,f2,f3
+53f02012|	fmul.d f0,f1,f2
+53f02014|	fmul.h f0,f1,f2
+53f02016|	fmul.q f0,f1,f2
+53f02010|	fmul.s f0,f1,f2
+538002f2|	fmv.d.x f0,x5
+538002f4|	fmv.h.x f0,x5
+d30200e2|	fmv.x.d x5,f0
+d30200e4|	fmv.x.h x5,f0
+d30200e0|	fmv.x.w x5,f0
+4ff0201a|	fnmadd.d f0,f1,f2,f3
+4ff0201c|	fnmadd.h f0,f1,f2,f3
+4ff0201e|	fnmadd.q f0,f1,f2,f3
+4ff02018|	fnmadd.s f0,f1,f2,f3
+4bf0201a|	fnmsub.d f0,f1,f2,f3
+4bf0201c|	fnmsub.h f0,f1,f2,f3
+4bf0201e|	fnmsub.q f0,f1,f2,f3
+4bf02018|	fnmsub.s f0,f1,f2,f3
+a7bf027e|	fsd f0,2047(x5)
+53902022|	fsgnjn.d f0,f1,f2
+53902024|	fsgnjn.h f0,f1,f2
+53902026|	fsgnjn.q f0,f1,f2
+53902020|	fsgnjn.s f0,f1,f2
+53a02022|	fsgnjx.d f0,f1,f2
+53a02024|	fsgnjx.h f0,f1,f2
+53a02026|	fsgnjx.q f0,f1,f2
+53a02020|	fsgnjx.s f0,f1,f2
+53802022|	fsgnj.d f0,f1,f2
+53802024|	fsgnj.h f0,f1,f2
+53802026|	fsgnj.q f0,f1,f2
+53802020|	fsgnj.s f0,f1,f2
+53a01022|	fabs.d f0,f1
+53a49420|	fabs.s f8,f9
+d305c622|	fmv.d f11,f12
+d306e720|	fmv.s f13,f14
+d3170823|	fneg.d f15,f16
+d398f720|	fneg.s f17,f15
+a79f027e|	fsh f0,2047(x5)
+a7cf027e|	fsq f0,2047(x5)
+53f0005a|	fsqrt.d f0,f1
+53f0005c|	fsqrt.h f0,f1
+53f0005e|	fsqrt.q f0,f1
+53f00058|	fsqrt.s f0,f1
+53f0200a|	fsub.d f0,f1,f2
+53f0200c|	fsub.h f0,f1,f2
+53f0200e|	fsub.q f0,f1,f2
+53f02008|	fsub.s f0,f1,f2
+a7af027e|	fsw f0,2047(x5)
+6ff0dfcb|	j -836
+eff09fcb|	jal -840
+eff25fcb|	jal x5,-844
+67800200|	jr x5
+e7800202|	jalr x1,32(x5)
+67800000|	ret
+6700a500|	jr 10(x10)
+8302f37f|	lb x5,2047(x6)
+8342f37f|	lbu x5,2047(x6)
+af320310|	lr.d x5,(x6)
+af320314|	lr.d.aq x5,(x6)
+af320312|	lr.d.rl x5,(x6)
+af220310|	lr.w x5,(x6)
+af220314|	lr.w.aq x5,(x6)
+af220312|	lr.w.rl x5,(x6)
+b7829102|	lui x5,0x2918
+8322f37f|	lw x5,2047(x6)
+8362f37f|	lwu x5,2047(x6)
+b3027302|	mul x5,x6,x7
+b3127302|	mulh x5,x6,x7
+b3227302|	mulhsu x5,x6,x7
+b3327302|	mulhu x5,x6,x7
+bb027302|	mulw x5,x6,x7
+b3627300|	or x5,x6,x7
+93620380|	ori x5,x6,-2048
+b3627302|	rem x5,x6,x7
+b3727302|	remu x5,x6,x7
+bb627302|	remw x5,x6,x7
+a30f537e|	sb x5,2047(x6)
+afb26318|	sc.d x5,x6,(x7)
+afb2631c|	sc.d.aq x5,x6,(x7)
+afb2631a|	sc.d.rl x5,x6,(x7)
+afa26318|	sc.w x5,x6,(x7)
+afa2631c|	sc.w.aq x5,x6,(x7)
+afa2631a|	sc.w.rl x5,x6,(x7)
+a33f537e|	sd x5,2047(x6)
+23105380|	sh x5,-2048(x6)
+b3127300|	sll x5,x6,x7
+93124303|	slli x5,x6,0x34
+9b127301|	slliw x5,x6,0x17
+b3227300|	slt x5,x6,x7
+b3226000|	sgtz x5,x6
+b32e0f00|	sltz x29,x30
+9322f37f|	slti x5,x6,2047
+93320380|	sltiu x5,x6,-2048
+93321300|	seqz x5,x6
+b3327300|	sltu x5,x6,x7
+33394001|	snez x18,x20
+b3527340|	sra x5,x6,x7
+93524343|	srai x5,x6,0x34
+9b526341|	sraiw x5,x6,0x16
+bb527340|	sraw x5,x6,x7
+b3527300|	srl x5,x6,x7
+93524303|	srli x5,x6,0x34
+9b526301|	srliw x5,x6,0x16
+bb527300|	srlw x5,x6,x7
+b3027340|	sub x5,x6,x7
+b3026040|	neg x5,x6
+bb027340|	subw x5,x6,x7
+3b0ff041|	negw x30,x31
+a32f537e|	sw x5,2047(x6)
+b3427300|	xor x5,x6,x7
+9342f37f|	xori x5,x6,2047
+93c2ffff|	not x5,x31
+bb003108|	add.uw x1,x2,x3
+33a26220|	sh1add x4,x5,x6
+bb239420|	sh1add.uw x7,x8,x9
+33c5c520|	sh2add x10,x11,x12
+bb46f720|	sh2add.uw x13,x14,x15
+33e82821|	sh3add x16,x17,x18
+bb695a21|	sh3add.uw x19,x20,x21
+1b9b7b09|	slli.uw x22,x23,0x17
+33fcac41|	andn x24,x25,x26
+b36dde41|	orn x27,x28,x29
+33cf1f40|	xnor x30,x31,x1
+13910160|	clz x2,x3
+1b920260|	clzw x4,x5
+13931360|	ctz x6,x7
+1b941460|	ctzw x8,x9
+13952560|	cpop x10,x11
+1b962660|	cpopw x12,x13
+33e7070b|	max x14,x15,x16
+b378390b|	maxu x17,x18,x19
+33ca6a0b|	min x20,x21,x22
+b35b9c0b|	minu x23,x24,x25
+139d4d60|	sext.b x26,x27
+139e5e60|	sext.h x28,x29
+3bcf0f08|	zext.h x30,x31
+b3102060|	rol x1,x0,x2
+bb115260|	rolw x3,x4,x5
+33d38360|	ror x6,x7,x8
+9354a560|	rori x9,x10,0xa
+9b55e660|	roriw x11,x12,0xe
+bb56f760|	rorw x13,x14,x15
+13d87828|	orc.b x16,x17
+13d9896b|	rev8 x18,x19
+339a6a49|	bclr x20,x21,x22
+931bfc48|	bclri x23,x24,0xf
+b35cbd49|	bext x25,x26,x27
+13de8e48|	bexti x28,x29,0x8
+339f0f68|	binv x30,x31,x0
+9310016a|	binvi x1,x2,0x20
+b3115228|	bset x3,x4,x5
+1393f32b|	bseti x6,x7,0x3f
+4000|	addi x8,x2,4
+2041|	lw x8,64(x10)
+94d0|	sw x13,32(x9)
+0100|	nop
+811f|	addi x31,x31,-32
+4111|	addi x2,x2,-16
+8158|	li x17,-32
+4161|	addi x2,x2,16
+4163|	lui x6,0x10
+819b|	andi x15,x15,-32
+0d8c|	sub x8,x8,x11
+b18c|	xor x9,x9,x12
+558c|	or x8,x8,x13
+f98c|	and x9,x9,x14
+01a8|	j 16
+99c5|	beqz x11,14
+85e3|	bnez x15,32
+c248|	lw x17,16(x2)
+8283|	jr x7
+fa88|	mv x17,x30
+0290|	ebreak
+0295|	jalr x10
+c297|	add x15,x15,x16
+76c4|	sw x29,8(x2)
+8873|	ld x10,32(x15)
+00ea|	sd x8,16(x12)
+3d31|	addiw x2,x2,-17
+2180|	srli x8,x8,0x8
+c184|	srai x9,x9,0x10
+919d|	subw x11,x11,x12
+b99e|	addw x13,x13,x14
+4a01|	slli x2,x2,0x12
+027d|	ld x26,32(x2)
+a260|	ld x1,8(x2)
+864d|	lw x27,64(x2)
+2021|	fld f8,64(x10)
+8cb0|	fsd f11,32(x9)
+8624|	fld f9,64(x2)
+3eb0|	fsd f15,32(x2)
+0000|	unimp
+ab|	illegalins
+f3|	illegalins
+abc3|	illegalins
+abcde3|	illegalins
diff --git a/riscv64/riscv64asm/testdata/plan9cases.txt b/riscv64/riscv64asm/testdata/plan9cases.txt
new file mode 100644
index 0000000..d38c5eb
--- /dev/null
+++ b/riscv64/riscv64asm/testdata/plan9cases.txt
@@ -0,0 +1,336 @@
+b3027300|	ADD X7, X6, X5
+9302f3ff|	ADDI $-1, X6, X5
+9302f37f|	ADDI $2047, X6, X5
+93870900|	MOV X19, X15
+93070100|	MOV X2, X15
+9b02f37f|	ADDIW $2047, X6, X5
+1b830a00|	MOVW X21, X6
+1b810a00|	MOVW X21, X2
+bb027300|	ADDW X7, X6, X5
+afb26300|	AMOADDD X6, (X7), X5
+afb26304|	AMOADDD X6, (X7), X5
+afb26302|	AMOADDD X6, (X7), X5
+afa26300|	AMOADDW X6, (X7), X5
+afa26304|	AMOADDW X6, (X7), X5
+afa26302|	AMOADDW X6, (X7), X5
+afb26360|	AMOANDD X6, (X7), X5
+afb26364|	AMOANDD X6, (X7), X5
+afb26362|	AMOANDD X6, (X7), X5
+afa26360|	AMOANDW X6, (X7), X5
+afa26364|	AMOANDW X6, (X7), X5
+afa26362|	AMOANDW X6, (X7), X5
+afb263e0|	AMOMAXUD X6, (X7), X5
+afb263e4|	AMOMAXUD X6, (X7), X5
+afb263e2|	AMOMAXUD X6, (X7), X5
+afa263e0|	AMOMAXUW X6, (X7), X5
+afa263e4|	AMOMAXUW X6, (X7), X5
+afa263e2|	AMOMAXUW X6, (X7), X5
+afb263a0|	AMOMAXD X6, (X7), X5
+afb263a4|	AMOMAXD X6, (X7), X5
+afb263a2|	AMOMAXD X6, (X7), X5
+afa263a0|	AMOMAXW X6, (X7), X5
+afa263a4|	AMOMAXW X6, (X7), X5
+afa263a2|	AMOMAXW X6, (X7), X5
+afb263c0|	AMOMINUD X6, (X7), X5
+afb263c4|	AMOMINUD X6, (X7), X5
+afb263c2|	AMOMINUD X6, (X7), X5
+afa263c0|	AMOMINUW X6, (X7), X5
+afa263c4|	AMOMINUW X6, (X7), X5
+afa263c2|	AMOMINUW X6, (X7), X5
+afb26380|	AMOMIND X6, (X7), X5
+afb26384|	AMOMIND X6, (X7), X5
+afb26382|	AMOMIND X6, (X7), X5
+afa26380|	AMOMINW X6, (X7), X5
+afa26384|	AMOMINW X6, (X7), X5
+afa26382|	AMOMINW X6, (X7), X5
+afb26340|	AMOORD X6, (X7), X5
+afb26344|	AMOORD X6, (X7), X5
+afb26342|	AMOORD X6, (X7), X5
+afa26340|	AMOORW X6, (X7), X5
+afa26344|	AMOORW X6, (X7), X5
+afa26342|	AMOORW X6, (X7), X5
+afb26308|	AMOSWAPD X6, (X7), X5
+afb2630c|	AMOSWAPD X6, (X7), X5
+afb2630a|	AMOSWAPD X6, (X7), X5
+afa26308|	AMOSWAPW X6, (X7), X5
+afa2630c|	AMOSWAPW X6, (X7), X5
+afa2630a|	AMOSWAPW X6, (X7), X5
+afb26320|	AMOXORD X6, (X7), X5
+afb26324|	AMOXORD X6, (X7), X5
+afb26322|	AMOXORD X6, (X7), X5
+afa26320|	AMOXORW X6, (X7), X5
+afa26324|	AMOXORW X6, (X7), X5
+afa26322|	AMOXORW X6, (X7), X5
+b3727300|	AND X7, X6, X5
+9372f3ff|	ANDI $-1, X6, X5
+9372f37f|	ANDI $2047, X6, X5
+9372f30f|	MOVBU X6, X5
+97020000|	AUIPC $0, X5
+97028000|	AUIPC $2048, X5
+e38062f0|	BEQ X5, X6, -64(PC)
+e3de62ee|	BGE X5, X6, -65(PC)
+e3fc62ee|	BGEU X5, X6, -66(PC)
+e3ca62ee|	BLT X5, X6, -67(PC)
+e3e862ee|	BLTU X5, X6, -68(PC)
+e39662ee|	BNE X5, X6, -69(PC)
+e30403ee|	BEQZ X6, -70(PC)
+e35203ee|	BGEZ X6, -71(PC)
+e34003ee|	BLTZ X6, -72(PC)
+e31e03ec|	BNEZ X6, -73(PC)
+f33213c0|	CSRRC X6, TIME, X5
+f3f21fc0|	CSRRCI $31, TIME, X5
+f32213c0|	CSRRS X6, TIME, X5
+f3e21fc0|	CSRRSI $31, TIME, X5
+f31213c0|	CSRRW X6, TIME, X5
+f3d21fc0|	CSRRWI $31, TIME, X5
+733015c0|	CSRRC X10, TIME, X0
+73f010c0|	CSRRCI $1, TIME, X0
+73253000|	FRCSR X10
+f3251000|	FRFLAGS X11
+73262000|	FRRM X12
+f32400c0|	RDCYCLE X9
+732920c0|	RDINSTRET X18
+f32910c0|	RDTIME X19
+f3224014|	CSRRS X0, SIP, X5
+73201bc0|	CSRRS X22, TIME, X0
+736014c8|	CSRRSI $8, TIMEH, X0
+73903700|	FSCSR X15, X0
+73101800|	FSFLAGS X16, X0
+73902800|	FSRM X17, X0
+731014c0|	CSRRW X8, TIME, X0
+735016c8|	CSRRWI $12, TIMEH, X0
+b3427302|	DIV X7, X6, X5
+b3527302|	DIVU X7, X6, X5
+bb527302|	DIVUW X7, X6, X5
+bb427302|	DIVW X7, X6, X5
+73001000|	EBREAK
+73000000|	ECALL
+53f02002|	FADDD F2, F1, F0
+53f02004|	FADDH F2, F1, F0
+53f02006|	FADDQ F2, F1, F0
+53f02000|	FADDS F2, F1, F0
+d31200e2|	FCLASSD F0, X5
+d31200e4|	FCLASSH F0, X5
+d31200e6|	FCLASSQ F0, X5
+d31200e0|	FCLASSS F0, X5
+53f022d2|	FCVTDL X5, F0
+53f032d2|	FCVTDLU X5, F0
+53f03042|	FCVTDQ F1, F0
+53800042|	FCVTDS F1, F0
+538002d2|	FCVTDW X5, F0
+538012d2|	FCVTDWU X5, F0
+53f022d4|	FCVTHL X5, F0
+53f032d4|	FCVTHLU X5, F0
+53f00044|	FCVTHS F1, F0
+53f002d4|	FCVTHW X5, F0
+53f012d4|	FCVTHWU X5, F0
+d37230c2|	FCVTLUD F0, X5
+d37230c4|	FCVTLUH F0, X5
+d37230c6|	FCVTLUQ F0, X5
+d37230c0|	FCVTLUS F0, X5
+d37220c2|	FCVTLD F0, X5
+d37220c4|	FCVTLH F0, X5
+d37220c6|	FCVTLQ F0, X5
+d37220c0|	FCVTLS F0, X5
+53801046|	FCVTQD F1, F0
+538022d6|	FCVTQL X5, F0
+538032d6|	FCVTQLU X5, F0
+53800046|	FCVTQS F1, F0
+538002d6|	FCVTQW X5, F0
+538012d6|	FCVTQWU X5, F0
+53f01040|	FCVTSD F1, F0
+53802040|	FCVTSH F1, F0
+53f022d0|	FCVTSL X5, F0
+53f032d0|	FCVTSLU X5, F0
+53f03040|	FCVTSQ F1, F0
+53f002d0|	FCVTSW X5, F0
+53f012d0|	FCVTSWU X5, F0
+d37210c2|	FCVTWUD F0, X5
+d37210c4|	FCVTWUH F0, X5
+d37210c6|	FCVTWUQ F0, X5
+d37210c0|	FCVTWUS F0, X5
+d37200c2|	FCVTWD F0, X5
+d37200c4|	FCVTWH F0, X5
+d37200c6|	FCVTWQ F0, X5
+d37200c0|	FCVTWS F0, X5
+53f0201a|	FDIVD F2, F1, F0
+53f0201c|	FDIVH F2, F1, F0
+53f0201e|	FDIVQ F2, F1, F0
+53f02018|	FDIVS F2, F1, F0
+0f00f00f|	FENCE
+0f100000|	FENCEI
+d32210a2|	FEQD F1, F0, X5
+d32210a4|	FEQH F1, F0, X5
+d32210a6|	FEQQ F1, F0, X5
+d32210a0|	FEQS F1, F0, X5
+07b0f27f|	MOVD F0, 2047(X5)
+d30210a2|	FLED F1, F0, X5
+d30210a4|	FLEH F1, F0, X5
+d30210a6|	FLEQ F1, F0, X5
+d30210a0|	FLES F1, F0, X5
+0790f27f|	FLH 2047(X5), F0
+07c0f27f|	FLQ 2047(X5), F0
+d31210a2|	FLTD F1, F0, X5
+d31210a4|	FLTH F1, F0, X5
+d31210a6|	FLTQ F1, F0, X5
+d31210a0|	FLTS F1, F0, X5
+07a0f27f|	MOVF F0, 2047(X5)
+43f0201a|	FMADDD F1, F2, F3, F0
+43f0201c|	FMADDH F1, F2, F3, F0
+43f0201e|	FMADDQ F1, F2, F3, F0
+43f02018|	FMADDS F1, F2, F3, F0
+5390202a|	FMAXD F2, F1, F0
+5390202c|	FMAXH F2, F1, F0
+5390202e|	FMAXQ F2, F1, F0
+53902028|	FMAXS F2, F1, F0
+5380202a|	FMIND F2, F1, F0
+5380202c|	FMINH F2, F1, F0
+5380202e|	FMINQ F2, F1, F0
+53802028|	FMINS F2, F1, F0
+47f0201a|	FMSUBD F1, F2, F3, F0
+47f0201c|	FMSUBH F1, F2, F3, F0
+47f0201e|	FMSUBQ F1, F2, F3, F0
+47f02018|	FMSUBS F1, F2, F3, F0
+53f02012|	FMULD F2, F1, F0
+53f02014|	FMULH F2, F1, F0
+53f02016|	FMULQ F2, F1, F0
+53f02010|	FMULS F2, F1, F0
+538002f2|	FMVDX X5, F0
+538002f4|	FMVHX X5, F0
+d30200e2|	FMVXD F0, X5
+d30200e4|	FMVXH F0, X5
+d30200e0|	FMVXW F0, X5
+4ff0201a|	FNMADDD F1, F2, F3, F0
+4ff0201c|	FNMADDH F1, F2, F3, F0
+4ff0201e|	FNMADDQ F1, F2, F3, F0
+4ff02018|	FNMADDS F1, F2, F3, F0
+4bf0201a|	FNMSUBD F1, F2, F3, F0
+4bf0201c|	FNMSUBH F1, F2, F3, F0
+4bf0201e|	FNMSUBQ F1, F2, F3, F0
+4bf02018|	FNMSUBS F1, F2, F3, F0
+a7bf027e|	MOVD 2047(X5), F0
+53902022|	FSGNJND F2, F1, F0
+53902024|	FSGNJNH F2, F1, F0
+53902026|	FSGNJNQ F2, F1, F0
+53902020|	FSGNJNS F2, F1, F0
+53a02022|	FSGNJXD F2, F1, F0
+53a02024|	FSGNJXH F2, F1, F0
+53a02026|	FSGNJXQ F2, F1, F0
+53a02020|	FSGNJXS F2, F1, F0
+53802022|	FSGNJD F2, F1, F0
+53802024|	FSGNJH F2, F1, F0
+53802026|	FSGNJQ F2, F1, F0
+53802020|	FSGNJS F2, F1, F0
+a79f027e|	FSH 2047(X5), F0
+a7cf027e|	FSQ 2047(X5), F0
+53f0005a|	FSQRTD F1, F0
+53f0005c|	FSQRTH F1, F0
+53f0005e|	FSQRTQ F1, F0
+53f00058|	FSQRTS F1, F0
+53f0200a|	FSUBD F2, F1, F0
+53f0200c|	FSUBH F2, F1, F0
+53f0200e|	FSUBQ F2, F1, F0
+53f02008|	FSUBS F2, F1, F0
+a7af027e|	MOVF 2047(X5), F0
+6ff0dfcb|	JMP -209(PC)
+eff09fcb|	CALL -210(PC)
+eff25fcb|	JAL X5, -211(PC)
+67800202|	JMP 32(X5)
+e7800202|	CALL 32(X5)
+e7820202|	JALR X5, 32(X5)
+67800000|	RET
+8302f37f|	MOVB 2047(X6), X5
+8342f37f|	MOVBU 2047(X6), X5
+af320310|	LRD (X6), X5
+af320314|	LRD (X6), X5
+af320312|	LRD (X6), X5
+af220310|	LRW (X6), X5
+af220314|	LRW (X6), X5
+af220312|	LRW (X6), X5
+b7829102|	LUI $10520, X5
+8322f37f|	MOVW 2047(X6), X5
+8362f37f|	MOVWU 2047(X6), X5
+b3027302|	MUL X7, X6, X5
+b3127302|	MULH X7, X6, X5
+b3227302|	MULHSU X7, X6, X5
+b3327302|	MULHU X7, X6, X5
+bb027302|	MULW X7, X6, X5
+b3627300|	OR X7, X6, X5
+93620380|	ORI $-2048, X6, X5
+b3627302|	REM X7, X6, X5
+b3727302|	REMU X7, X6, X5
+bb627302|	REMW X7, X6, X5
+a30f537e|	MOVB X5, 2047(X6)
+afb26318|	SCD X6, (X7), X5
+afb2631c|	SCD X6, (X7), X5
+afb2631a|	SCD X6, (X7), X5
+afa26318|	SCW X6, (X7), X5
+afa2631c|	SCW X6, (X7), X5
+afa2631a|	SCW X6, (X7), X5
+a33f537e|	MOV X5, 2047(X6)
+23105380|	MOVH X5, -2048(X6)
+b3127300|	SLL X7, X6, X5
+93124303|	SLLI $52, X6, X5
+9b127301|	SLLIW $23, X6, X5
+b3227300|	SLT X7, X6, X5
+9322f37f|	SLTI $2047, X6, X5
+93320380|	SLTIU $-2048, X6, X5
+93321300|	SEQZ X6, X5
+b3327300|	SLTU X7, X6, X5
+33394001|	SNEZ X20, X18
+b3527340|	SRA X7, X6, X5
+93524343|	SRAI $52, X6, X5
+9b526341|	SRAIW $22, X6, X5
+bb527340|	SRAW X7, X6, X5
+b3527300|	SRL X7, X6, X5
+93524303|	SRLI $52, X6, X5
+9b526301|	SRLIW $22, X6, X5
+bb527300|	SRLW X7, X6, X5
+b3027340|	SUB X7, X6, X5
+b3026040|	NEG X6, X5
+bb027340|	SUBW X7, X6, X5
+a32f537e|	MOVW X5, 2047(X6)
+b3427300|	XOR X7, X6, X5
+9342f37f|	XORI $2047, X6, X5
+93c2ffff|	NOT X31, X5
+bb003108|	ADDUW X3, X2, X1
+33a26220|	SH1ADD X6, X5, X4
+bb239420|	SH1ADDUW X9, X8, X7
+33c5c520|	SH2ADD X12, X11, X10
+bb46f720|	SH2ADDUW X15, X14, X13
+33e82821|	SH3ADD X18, X17, X16
+bb695a21|	SH3ADDUW X21, X20, X19
+1b9b7b09|	SLLIUW $23, X23, X22
+33fcac41|	ANDN X26, X25, X24
+b36dde41|	ORN X29, X28, X27
+33cf1f40|	XNOR X1, X31, X30
+13910160|	CLZ X3, X2
+1b920260|	CLZW X5, X4
+13931360|	CTZ X7, X6
+1b941460|	CTZW X9, X8
+13952560|	CPOP X11, X10
+1b962660|	CPOPW X13, X12
+33e7070b|	MAX X16, X15, X14
+b378390b|	MAXU X19, X18, X17
+33ca6a0b|	MIN X22, X21, X20
+b35b9c0b|	MINU X25, X24, X23
+139d4d60|	SEXTB X27, X26
+139e5e60|	SEXTH X29, X28
+3bcf0f08|	ZEXTH X31, X30
+b3102060|	ROL X2, X0, X1
+bb115260|	ROLW X5, X4, X3
+33d38360|	ROR X8, X7, X6
+9354a560|	RORI $10, X10, X9
+9b55e660|	RORIW $14, X12, X11
+bb56f760|	RORW X15, X14, X13
+13d87828|	ORCB X17, X16
+13d9896b|	REV8 X19, X18
+339a6a49|	BCLR X22, X21, X20
+931bfc48|	BCLRI $15, X24, X23
+b35cbd49|	BEXT X27, X26, X25
+13de8e48|	BEXTI $8, X29, X28
+339f0f68|	BINV X0, X31, X30
+9310016a|	BINVI $32, X2, X1
+b3115228|	BSET X5, X4, X3
+1393f32b|	BSETI $63, X7, X6
+0000|	UNIMP