diff options
author | jmcp <none@none> | 2007-10-06 21:54:53 -0700 |
---|---|---|
committer | jmcp <none@none> | 2007-10-06 21:54:53 -0700 |
commit | a2bb96e7d59f447f59bc306e53b7d00e38594667 (patch) | |
tree | 09c5ca44950597254e27400404bf5d67a1f08c50 /usr/src/lib/libdisasm | |
parent | 1d76b12554f7e16caa5910206315015445313940 (diff) | |
download | illumos-joyent-a2bb96e7d59f447f59bc306e53b7d00e38594667.tar.gz |
PSARC 2007/507 Unencumbered libdisasm for Sparc
6596739 need non-encumbered libdisasm for sparc
6396410 Update dis for preferred assembly language syntax
6193412 Support for new Olympus B/C instructions needed in disassemblers
Code contributed by Jason Brian King <jason@ansipunx.net>
4751282 fp conversion ops decode registers incorrectly
4767086 fmovrq registers decoded wrong
4767091 pixel compare source registers decoded wrong
4767154 Registers for fmul8x16, fmul8sux16, fmul8ulx16 decoded wrong.
4658958 dis misrepresents invalid opcodes
Diffstat (limited to 'usr/src/lib/libdisasm')
-rw-r--r-- | usr/src/lib/libdisasm/Makefile | 7 | ||||
-rw-r--r-- | usr/src/lib/libdisasm/Makefile.com | 7 | ||||
-rw-r--r-- | usr/src/lib/libdisasm/common/libdisasm.h | 1 | ||||
-rw-r--r-- | usr/src/lib/libdisasm/common/linktest_stand.c | 3 | ||||
-rw-r--r-- | usr/src/lib/libdisasm/sparc/Makefile | 38 | ||||
-rw-r--r-- | usr/src/lib/libdisasm/sparc/dis_sparc.c | 339 | ||||
-rw-r--r-- | usr/src/lib/libdisasm/sparc/dis_sparc.h | 109 | ||||
-rw-r--r-- | usr/src/lib/libdisasm/sparc/dis_sparc_fmt.c | 2422 | ||||
-rw-r--r-- | usr/src/lib/libdisasm/sparc/dis_sparc_fmt.h | 124 | ||||
-rw-r--r-- | usr/src/lib/libdisasm/sparc/instr.c | 1625 | ||||
-rw-r--r-- | usr/src/lib/libdisasm/sparcv9/Makefile | 39 |
11 files changed, 4706 insertions, 8 deletions
diff --git a/usr/src/lib/libdisasm/Makefile b/usr/src/lib/libdisasm/Makefile index 69dbd89f35..fbff822dc2 100644 --- a/usr/src/lib/libdisasm/Makefile +++ b/usr/src/lib/libdisasm/Makefile @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -30,9 +30,8 @@ include ../Makefile.lib HDRS= libdisasm.h HDRDIR= common -$(INTEL_BLD)SUBDIRS= $(MACH) -$(INTEL_BLD)$(BUILD64)SUBDIRS += $(MACH64) -$(CLOSED_BUILD)SUBDIRS += $(CLOSED)/lib/libdisasm +SUBDIRS= $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) all := TARGET = all clean := TARGET = clean diff --git a/usr/src/lib/libdisasm/Makefile.com b/usr/src/lib/libdisasm/Makefile.com index 343ff60f5b..07280f6d5a 100644 --- a/usr/src/lib/libdisasm/Makefile.com +++ b/usr/src/lib/libdisasm/Makefile.com @@ -50,10 +50,11 @@ COMDIR= $(SRC)/lib/libdisasm/common # Architecture-dependent files common to both versions of libdisasm # OBJECTS_common_i386 = dis_i386.o dis_tables.o -OBJECTS_common_sparc = dis_sparc.o +OBJECTS_common_sparc = dis_sparc.o instr.o dis_sparc_fmt.o SRCS_common_i386 = $(ISASRCDIR)/dis_i386.c $(SRC)/common/dis/i386/dis_tables.c -SRCS_common_sparc = $(ISASRCDIR)/dis_sparc.c +SRCS_common_sparc = $(ISASRCDIR)/dis_sparc.c $(ISASRCDIR)/instr.c \ + $(ISASRCDIR)/dis_sparc_fmt.c # # Architecture-independent files common to both version of libdisasm @@ -112,7 +113,7 @@ STAND_RENAMED_FUNCS= \ snprintf CPPFLAGS_standalone = -DDIS_STANDALONE $(STAND_RENAMED_FUNCS:%=-D%=mdb_%) \ - -I$(SRC)/cmd/mdb/common + -Dvsnprintf=mdb_iob_vsnprintf -I$(SRC)/cmd/mdb/common CPPFLAGS_library = -D_REENTRANT CPPFLAGS += -I$(COMDIR) $(CPPFLAGS_$(CURTYPE)) diff --git a/usr/src/lib/libdisasm/common/libdisasm.h b/usr/src/lib/libdisasm/common/libdisasm.h index 3ecdea0860..bcd7318cd1 100644 --- a/usr/src/lib/libdisasm/common/libdisasm.h +++ b/usr/src/lib/libdisasm/common/libdisasm.h @@ -43,6 +43,7 @@ typedef struct dis_handle dis_handle_t; #define DIS_SPARC_V8 0x01 #define DIS_SPARC_V9 0x02 #define DIS_SPARC_V9_SGI 0x04 +#define DIS_SPARC_V9_OPL 0x08 /* x86 diassembler flags (mutually exclusive) */ #define DIS_X86_SIZE16 0x08 diff --git a/usr/src/lib/libdisasm/common/linktest_stand.c b/usr/src/lib/libdisasm/common/linktest_stand.c index 88f3e2ce8b..36466b24fa 100644 --- a/usr/src/lib/libdisasm/common/linktest_stand.c +++ b/usr/src/lib/libdisasm/common/linktest_stand.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -33,6 +33,7 @@ void mdb_free(void) {} void snprintf(void) {} +void vsnprintf(void) {} void mdb_zalloc(void) {} void strcmp(void) {} void strlen(void) {} diff --git a/usr/src/lib/libdisasm/sparc/Makefile b/usr/src/lib/libdisasm/sparc/Makefile new file mode 100644 index 0000000000..1c6db3c840 --- /dev/null +++ b/usr/src/lib/libdisasm/sparc/Makefile @@ -0,0 +1,38 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" + +ISASRCDIR=. + +include ../Makefile.com + +TYPES=library standalone + +INSTALL_DEPS_library = $(ROOTLINKS) $(ROOTLINT) $(ROOTLIBS) +INSTALL_DEPS_standalone = $(ROOTLIBS) + +include ../Makefile.targ + +C99MODE = $(C99_ENABLE) diff --git a/usr/src/lib/libdisasm/sparc/dis_sparc.c b/usr/src/lib/libdisasm/sparc/dis_sparc.c new file mode 100644 index 0000000000..b9821a304c --- /dev/null +++ b/usr/src/lib/libdisasm/sparc/dis_sparc.c @@ -0,0 +1,339 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Copyright 2007 Jason King. All rights reserved. + * Use is subject to license terms. + */ + + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * The sparc disassembler is mostly straightforward, each instruction is + * represented by an inst_t structure. The inst_t definitions are organized + * into tables. The tables are correspond to the opcode maps documented in the + * various sparc architecture manuals. Each table defines the bit range of the + * instruction whose value act as an index into the array of instructions. A + * table can also refer to another table if needed. Each table also contains + * a function pointer of type format_fcn that knows how to output the + * instructions in the table, as well as handle any synthetic instructions + * + * Unfortunately, the changes from sparcv8 -> sparcv9 not only include new + * instructions, they sometimes renamed or just reused the same instruction to + * do different operations (i.e. the sparcv8 coprocessor instructions). To + * accommodate this, each table can define an overlay table. The overlay table + * is a list of (table index, architecture, new instruction definition) values. + * + * + * Traversal starts with the first table, + * get index value from the instruction + * if an relevant overlay entry exists for this index, + * grab the overlay definition + * else + * grab the definition from the array (corresponding to the index value) + * + * If the entry is an instruction, + * call print function of instruction. + * If the entry is a pointer to another table + * traverse the table + * If not valid, + * return an error + * + * + * To keep dis happy, for sparc, instead of actually returning an error, if + * the instruction cannot be disassembled, we instead merely place the value + * of the instruction into the output buffer. + * + * Adding new instructions: + * + * With the above information, it hopefully makes it clear how to add support + * for decoding new instructions. Presumably, with new instructions will come + * a new dissassembly mode (I.e. DIS_SPARC_V8, DIS_SPARC_V9, etc.). + * + * If the dissassembled format does not correspond to one of the existing + * formats, a new formatter will have to be written. The 'flags' value of + * inst_t is intended to instruct the corresponding formatter about how to + * output the instruction. + * + * If the corresponding entry in the correct table is currently unoccupied, + * simply replace the INVALID entry with the correct definition. The INST and + * TABLE macros are suggested to be used for this. If there is already an + * instruction defined, then the entry must be placed in an overlay table. If + * no overlay table exists for the instruction table, one will need to be + * created. + */ + +#include <libdisasm.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/byteorder.h> +#include <string.h> + +#include "libdisasm_impl.h" +#include "dis_sparc.h" + +static const inst_t *dis_get_overlay(dis_handle_t *, const table_t *, + uint32_t); +static uint32_t dis_get_bits(uint32_t, int, int); + +#if !defined(DIS_STANDALONE) +static void do_binary(uint32_t); +#endif /* DIS_STANDALONE */ + +dis_handle_t * +dis_handle_create(int flags, void *data, dis_lookup_f lookup_func, + dis_read_f read_func) +{ + +#if !defined(DIS_STANDALONE) + char *opt = NULL; + char *opt2, *save, *end; +#endif + dis_handle_t *dhp; + + if ((flags & (DIS_SPARC_V8|DIS_SPARC_V9|DIS_SPARC_V9_SGI)) == 0) { + (void) dis_seterrno(E_DIS_INVALFLAG); + return (NULL); + } + + if ((dhp = dis_zalloc(sizeof (struct dis_handle))) == NULL) { + (void) dis_seterrno(E_DIS_NOMEM); + return (NULL); + } + + dhp->dh_lookup = lookup_func; + dhp->dh_read = read_func; + dhp->dh_flags = flags; + dhp->dh_data = data; + dhp->dh_debug = DIS_DEBUG_COMPAT; + +#if !defined(DIS_STANDALONE) + + opt = getenv("_LIBDISASM_DEBUG"); + if (opt == NULL) + return (dhp); + + opt2 = strdup(opt); + if (opt2 == NULL) { + dis_handle_destroy(dhp); + (void) dis_seterrno(E_DIS_NOMEM); + return (NULL); + } + save = opt2; + + while (opt2 != NULL) { + end = strchr(opt2, ','); + + if (end != 0) + *end++ = '\0'; + + if (strcasecmp("synth-all", opt2) == 0) + dhp->dh_debug |= DIS_DEBUG_SYN_ALL; + + if (strcasecmp("compat", opt2) == 0) + dhp->dh_debug |= DIS_DEBUG_COMPAT; + + if (strcasecmp("synth-none", opt2) == 0) + dhp->dh_debug &= ~(DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT); + + if (strcasecmp("binary", opt2) == 0) + dhp->dh_debug |= DIS_DEBUG_PRTBIN; + + if (strcasecmp("format", opt2) == 0) + dhp->dh_debug |= DIS_DEBUG_PRTFMT; + + if (strcasecmp("all", opt2) == 0) + dhp->dh_debug = DIS_DEBUG_ALL; + + if (strcasecmp("none", opt2) == 0) + dhp->dh_debug = DIS_DEBUG_NONE; + + opt2 = end; + } + free(save); +#endif /* DIS_STANDALONE */ + return (dhp); +} + +void +dis_handle_destroy(dis_handle_t *dhp) +{ + dis_free(dhp, sizeof (dis_handle_t)); +} + +void +dis_set_data(dis_handle_t *dhp, void *data) +{ + dhp->dh_data = data; +} + +void +dis_flags_set(dis_handle_t *dhp, int f) +{ + dhp->dh_flags |= f; +} + +void +dis_flags_clear(dis_handle_t *dhp, int f) +{ + dhp->dh_flags &= ~f; +} + +/* ARGSUSED */ +int +dis_max_instrlen(dis_handle_t *dhp) +{ + return (4); +} + +/* + * The dis_i386.c comment for this says it returns the previous instruction, + * however, I'm fairly sure it's actually returning the _address_ of the + * nth previous instruction. + */ +/* ARGSUSED */ +uint64_t +dis_previnstr(dis_handle_t *dhp, uint64_t pc, int n) +{ + if (n <= 0) + return (pc); + + if (pc < n) + return (pc); + + return (pc - n*4); +} + +int +dis_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf, size_t buflen) +{ + const table_t *tp = &initial_table; + const inst_t *inp = NULL; + + uint32_t instr; + uint32_t idx = 0; + + if (dhp->dh_read(dhp->dh_data, addr, &instr, sizeof (instr)) != + sizeof (instr)) + return (-1); + + dhp->dh_buf = buf; + dhp->dh_buflen = buflen; + dhp->dh_addr = addr; + + buf[0] = '\0'; + + /* this allows sparc code to be tested on x86 */ + instr = BE_32(instr); + +#if !defined(DIS_STANDALONE) + if ((dhp->dh_debug & DIS_DEBUG_PRTBIN) != 0) + do_binary(instr); +#endif /* DIS_STANDALONE */ + + /* CONSTCOND */ + while (1) { + idx = dis_get_bits(instr, tp->tbl_field, tp->tbl_len); + inp = &tp->tbl_inp[idx]; + + inp = dis_get_overlay(dhp, tp, idx); + + if ((inp->in_type == INST_NONE) || + ((inp->in_arch & dhp->dh_flags) == 0)) + goto error; + + if (inp->in_type == INST_TBL) { + tp = inp->in_data.in_tbl; + continue; + } + + break; + } + + if (tp->tbl_fmt(dhp, instr, inp, idx) == 0) + return (0); + +error: + + (void) snprintf(buf, buflen, + ((dhp->dh_flags & DIS_OCTAL) != 0) ? "0%011lo" : "0x%08lx", + instr); + + return (0); +} + +static uint32_t +dis_get_bits(uint32_t instr, int offset, int length) +{ + uint32_t mask, val; + int i; + + for (i = 0, mask = 0; i < length; ++i) + mask |= (1UL << i); + + mask = mask << (offset - length + 1); + + val = instr & mask; + + val = val >> (offset - length + 1); + + return (val); +} + +static const inst_t * +dis_get_overlay(dis_handle_t *dhp, const table_t *tp, uint32_t idx) +{ + const inst_t *ip = &tp->tbl_inp[idx]; + int i; + + if (tp->tbl_ovp == NULL) + return (ip); + + for (i = 0; tp->tbl_ovp[i].ov_idx != -1; ++i) { + if (tp->tbl_ovp[i].ov_idx != idx) + continue; + + if ((tp->tbl_ovp[i].ov_inst.in_arch & dhp->dh_flags) == 0) + continue; + + ip = &tp->tbl_ovp[i].ov_inst; + break; + } + + return (ip); +} + +#if !defined(DIS_STANDALONE) +static void +do_binary(uint32_t instr) +{ + (void) fprintf(stderr, "DISASM: "); + prt_binary(instr, 32); + (void) fprintf(stderr, "\n"); +} +#endif /* DIS_STANDALONE */ diff --git a/usr/src/lib/libdisasm/sparc/dis_sparc.h b/usr/src/lib/libdisasm/sparc/dis_sparc.h new file mode 100644 index 0000000000..8ebeda18b7 --- /dev/null +++ b/usr/src/lib/libdisasm/sparc/dis_sparc.h @@ -0,0 +1,109 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Copyright 2007 Jason King. All rights reserved. + * Use is subject to license terms. + */ + + +#ifndef _DIS_SPARC_H +#define _DIS_SPARC_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> + +#define DIS_DEBUG_NONE 0x00L +#define DIS_DEBUG_COMPAT 0x01L +#define DIS_DEBUG_SYN_ALL 0x02L +#define DIS_DEBUG_PRTBIN 0x04L +#define DIS_DEBUG_PRTFMT 0x08L + +#define DIS_DEBUG_ALL DIS_DEBUG_SYN_ALL|DIS_DEBUG_PRTBIN|DIS_DEBUG_PRTFMT + +struct dis_handle { + void *dh_data; + dis_lookup_f dh_lookup; + dis_read_f dh_read; + int dh_flags; + + char *dh_buf; + size_t dh_buflen; + uint64_t dh_addr; + int dh_debug; +}; + +/* different types of things we can have in inst_t */ +#define INST_NONE 0x00 +#define INST_DEF 0x01 +#define INST_TBL 0x02 + +struct inst; +struct overlay; + +typedef struct inst inst_t; +typedef struct overlay overlay_t; + +typedef int (*format_fcn)(dis_handle_t *, uint32_t, const inst_t *, int); + +typedef struct table { + const struct inst *tbl_inp; + const struct overlay *tbl_ovp; + format_fcn tbl_fmt; + uint32_t tbl_field; + uint32_t tbl_len; +} table_t; + +struct inst { + int in_type; + int in_arch; + union { + struct { + const char *in_name; + uint32_t in_flags; + } in_def; + const table_t *in_tbl; + } in_data; +}; + +struct overlay { + int ov_idx; + inst_t ov_inst; +}; + +extern const table_t initial_table; + +void prt_binary(uint32_t, int); +#ifdef __cplusplus +} +#endif + +#endif /* _DIS_SPARC_H */ diff --git a/usr/src/lib/libdisasm/sparc/dis_sparc_fmt.c b/usr/src/lib/libdisasm/sparc/dis_sparc_fmt.c new file mode 100644 index 0000000000..b49c381d96 --- /dev/null +++ b/usr/src/lib/libdisasm/sparc/dis_sparc_fmt.c @@ -0,0 +1,2422 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Copyright 2007 Jason King. All rights reserved. + * Use is subject to license terms. + */ + + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/byteorder.h> +#include <stdarg.h> + +#if !defined(DIS_STANDALONE) +#include <stdio.h> +#endif /* DIS_STANDALONE */ + +#include "libdisasm.h" +#include "libdisasm_impl.h" +#include "dis_sparc.h" +#include "dis_sparc_fmt.h" + +extern char *strncpy(char *, const char *, size_t); +extern size_t strlen(const char *); +extern int strcmp(const char *, const char *); +extern int strncmp(const char *, const char *, size_t); +extern size_t strlcat(char *, const char *, size_t); +extern size_t strlcpy(char *, const char *, size_t); +extern int snprintf(char *, size_t, const char *, ...); +extern int vsnprintf(char *, size_t, const char *, va_list); + +/* + * This file has the functions that do all the dirty work of outputting the + * disassembled instruction + * + * All the non-static functions follow the format_fcn (in dis_sparc.h): + * Input: + * disassembler handle/context + * instruction to disassemble + * instruction definition pointer (inst_t *) + * index in the table of the instruction + * Return: + * 0 Success + * !0 Invalid instruction + * + * Generally, instructions found in the same table use the same output format + * or have a few minor differences (which are described in the 'flags' field + * of the instruction definition. In some cases, certain instructions differ + * radically enough from those in the same table, that their own format + * function is used. + * + * Typically each table has a unique format function defined in this file. In + * some cases (such as branches) a common one for all the tables is used. + * + * When adding support for new instructions, it is largely a judgement call + * as to when a new format function is defined. + */ + +/* The various instruction formats of a sparc instruction */ + +#if defined(_BIT_FIELDS_HTOL) +typedef struct format1 { + uint32_t op:2; + uint32_t disp30:30; +} format1_t; +#elif defined(_BIT_FIELDS_LTOH) +typedef struct format1 { + uint32_t disp30:30; + uint32_t op:2; +} format1_t; +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + +#if defined(_BIT_FIELDS_HTOL) +typedef struct format2 { + uint32_t op:2; + uint32_t rd:5; + uint32_t op2:3; + uint32_t imm22:22; +} format2_t; +#elif defined(_BIT_FIELDS_LTOH) +typedef struct format2 { + uint32_t imm22:22; + uint32_t op2:3; + uint32_t rd:5; + uint32_t op:2; +} format2_t; +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + +#if defined(_BIT_FIELDS_HTOL) +typedef struct format2a { + uint32_t op:2; + uint32_t a:1; + uint32_t cond:4; + uint32_t op2:3; + uint32_t disp22:22; +} format2a_t; +#elif defined(_BIT_FIELDS_LTOH) +typedef struct format2a { + uint32_t disp22:22; + uint32_t op2:3; + uint32_t cond:4; + uint32_t a:1; + uint32_t op:2; +} format2a_t; +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + +#if defined(_BIT_FIELDS_HTOL) +typedef struct format2b { + uint32_t op:2; + uint32_t a:1; + uint32_t cond:4; + uint32_t op2:3; + uint32_t cc:2; + uint32_t p:1; + uint32_t disp19:19; +} format2b_t; +#elif defined(_BIT_FIELDS_LTOH) +typedef struct format2b { + uint32_t disp19:19; + uint32_t p:1; + uint32_t cc:2; + uint32_t op2:3; + uint32_t cond:4; + uint32_t a:1; + uint32_t op:2; +} format2b_t; +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + +#if defined(_BIT_FIELDS_HTOL) +typedef struct format2c { + uint32_t op:2; + uint32_t a:1; + uint32_t cond:4; + uint32_t op2:3; + uint32_t d16hi:2; + uint32_t p:1; + uint32_t rs1:5; + uint32_t d16lo:14; +} format2c_t; +#elif defined(_BIT_FIELDS_LTOH) +typedef struct format2c { + uint32_t d16lo:14; + uint32_t rs1:5; + uint32_t p:1; + uint32_t d16hi:2; + uint32_t op2:3; + uint32_t cond:4; + uint32_t a:1; + uint32_t op:2; +} format2c_t; +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + +#if defined(_BIT_FIELDS_HTOL) +typedef struct format3 { + uint32_t op:2; + uint32_t rd:5; + uint32_t op3:6; + uint32_t rs1:5; + uint32_t i:1; + uint32_t asi:8; + uint32_t rs2:5; +} format3_t; +#elif defined(_BIT_FIELDS_LTOH) +typedef struct format3 { + uint32_t rs2:5; + uint32_t asi:8; + uint32_t i:1; + uint32_t rs1:5; + uint32_t op3:6; + uint32_t rd:5; + uint32_t op:2; +} format3_t; +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + +#if defined(_BIT_FIELDS_HTOL) +typedef struct format3a { + uint32_t op:2; + uint32_t rd:5; + uint32_t op3:6; + uint32_t rs1:5; + uint32_t i:1; + uint32_t simm13:13; +} format3a_t; +#elif defined(_BIT_FIELDS_LTOH) +typedef struct format3a { + uint32_t simm13:13; + uint32_t i:1; + uint32_t rs1:5; + uint32_t op3:6; + uint32_t rd:5; + uint32_t op:2; +} format3a_t; +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + +#if defined(_BIT_FIELDS_HTOL) +typedef struct format3b { + uint32_t op:2; + uint32_t rd:5; + uint32_t op3:6; + uint32_t rs1:5; + uint32_t i:1; + uint32_t x:1; + uint32_t undef:6; + uint32_t shcnt:6; +} format3b_t; +#elif defined(_BIT_FIELDS_LTOH) +typedef struct format3b { + uint32_t shcnt:6; + uint32_t undef:6; + uint32_t x:1; + uint32_t i:1; + uint32_t rs1:5; + uint32_t op3:6; + uint32_t rd:5; + uint32_t op:2; +} format3b_t; +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + +#if defined(_BIT_FIELDS_HTOL) +typedef struct format3c { + uint32_t op:2; + uint32_t rd:5; + uint32_t op3:6; + uint32_t cc2:1; + uint32_t cond:4; + uint32_t i:1; + uint32_t cc:2; + uint32_t simm11:11; +} format3c_t; +#elif defined(_BIT_FIELDS_LTOH) +typedef struct format3c { + uint32_t simm11:11; + uint32_t cc:2; + uint32_t i:1; + uint32_t cond:4; + uint32_t cc2:1; + uint32_t op3:6; + uint32_t rd:5; + uint32_t op:2; +} format3c_t; +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + +#if defined(_BIT_FIELDS_HTOL) +typedef struct format3d { + uint32_t op:2; + uint32_t rd:5; + uint32_t op3:6; + uint32_t rs1:5; + uint32_t i:1; + uint32_t rcond:3; + uint32_t simm10:10; +} format3d_t; +#elif defined(_BIT_FIELDS_LTOH) +typedef struct format3d { + uint32_t simm10:10; + uint32_t rcond:3; + uint32_t i:1; + uint32_t rs1:5; + uint32_t op3:6; + uint32_t rd:5; + uint32_t op:2; +} format3d_t; +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + +#if defined(_BIT_FIELDS_HTOL) +typedef struct formatcp { + uint32_t op:2; + uint32_t rd:5; + uint32_t op3:6; + uint32_t rs1:5; + uint32_t opc:9; + uint32_t rs2:5; +} formatcp_t; +#elif defined(_BIT_FIELDS_LTOH) +typedef struct formatcp { + uint32_t rs2:5; + uint32_t opc:9; + uint32_t rs1:5; + uint32_t op3:6; + uint32_t rd:5; + uint32_t op:2; +} formatcp_t; +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + +#if defined(_BIT_FIELDS_HTOL) +typedef struct formattcc { + uint32_t op:2; + uint32_t undef:1; + uint32_t cond:4; + uint32_t op3:6; + uint32_t rs1:5; + uint32_t i:1; + uint32_t cc:2; + uint32_t undef2:3; + uint32_t immtrap:8; +} formattcc_t; +#elif defined(_BIT_FIELDS_LTOH) +typedef struct formattcc { + uint32_t immtrap:8; + uint32_t undef2:3; + uint32_t cc:2; + uint32_t i:1; + uint32_t rs1:5; + uint32_t op3:6; + uint32_t cond:4; + uint32_t undef:1; + uint32_t op:2; +} formattcc_t; +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + +#if defined(_BIT_FIELDS_HTOL) +typedef struct formattcc2 { + uint32_t op:2; + uint32_t undef:1; + uint32_t cond:4; + uint32_t op3:6; + uint32_t rs1:5; + uint32_t i:1; + uint32_t cc:2; + uint32_t undef2:6; + uint32_t rs2:5; +} formattcc2_t; +#elif defined(_BIT_FIELDS_LTOH) +typedef struct formattcc2 { + uint32_t rs2:5; + uint32_t undef2:6; + uint32_t cc:2; + uint32_t i:1; + uint32_t rs1:5; + uint32_t op3:6; + uint32_t cond:4; + uint32_t undef:1; + uint32_t op:2; +} formattcc2_t; +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + +#if defined(_BIT_FIELDS_HTOL) +typedef struct formatmbr { + uint32_t op:2; + uint32_t rd:5; + uint32_t op3:6; + uint32_t rs1:5; + uint32_t i:1; + uint32_t undef:6; + uint32_t cmask:3; + uint32_t mmask:4; +} formatmbr_t; +#elif defined(_BIT_FIELDS_LTOH) +typedef struct formatmbr { + uint32_t mmask:4; + uint32_t cmask:3; + uint32_t undef:6; + uint32_t i:1; + uint32_t rs1:5; + uint32_t op3:6; + uint32_t rd:5; + uint32_t op:2; +} formatmbr_t; +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + +#if defined(_BIT_FIELDS_HTOL) +typedef struct formatfcmp { + uint32_t op:2; + uint32_t undef:3; + uint32_t cc:2; + uint32_t op3:6; + uint32_t rs1:5; + uint32_t opf:9; + uint32_t rs2:5; +} formatfcmp_t; +#elif defined(_BIT_FIELDS_LTOH) +typedef struct formatfcmp { + uint32_t rs2:5; + uint32_t opf:9; + uint32_t rs1:5; + uint32_t op3:6; + uint32_t cc:2; + uint32_t undef:3; + uint32_t op:2; +} formatfcmp_t; +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + +#if defined(_BIT_FIELDS_HTOL) +typedef struct formatfmov { + uint32_t op:2; + uint32_t rd:5; + uint32_t op3:6; + uint32_t undef:1; + uint32_t cond:4; + uint32_t cc:3; + uint32_t opf:6; + uint32_t rs2:5; +} formatfmov_t; +#elif defined(_BIT_FIELDS_LTOH) +typedef struct formatfmov { + uint32_t rs2:5; + uint32_t opf:6; + uint32_t cc:3; + uint32_t cond:4; + uint32_t undef:1; + uint32_t op3:6; + uint32_t rd:5; + uint32_t op:2; +} formatfmov_t; +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + +#if defined(_BIT_FIELDS_HTOL) +typedef struct formatfused { + uint32_t op:2; + uint32_t rd:5; + uint32_t op3:6; + uint32_t rs1:5; + uint32_t rs3:5; + uint32_t op5:4; + uint32_t rs2:5; +} formatfused_t; +#elif defined(_BIT_FIELDS_LTOH) +typedef struct formatfused { + uint32_t rs2:5; + uint32_t op5:4; + uint32_t rs3:5; + uint32_t rs1:5; + uint32_t op3:6; + uint32_t rd:5; + uint32_t op:2; +} formatfused_t; +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif + +typedef union ifmt { + uint32_t i; + format1_t f1; + format2_t f2; + format2a_t f2a; + format2b_t f2b; + format2c_t f2c; + format3_t f3; + format3a_t f3a; + format3b_t f3b; + format3c_t f3c; + format3d_t f3d; + formatcp_t fcp; + formattcc_t ftcc; + formattcc2_t ftcc2; + formatfcmp_t fcmp; + formatmbr_t fmb; + formatfmov_t fmv; + formatfused_t fused; +} ifmt_t; + +/* integer register names */ +static const char *reg_names[32] = { + "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7", + "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7", + "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7", + "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7" +}; + +/* floating point register names */ +static const char *freg_names[32] = { + "%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" +}; + +/* double precision register names */ +static const char *fdreg_names[32] = { + "%d0", "%d32", "%d2", "%d34", "%d4", "%d36", "%d6", "%d38", + "%d8", "%d40", "%d10", "%d42", "%d12", "%d44", "%d14", "%d46", + "%d16", "%d48", "%d18", "%d50", "%d20", "%d52", "%d22", "%d54", + "%d24", "%d56", "%d26", "%d58", "%d28", "%d60", "%d30", "%d62" +}; + +static const char *compat_fdreg_names[32] = { + "%f0", "%f32", "%f2", "%f34", "%f4", "%f36", "%f6", "%f38", + "%f8", "%f40", "%f10", "%f42", "%f12", "%f44", "%f14", "%f46", + "%f16", "%f48", "%f18", "%f50", "%f20", "%f52", "%f22", "%f54", + "%f24", "%f56", "%f26", "%f58", "%f28", "%f60", "%f30", "%f62" +}; + + +static const char *fqreg_names[32] = { + "%q0", "%q32", "%f2", "%f3", "%f4", "%q4", "%q36", "%f6", + "%f7", "%q8", "%q40", "%f10", "%f11", "%q12", "%q44", "%f14", + "%f15", "%q16", "%q48", "%f18", "%f19", "%q20", "%q52", "%f22", + "%f23", "%q24", "%q56", "%f26", "%f27", "%q28", "%q60", "%f30", +}; + + +/* coprocessor register names -- sparcv8 only */ +static const char *cpreg_names[32] = { + "%c0", "%c1", "%c2", "%c3", "%c4", "%c5", "%c6", "%c7", + "%c8", "%c9", "%c10", "%c11", "%c12", "%c13", "%c14", "%c15", + "%c16", "%c17", "%c18", "%c19", "%c20", "%c21", "%c22", "%c23", + "%c24", "%c25", "%c26", "%c27", "%c28", "%c29", "%c30", "%c31", +}; + +/* floating point condition code names */ +static const char *fcc_names[4] = { + "%fcc0", "%fcc1", "%fcc2", "%fcc3" +}; + +/* condition code names */ +static const char *icc_names[4] = { + "%icc", NULL, "%xcc", NULL +}; + +/* bitmask values for membar */ +static const char *membar_mmask[4] = { + "#LoadLoad", "#StoreLoad", "#LoadStore", "#StoreStore" +}; + +static const char *membar_cmask[3] = { + "#Lookaside", "#MemIssue", "#Sync" +}; + +/* v8 ancillary state register names */ +static const char *asr_names[32] = { + "%y", "%asr1", "%asr2", "%asr3", + "%asr4", "%asr5", "%asr6", "%asr7", + "%asr8", "%asr9", "%asr10", "%asr11", + "%asr12", "%asr13", "%asr14", "%asr15", + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL +}; +static const uint32_t asr_rdmask = 0x0000ffffL; +static const uint32_t asr_wrmask = 0x0000ffffL; + +static const char *v9_asr_names[32] = { + "%y", NULL, "%ccr", "%asi", + "%tick", "%pc", "%fprs", NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + "%pcr", "%pic", NULL, "%gsr", + "%softint_set", "%softint_clr", "%softint", "%tick_cmpr", + "%stick", "%stick_cmpr", NULL, NULL, + NULL, NULL, NULL, NULL +}; +/* + * on v9, only certain registers are valid for read or writing + * these are bitmasks corresponding to which registers are valid in which + * case + */ +static const uint32_t v9_asr_rdmask = 0x03cb007d; +static const uint32_t v9_asr_wrmask = 0x02fb004d; + +/* privledged register names on v9 */ +/* TODO: compat - NULL to %priv_nn */ +static const char *v9_privreg_names[32] = { + "%tpc", "%tnpc", "%tstate", "%tt", + "%tick", "%tba", "%pstate", "%tl", + "%pil", "%cwp", "%cansave", "%canrestore", + "%cleanwin", "%otherwin", "%wstate", "%fq", + "%gl", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, "%ver" +}; + +static const uint32_t v9_pr_rdmask = 0x80017fff; +static const uint32_t v9_pr_wrmask = 0x00017fef; + +static const char *prefetch_str[32] = { + "#n_reads", "#one_read", + "#n_writes", "#one_write", + "#page", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, "#unified", NULL, NULL, + "#n_reads_strong", "#one_read_strong", + "#n_writes_strong", "#one_write_strong", + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL +}; + +static void prt_field(const char *, uint32_t, int); + +static const char *get_regname(dis_handle_t *, int, uint32_t); +static int32_t sign_extend(int32_t, int32_t); + +static void prt_name(dis_handle_t *, const char *, int); + +#define IMM_SIGNED 0x01 /* Is immediate value signed */ +#define IMM_ADDR 0x02 /* Is immediate value part of an address */ +static void prt_imm(dis_handle_t *, uint32_t, int); + +static void prt_asi(dis_handle_t *, uint32_t); +static void prt_address(dis_handle_t *, uint32_t, int); +static void prt_aluargs(dis_handle_t *, uint32_t, uint32_t); +static void bprintf(dis_handle_t *, const char *, ...); + +/* + * print out val (which is 'bitlen' bits long) in binary + */ +#if defined(DIS_STANDALONE) +/* ARGSUSED */ +void +prt_binary(uint32_t val, int bitlen) +{ + +} + +#else + +void +prt_binary(uint32_t val, int bitlen) +{ + int i; + + for (i = bitlen - 1; i >= 0; --i) { + (void) fprintf(stderr, ((val & (1L << i)) != 0) ? "1" : "0"); + + if (i % 4 == 0 && i != 0) + (void) fprintf(stderr, " "); + } +} +#endif /* DIS_STANDALONE */ + + +/* + * print out a call instruction + * format: call address <name> + */ +/* ARGSUSED1 */ +int +fmt_call(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx) +{ + ifmt_t *f = (ifmt_t *)&instr; + + int32_t disp; + size_t curlen; + + int octal = ((dhp->dh_flags & DIS_OCTAL) != 0); + + if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) { + prt_field("op", f->f1.op, 2); + prt_field("disp30", f->f1.disp30, 30); + } + + disp = sign_extend(f->f1.disp30, 30) * 4; + + prt_name(dhp, inp->in_data.in_def.in_name, 1); + + bprintf(dhp, (octal != 0) ? "%s0%-11lo" : "%s0x%-10lx", + (disp < 0) ? "-" : "+", + (disp < 0) ? (-disp) : disp); + + (void) strlcat(dhp->dh_buf, " <", dhp->dh_buflen); + + curlen = strlen(dhp->dh_buf); + dhp->dh_lookup(dhp->dh_data, dhp->dh_addr + (int64_t)disp, + dhp->dh_buf + curlen, dhp->dh_buflen - curlen - 1, NULL, + NULL); + (void) strlcat(dhp->dh_buf, ">", dhp->dh_buflen); + + + return (0); +} + +int +fmt_sethi(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx) +{ + ifmt_t *f = (ifmt_t *)&instr; + + if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) { + prt_field("op", f->f2.op, 2); + prt_field("op2", f->f2.op2, 3); + prt_field("rd", f->f2.rd, 5); + prt_field("imm22", f->f2.imm22, 22); + } + + if (idx == 0) { + /* unimp / illtrap */ + prt_name(dhp, inp->in_data.in_def.in_name, 1); + prt_imm(dhp, f->f2.imm22, 0); + return (0); + } + + if (f->f2.imm22 == 0 && f->f2.rd == 0) { + prt_name(dhp, "nop", 0); + return (0); + } + + /* ?? Should we return -1 if rd == 0 && disp != 0 */ + + prt_name(dhp, inp->in_data.in_def.in_name, 1); + + bprintf(dhp, + ((dhp->dh_flags & DIS_OCTAL) != 0) ? + "%%hi(0%lo), %s" : "%%hi(0x%lx), %s", + f->f2.imm22 << 10, + reg_names[f->f2.rd]); + + return (0); +} + +/* ARGSUSED3 */ +int +fmt_branch(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx) +{ + const char *name = inp->in_data.in_def.in_name; + const char *r = NULL; + const char *annul = ""; + const char *pred = ""; + + char buf[15]; + + ifmt_t *f = (ifmt_t *)&instr; + + size_t curlen; + int32_t disp; + uint32_t flags = inp->in_data.in_def.in_flags; + int octal = ((dhp->dh_flags & DIS_OCTAL) != 0); + + if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) { + prt_field("op", f->f2.op, 2); + prt_field("op2", f->f2.op2, 3); + + switch (FLG_DISP_VAL(flags)) { + case DISP22: + prt_field("cond", f->f2a.cond, 4); + prt_field("a", f->f2a.a, 1); + prt_field("disp22", f->f2a.disp22, 22); + break; + + case DISP19: + prt_field("cond", f->f2a.cond, 4); + prt_field("a", f->f2a.a, 1); + prt_field("p", f->f2b.p, 1); + prt_field("cc", f->f2b.cc, 2); + prt_field("disp19", f->f2b.disp19, 19); + break; + + case DISP16: + prt_field("bit 28", ((instr & (1L << 28)) >> 28), 1); + prt_field("rcond", f->f2c.cond, 3); + prt_field("p", f->f2c.p, 1); + prt_field("rs1", f->f2c.rs1, 5); + prt_field("d16hi", f->f2c.d16hi, 2); + prt_field("d16lo", f->f2c.d16lo, 14); + break; + } + } + + if (f->f2b.op2 == 0x01 && idx == 0x00 && f->f2b.p == 1 && + f->f2b.cc == 0x02 && ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) != 0)) { + name = "iprefetch"; + flags = FLG_RS1(REG_NONE)|FLG_DISP(DISP19); + } + + switch (FLG_DISP_VAL(flags)) { + case DISP22: + disp = sign_extend(f->f2a.disp22, 22); + break; + + case DISP19: + disp = sign_extend(f->f2b.disp19, 19); + break; + + case DISP16: + disp = sign_extend((f->f2c.d16hi << 14)|f->f2c.d16lo, 16); + break; + + } + + disp *= 4; + + if ((FLG_RS1_VAL(flags) == REG_ICC) || (FLG_RS1_VAL(flags) == REG_FCC)) + r = get_regname(dhp, FLG_RS1_VAL(flags), f->f2b.cc); + else + r = get_regname(dhp, FLG_RS1_VAL(flags), f->f2c.rs1); + + if (r == NULL) + return (-1); + + if (f->f2a.a == 1) + annul = ",a"; + + if ((flags & FLG_PRED) != 0) { + if (f->f2b.p == 0) { + pred = ",pn"; + } else { + if ((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0) + pred = ",pt"; + } + } + + (void) snprintf(buf, sizeof (buf), "%s%s%s", name, annul, pred); + prt_name(dhp, buf, 1); + + + switch (FLG_DISP_VAL(flags)) { + case DISP22: + bprintf(dhp, + (octal != 0) ? "%s0%-11lo <" : "%s0x%-10lx <", + (disp < 0) ? "-" : "+", + (disp < 0) ? (-disp) : disp); + break; + + case DISP19: + bprintf(dhp, + (octal != 0) ? "%s, %s0%-5lo <" : "%s, %s0x%-04lx <", + r, + (disp < 0) ? "-" : "+", + (disp < 0) ? (-disp) : disp); + break; + + case DISP16: + bprintf(dhp, + (octal != 0) ? "%s, %s0%-6lo <" : "%s, %s0x%-5lx <", + r, + (disp < 0) ? "-" : "+", + (disp < 0) ? (-disp) : disp); + break; + } + + curlen = strlen(dhp->dh_buf); + dhp->dh_lookup(dhp->dh_data, dhp->dh_addr + (int64_t)disp, + dhp->dh_buf + curlen, dhp->dh_buflen - curlen - 1, NULL, NULL); + + (void) strlcat(dhp->dh_buf, ">", dhp->dh_buflen); + + return (0); +} + + + +/* + * print out the compare and swap instructions (casa/casxa) + * format: casa/casxa [%rs1] imm_asi, %rs2, %rd + * casa/casxa [%rs1] %asi, %rs2, %rd + * + * If DIS_DEBUG_SYN_ALL is set, synthetic instructions are emitted + * when an immediate ASI value is given as follows: + * + * casa [%rs1]#ASI_P, %rs2, %rd -> cas [%rs1], %rs2, %rd + * casa [%rs1]#ASI_P_L, %rs2, %rd -> casl [%rs1], %rs2, %rd + * casxa [%rs1]#ASI_P, %rs2, %rd -> casx [%rs1], %rs2, %rd + * casxa [%rs1]#ASI_P_L, %rs2, %rd -> casxl [%rs1], %rs2, %rd + */ +static int +fmt_cas(dis_handle_t *dhp, uint32_t instr, const char *name) +{ + ifmt_t *f = (ifmt_t *)&instr; + int noasi = 0; + + if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT)) != 0) { + if (f->f3.op3 == 0x3c && f->f3.i == 0) { + if (f->f3.asi == 0x80) { + noasi = 1; + name = "cas"; + } + + if (f->f3.asi == 0x88) { + noasi = 1; + name = "casl"; + } + } + + if (f->f3.op3 == 0x3e && f->f3.i == 0) { + if (f->f3.asi == 0x80) { + noasi = 1; + name = "casx"; + } + + if (f->f3.asi == 0x88) { + noasi = 1; + name = "casxl"; + } + } + } + + prt_name(dhp, name, 1); + + bprintf(dhp, "[%s]", reg_names[f->f3.rs1]); + + if (noasi == 0) { + (void) strlcat(dhp->dh_buf, " ", dhp->dh_buflen); + prt_asi(dhp, instr); + } + + bprintf(dhp, ", %s, %s", reg_names[f->f3.rs2], reg_names[f->f3.rd]); + + return (0); +} + +/* + * format a load/store instruction + * format: ldXX [%rs1 + %rs2], %rd load, i==0 + * ldXX [%rs1 +/- nn], %rd load, i==1 + * ldXX [%rs1 + %rs2] #XX, %rd load w/ imm_asi, i==0 + * ldXX [%rs1 +/- nn] %asi, %rd load from asi[%asi], i==1 + * + * stXX %rd, [%rs1 + %rs2] store, i==0 + * stXX %rd, [%rs1 +/- nn] store, i==1 + * stXX %rd, [%rs1 + %rs1] #XX store to imm_asi, i==0 + * stXX %rd, [%rs1 +/-nn] %asi store to asi[%asi], i==1 + * + * The register sets used for %rd are set in the instructions flags field + * The asi variants are used if FLG_ASI is set in the instructions flags field + * + * If DIS_DEBUG_SYNTH_ALL or DIS_DEBUG_COMPAT are set, + * When %rs1, %rs2 or nn are 0, they are not printed, i.e. + * [ %rs1 + 0x0 ], %rd -> [%rs1], %rd for example + * + * The following synthetic instructions are also implemented: + * + * stb %g0, [addr] -> clrb [addr] DIS_DEBUG_SYNTH_ALL + * sth %g0, [addr] -> crlh [addr] DIS_DEBUG_SYNTH_ALL + * stw %g0, [addr] -> clr [addr] DIS_DEBUG_SYNTH_ALL|DIS_DEBUG_COMPAT + * stx %g0, [addr] -> clrx [addr] DIS_DEBUG_SYNTH_ALL + * + * If DIS_DEBUG_COMPAT is set, the following substitutions also take place + * lduw -> ld + * ldtw -> ld + * stuw -> st + * sttw -> st + */ +int +fmt_ls(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx) +{ + ifmt_t *f = (ifmt_t *)&instr; + const char *regstr = NULL; + + const char *iname = inp->in_data.in_def.in_name; + uint32_t flags = inp->in_data.in_def.in_flags; + + if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) { + prt_field("op", f->f3.op, 2); + prt_field("op3", f->f3.op3, 6); + prt_field("rs1", f->f3.rs1, 5); + prt_field("i", f->f3.i, 1); + if (f->f3.i != 0) { + prt_field("simm13", f->f3a.simm13, 13); + } else { + if ((flags & FLG_ASI) != 0) + prt_field("imm_asi", f->f3.asi, 8); + prt_field("rs2", f->f3.rs2, 5); + } + prt_field("rd", f->f3.rd, 5); + } + + if (idx == 0x2d || idx == 0x3d) { + /* prefetch / prefetcha */ + + prt_name(dhp, iname, 1); + + prt_address(dhp, instr, 0); + + if (idx == 0x3d) { + (void) strlcat(dhp->dh_buf, " ", dhp->dh_buflen); + prt_asi(dhp, instr); + } + + (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen); + + /* fcn field is the same as rd */ + if (prefetch_str[f->f3.rd] != NULL) + (void) strlcat(dhp->dh_buf, prefetch_str[f->f3.rd], + dhp->dh_buflen); + else + prt_imm(dhp, f->f3.rd, 0); + + return (0); + } + + /* casa / casxa */ + if (idx == 0x3c || idx == 0x3e) + return (fmt_cas(dhp, instr, iname)); + + /* synthetic instructions & special cases */ + switch (idx) { + case 0x00: + /* ld */ + if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0) + iname = "lduw"; + break; + + case 0x03: + if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0) + iname = "ldtw"; + break; + + case 0x04: + /* stw */ + if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0) + iname = "stuw"; + + if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) + == 0) + break; + + if (f->f3.rd == 0) { + iname = "clr"; + flags = FLG_RD(REG_NONE); + } + break; + + case 0x05: + /* stb */ + if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) + == 0) + break; + + if (f->f3.rd == 0) { + iname = "clrb"; + flags = FLG_RD(REG_NONE); + } + break; + + case 0x06: + /* sth */ + if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) + == 0) + break; + + if (f->f3.rd == 0) { + iname = "clrh"; + flags = FLG_RD(REG_NONE); + } + break; + + case 0x07: + if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0) + iname = "sttw"; + break; + + case 0x0e: + /* stx */ + + if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) + == 0) + break; + + if (f->f3.rd == 0) { + iname = "clrx"; + flags = FLG_RD(REG_NONE); + } + break; + + case 0x13: + /* ldtwa */ + if (((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0) && + ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0)) + iname = "ldtwa"; + break; + + case 0x17: + /* sttwa */ + if (((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0) && + ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0)) + iname = "sttwa"; + break; + + case 0x21: + case 0x25: + /* + * on sparcv8 it merely says that rd != 1 should generate an + * exception, on v9, it is illegal + */ + if ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) == 0) + break; + + iname = (idx == 0x21) ? "ldx" : "stx"; + + if (f->f3.rd > 1) + return (-1); + + break; + + case 0x31: + /* stda */ + switch (f->f3.asi) { + case 0xc0: + case 0xc1: + case 0xc8: + case 0xc9: + case 0xc2: + case 0xc3: + case 0xca: + case 0xcb: + case 0xc4: + case 0xc5: + case 0xcc: + case 0xcd: + /* + * store partial floating point, only valid w/ + * vis + * + * Somewhat confusingly, it uses the same op + * code as 'stda' -- store double to alternate + * space. It is distinguised by specific + * imm_asi values (as seen above), and + * has a slightly different output syntax + */ + + if ((dhp->dh_flags & DIS_SPARC_V9_SGI) == 0) + break; + if (f->f3.i != 0) + break; + prt_name(dhp, iname, 1); + bprintf(dhp, "%s, %s, [%s] ", + get_regname(dhp, REG_FPD, f->f3.rd), + get_regname(dhp, REG_FPD, f->f3.rs2), + get_regname(dhp, REG_FPD, f->f3.rs1)); + prt_asi(dhp, instr); + return (0); + + default: + break; + } + + } + + regstr = get_regname(dhp, FLG_RD_VAL(flags), f->f3.rd); + + prt_name(dhp, iname, 1); + + if ((flags & FLG_STORE) != 0) { + if (regstr[0] != '\0') { + (void) strlcat(dhp->dh_buf, regstr, dhp->dh_buflen); + (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen); + } + + prt_address(dhp, instr, 0); + if ((flags & FLG_ASI) != 0) { + (void) strlcat(dhp->dh_buf, " ", dhp->dh_buflen); + prt_asi(dhp, instr); + } + } else { + prt_address(dhp, instr, 0); + if ((flags & FLG_ASI) != 0) { + (void) strlcat(dhp->dh_buf, " ", dhp->dh_buflen); + prt_asi(dhp, instr); + } + + if (regstr[0] != '\0') { + (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen); + (void) strlcat(dhp->dh_buf, regstr, dhp->dh_buflen); + } + } + + return (0); +} + +static int +fmt_cpop(dis_handle_t *dhp, uint32_t instr, const inst_t *inp) +{ + ifmt_t *f = (ifmt_t *)&instr; + int flags = FLG_P1(REG_CP)|FLG_P2(REG_CP)|FLG_NOIMM|FLG_P3(REG_CP); + + if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) { + prt_field("op", f->fcp.op, 2); + prt_field("op3", f->fcp.op3, 6); + prt_field("opc", f->fcp.opc, 9); + prt_field("rs1", f->fcp.rs1, 5); + prt_field("rs2", f->fcp.rs2, 5); + prt_field("rd", f->fcp.rd, 5); + } + + prt_name(dhp, inp->in_data.in_def.in_name, 1); + prt_imm(dhp, f->fcp.opc, 0); + + (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen); + (void) prt_aluargs(dhp, instr, flags); + + return (0); +} + +static int +dis_fmt_rdwr(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx) +{ + const char *psr_str = "%psr"; + const char *wim_str = "%wim"; + const char *tbr_str = "%tbr"; + + const char *name = inp->in_data.in_def.in_name; + const char *regstr = NULL; + + ifmt_t *f = (ifmt_t *)&instr; + + int rd = (idx < 0x30); + int v9 = (dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)); + int ridx = f->f3.rs1; + int i, first; + int pr_rs1 = 1; + int pr_rs2 = 1; + + int use_mask = 1; + uint32_t mask; + + if (rd == 0) + ridx = f->f3.rd; + + switch (idx) { + case 0x28: + /* rd */ + + /* stbar */ + if ((f->f3.rd == 0) && (f->f3.rs1 == 15) && (f->f3.i == 0)) { + prt_name(dhp, "stbar", 0); + return (0); + } + + /* membar */ + if ((v9 != 0) && (f->f3.rd == 0) && (f->f3.rs1 == 15) && + (f->f3.i == 1) && ((f->i & (1L << 12)) == 0)) { + + prt_name(dhp, "membar", + ((f->fmb.cmask != 0) || (f->fmb.mmask != 0))); + + first = 0; + + for (i = 0; i < 4; ++i) { + if ((f->fmb.cmask & (1L << i)) != 0) { + bprintf(dhp, "%s%s", + (first != 0) ? "|" : "", + membar_cmask[i]); + first = 1; + } + } + + for (i = 0; i < 5; ++i) { + if ((f->fmb.mmask & (1L << i)) != 0) { + bprintf(dhp, "%s%s", + (first != 0) ? "|" : "", + membar_mmask[i]); + first = 1; + } + } + + return (0); + } + + if (v9 != 0) { + regstr = v9_asr_names[ridx]; + mask = v9_asr_rdmask; + } else { + regstr = asr_names[ridx]; + mask = asr_rdmask; + } + break; + + case 0x29: + /* + * NOTE: due to an overlay entry, this only gets executed when + * disassembling v8 instructions + */ + regstr = psr_str; + use_mask = 0; + break; + + case 0x2a: + if (v9 != 0) { + regstr = v9_privreg_names[ridx]; + mask = v9_pr_rdmask; + } else { + regstr = wim_str; + use_mask = 0; + } + break; + + case 0x2b: + if (v9 != 0) { + /* flushw */ + prt_name(dhp, name, 0); + return (0); + } + + regstr = tbr_str; + use_mask = 0; + break; + + case 0x30: + if (v9 != 0) { + regstr = v9_asr_names[ridx]; + mask = v9_asr_wrmask; + } else { + regstr = asr_names[ridx]; + mask = asr_wrmask; + } + + /* synth: mov */ + if ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) + == 0) + break; + + if (f->f3.rs1 == 0) { + name = "mov"; + pr_rs1 = 0; + } + + if ((f->f3.i == 0 && f->f3.rs2 == 0) || + (f->f3.i == 1 && f->f3a.simm13 == 0)) { + name = "mov"; + pr_rs2 = 0; + } + + if (pr_rs1 == 0) + pr_rs2 = 1; + + break; + + case 0x31: + /* + * NOTE: due to the presence of an overlay entry for another + * table, this case only happens when doing v8 instructions + * only + */ + regstr = psr_str; + use_mask = 0; + break; + + case 0x32: + if (v9 != 0) { + regstr = v9_privreg_names[ridx]; + mask = v9_pr_wrmask; + } else { + regstr = wim_str; + use_mask = 0; + } + break; + + case 0x33: + /* NOTE: due to an overlay entry, this is v8 only */ + regstr = tbr_str; + use_mask = 0; + break; + } + + if (regstr == NULL) + return (-1); + + if (use_mask != 0 && ((1L << ridx) & mask) == 0) + return (-1); + + prt_name(dhp, name, 1); + + if (rd != 0) { + bprintf(dhp, "%s, %s", regstr, reg_names[f->f3.rd]); + } else { + if (pr_rs1 == 1) + bprintf(dhp, "%s, ", reg_names[f->f3.rs1]); + + if (pr_rs2 != 0) { + if (f->f3.i == 1) + prt_imm(dhp, sign_extend(f->f3a.simm13, 13), + IMM_SIGNED); + else + (void) strlcat(dhp->dh_buf, + reg_names[f->f3.rs2], dhp->dh_buflen); + (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen); + } + + (void) strlcat(dhp->dh_buf, regstr, dhp->dh_buflen); + } + + return (0); +} + +/* ARGSUSED3 */ +int +fmt_trap(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx) +{ + ifmt_t *f = (ifmt_t *)&instr; + + int v9 = ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0); + int p_rs1, p_t; + + if (f->ftcc.undef != 0) + return (-1); + + if (icc_names[f->ftcc.cc] == NULL) + return (-1); + + if (f->ftcc.i == 1 && f->ftcc.undef2 != 0) + return (-1); + + if (f->ftcc2.i == 0 && f->ftcc2.undef2 != 0) + return (-1); + + p_rs1 = ((f->ftcc.rs1 != 0) || + ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) == 0)); + + if (f->ftcc.i == 0) { + p_t = (f->f3.rs2 != 0 || p_rs1 == 0); + + bprintf(dhp, "%-9s %s%s%s%s%s", inp->in_data.in_def.in_name, + (v9 != 0) ? icc_names[f->ftcc2.cc] : "", + (v9 != 0) ? ", " : "", + (p_rs1 != 0) ? reg_names[f->ftcc2.rs1] : "", + (p_rs1 != 0) ? " + " : "", + (p_t != 0) ? reg_names[f->f3.rs2] : ""); + } else { + bprintf(dhp, "%-9s %s%s%s%s0x%x", inp->in_data.in_def.in_name, + (v9 != 0) ? icc_names[f->ftcc2.cc] : "", + (v9 != 0) ? ", " : "", + (p_rs1 != 0) ? reg_names[f->ftcc2.rs1] : "", + (p_rs1 != 0) ? " + " : "", + f->ftcc.immtrap); + } + + return (0); +} + +static int +prt_shift(dis_handle_t *dhp, uint32_t instr, const inst_t *inp) +{ + char name[5]; + uint32_t cnt; + + ifmt_t *f = (ifmt_t *)&instr; + int octal = ((dhp->dh_flags & DIS_OCTAL) != 0); + + name[0] = '\0'; + (void) strlcat(name, inp->in_data.in_def.in_name, sizeof (name)); + + if (f->f3b.i == 1) + cnt = f->f3.rs2; + + if (f->f3b.x == 1 && ((dhp->dh_flags & DIS_SPARC_V8) == 0)) { + cnt = f->f3b.shcnt; + (void) strlcat(name, "x", sizeof (name)); + } + + prt_name(dhp, name, 1); + + if (f->f3b.i == 1) + bprintf(dhp, (octal != 0) ? "%s, 0%lo, %s" : "%s, 0x%lx, %s", + reg_names[f->f3.rs1], cnt, reg_names[f->f3.rd]); + else + bprintf(dhp, "%s, %s, %s", reg_names[f->f3.rs1], + reg_names[f->f3.rs2], reg_names[f->f3.rd]); + + return (0); +} + +/* ARGSUSED3 */ +static int +prt_jmpl(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx) +{ + const char *name = inp->in_data.in_def.in_name; + ifmt_t *f = (ifmt_t *)&instr; + + if (f->f3.rd == 15 && ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0)) + name = "call"; + + if (f->f3.rd == 0) { + if (f->f3.i == 1 && f->f3a.simm13 == 8) { + if (f->f3.rs1 == 15) { + prt_name(dhp, "retl", 0); + return (0); + } + + if (f->f3.rs1 == 31) { + prt_name(dhp, "ret", 0); + return (0); + } + } + + name = "jmp"; + } + + prt_name(dhp, name, 1); + prt_address(dhp, instr, 1); + + if (f->f3.rd == 0) + return (0); + + if (f->f3.rd == 15 && ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0)) + return (0); + + bprintf(dhp, ", %s", reg_names[f->f3.rd]); + + return (0); +} + +int +fmt_alu(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx) +{ + ifmt_t *f = (ifmt_t *)&instr; + + const char *name = inp->in_data.in_def.in_name; + int flags = inp->in_data.in_def.in_flags; + int arg = 0; + + if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) { + prt_field("op", f->f3.op, 2); + prt_field("op3", f->f3.op3, 6); + prt_field("rs1", f->f3.rs1, 5); + + switch (idx) { + /* TODO: more formats */ + + default: + if (f->f3.i == 0) + prt_field("rs2", f->f3.rs2, 5); + else + prt_field("simm13", f->f3a.simm13, 13); + + prt_field("rd", f->f3.rd, 5); + } + + } + + switch (idx) { + case 0x00: + /* add */ + + if ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) == 0) + break; + + if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 && + f->f3a.simm13 == 1) { + name = "inc"; + flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM; + break; + } + + if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 && + f->f3a.simm13 != 1) { + name = "inc"; + flags = FLG_P1(REG_NONE); + break; + } + break; + + case 0x02: + /* or */ + + if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT)) + == 0) + break; + + if ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) != 0) { + if (f->f3.rs1 == f->f3.rd) { + name = "bset"; + flags = FLG_P1(REG_NONE); + break; + } + } + + if (((f->f3.i == 0 && f->f3.rs2 == 0) || + (f->f3.i == 1 && f->f3a.simm13 == 0)) && + (f->f3.rs1 == 0)) { + name = "clr"; + flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM; + break; + } + + if (f->f3.rs1 == 0) { + name = "mov"; + flags = FLG_P1(REG_NONE); + break; + } + break; + + case 0x04: + /* sub */ + + if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT)) + == 0) + break; + + if (f->f3.rs1 == 0 && f->f3.i == 0 && f->f3.rs2 == f->f3.rd) { + name = "neg"; + flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE); + break; + } + + if (f->f3.rs1 == 0 && f->f3.i == 0 && f->f3.rs2 != f->f3.rd) { + name = "neg"; + flags = FLG_P1(REG_NONE); + break; + } + + if ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) == 0) + break; + + if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 && + f->f3a.simm13 == 1) { + name = "dec"; + flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM; + break; + } + + if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 && + f->f3a.simm13 != 1) { + name = "dec"; + flags = FLG_P1(REG_NONE); + break; + } + break; + + case 0x07: + /* xnor */ + + if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT)) + == 0) + break; + + /* + * xnor -> not when you have: + * xnor %rs1, 0x0 or %g0, %rd + */ + if ((f->f3.i == 0 && f->f3.rs2 != 0) || + (f->f3.i == 1 && f->f3a.simm13 != 0)) + break; + + name = "not"; + + if (f->f3.rs1 == f->f3.rd) + flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM| + FLG_P3(REG_INT); + else + flags = FLG_P1(REG_INT)|FLG_P2(REG_NONE)|FLG_NOIMM| + FLG_P3(REG_INT); + + break; + + case 0x10: + /* addcc */ + + if ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) == 0) + break; + + if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 && + f->f3a.simm13 == 1) { + name = "inccc"; + flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM; + break; + } + + if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 && + f->f3a.simm13 != 1) { + name = "inccc"; + flags = FLG_P1(REG_NONE); + break; + } + break; + + case 0x11: + /* andcc */ + + if (f->f3.rd != 0) + break; + + if ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) + == 0) + break; + + if (((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0) && + ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) == 0)) + break; + + name = "btst"; + flags = FLG_P1(REG_NONE); + f->f3.rd = f->f3.rs1; + break; + + case 0x12: + /* orcc */ + + if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT)) + == 0) + break; + + if (f->f3.rs1 == 0 && f->f3.rd == 0 && f->f3.i == 0) { + name = "tst"; + flags = FLG_P1(REG_NONE)|FLG_P3(REG_NONE); + break; + } + + if (f->f3.rs2 == 0 && f->f3.rd == 0 && f->f3.i == 0) { + name = "tst"; + flags = FLG_P2(REG_NONE)|FLG_P3(REG_NONE); + break; + } + + break; + + case 0x14: + /* subcc */ + + if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT)) + == 0) + break; + + if (f->f3.rd == 0) { + name = "cmp"; + flags = FLG_P3(REG_NONE); + break; + } + + if ((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0) + break; + + if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 && + f->f3a.simm13 == 1) { + name = "deccc"; + flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM; + break; + } + + if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 && + f->f3a.simm13 != 1) { + name = "deccc"; + flags = FLG_P1(REG_NONE); + break; + } + + break; + + case 0x25: + case 0x26: + case 0x27: + return (prt_shift(dhp, instr, inp)); + + case 0x28: + case 0x29: + case 0x2a: + case 0x2b: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + return (dis_fmt_rdwr(dhp, instr, inp, idx)); + + case 0x36: + case 0x37: + /* NOTE: overlayed on v9 */ + if ((dhp->dh_flags & DIS_SPARC_V8) != 0) + return (fmt_cpop(dhp, instr, inp)); + break; + + case 0x38: + /* jmpl */ + return (prt_jmpl(dhp, instr, inp, idx)); + + case 0x39: + /* rett / return */ + prt_name(dhp, name, 1); + prt_address(dhp, instr, 1); + return (0); + + case 0x3b: + /* flush */ + prt_name(dhp, name, 1); + prt_address(dhp, instr, 0); + return (0); + + case 0x3c: + case 0x3d: + /* save / restore */ + if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT)) + == 0) + break; + + if (f->f3.rs1 != 0 || f->f3.rs2 != 0 || f->f3.rd != 0) + break; + + if (f->f3.i != 0 && ((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0)) + break; + + prt_name(dhp, name, 0); + return (0); + } + + if (FLG_P1_VAL(flags) != REG_NONE || FLG_P2_VAL(flags) != REG_NONE || + FLG_P3_VAL(flags) != REG_NONE) + arg = 1; + + prt_name(dhp, name, (arg != 0)); + prt_aluargs(dhp, instr, flags); + + return (0); +} + +/* ARGSUSED1 */ +int +fmt_regwin(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx) +{ + prt_name(dhp, inp->in_data.in_def.in_name, 0); + return (0); +} + +/* ARGSUSED1 */ +int +fmt_trap_ret(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx) +{ + prt_name(dhp, inp->in_data.in_def.in_name, 0); + return (0); +} + +/* ARGSUSED3 */ +int +fmt_movcc(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx) +{ + ifmt_t *f = (ifmt_t *)&instr; + const char **regs = NULL; + + if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) { + prt_field("op", f->f3c.op, 2); + prt_field("op3", f->f3c.op3, 6); + prt_field("cond", f->f3c.cond, 4); + prt_field("cc2", f->f3c.cc2, 1); + prt_field("cc", f->f3c.cc, 2); + prt_field("i", f->f3c.i, 1); + + if (f->f3c.i == 0) + prt_field("rs2", f->f3.rs2, 5); + else + prt_field("simm11", f->f3c.simm11, 11); + + prt_field("rd", f->f3.rd, 5); + } + + if (f->f3c.cc2 == 0) { + regs = fcc_names; + } else { + regs = icc_names; + if (regs[f->f3c.cc] == NULL) + return (-1); + } + + prt_name(dhp, inp->in_data.in_def.in_name, 1); + + bprintf(dhp, "%s, ", regs[f->f3c.cc]); + + if (f->f3c.i == 1) + prt_imm(dhp, sign_extend(f->f3c.simm11, 11), IMM_SIGNED); + else + (void) strlcat(dhp->dh_buf, reg_names[f->f3.rs2], + dhp->dh_buflen); + + bprintf(dhp, ", %s", reg_names[f->f3.rd]); + + return (0); +} + +/* ARGSUSED3 */ +int +fmt_movr(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx) +{ + ifmt_t *f = (ifmt_t *)&instr; + + prt_name(dhp, inp->in_data.in_def.in_name, 1); + + bprintf(dhp, "%s, ", reg_names[f->f3d.rs1]); + + if (f->f3d.i == 1) + prt_imm(dhp, sign_extend(f->f3d.simm10, 10), IMM_SIGNED); + else + (void) strlcat(dhp->dh_buf, reg_names[f->f3.rs2], + dhp->dh_buflen); + + bprintf(dhp, ", %s", reg_names[f->f3.rd]); + + return (0); +} + +/* ARGSUSED3 */ +int +fmt_fpop1(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx) +{ + ifmt_t *f = (ifmt_t *)&instr; + int flags = inp->in_data.in_def.in_flags; + + flags |= FLG_NOIMM; + + if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) { + prt_field("op", f->f3.op, 2); + prt_field("op3", f->f3.op3, 6); + prt_field("opf", f->fcmp.opf, 9); + prt_field("rs1", f->f3.rs1, 5); + prt_field("rs2", f->f3.rs2, 5); + prt_field("rd", f->f3.rd, 5); + } + + prt_name(dhp, inp->in_data.in_def.in_name, 1); + prt_aluargs(dhp, instr, flags); + + return (0); +} + +int +fmt_fpop2(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx) +{ + static const char *condstr_icc[16] = { + "n", "e", "le", "l", "leu", "lu", "neg", "vs", + "a", "nz", "g", "ge", "gu", "geu", "pos", "vc" + }; + + static const char *condstr_fcc[16] = { + "n", "nz", "lg", "ul", "l", "ug", "g", "u", + "a", "e", "ue", "ge", "uge", "le", "ule", "o" + }; + + ifmt_t *f = (ifmt_t *)&instr; + const char *ccstr = ""; + char name[15]; + + int flags = inp->in_data.in_def.in_flags; + int is_cmp = (idx == 0x51 || idx == 0x52 || idx == 0x53 || + idx == 0x55 || idx == 0x56 || idx == 0x57); + int is_fmov = (idx & 0x3f); + int is_v9 = ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0); + int is_compat = ((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0); + + int p_cc = 0; + + is_fmov = (is_fmov == 0x1 || is_fmov == 0x2 || is_fmov == 0x3); + + if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) { + prt_field("op", f->f3.op, 2); + prt_field("op3", f->f3.op3, 6); + prt_field("opf", f->fcmp.opf, 9); + + switch (idx & 0x3f) { + case 0x51: + case 0x52: + case 0x53: + case 0x55: + case 0x56: + case 0x57: + prt_field("cc", f->fcmp.cc, 2); + prt_field("rs1", f->f3.rs1, 5); + prt_field("rs2", f->f3.rs2, 5); + break; + + case 0x01: + case 0x02: + case 0x03: + prt_field("opf_low", f->fmv.opf, 6); + prt_field("cond", f->fmv.cond, 4); + prt_field("opf_cc", f->fmv.cc, 3); + prt_field("rs2", f->fmv.rs2, 5); + break; + + default: + prt_field("rs1", f->f3.rs1, 5); + prt_field("rs2", f->f3.rs2, 5); + prt_field("rd", f->f3.rd, 5); + } + } + + name[0] = '\0'; + (void) strlcat(name, inp->in_data.in_def.in_name, sizeof (name)); + + if (is_fmov != 0) { + (void) strlcat(name, + (f->fmv.cc < 4) ? condstr_fcc[f->fmv.cond] + : condstr_icc[f->fmv.cond], + sizeof (name)); + } + + prt_name(dhp, name, 1); + + if (is_cmp != 0) + ccstr = fcc_names[f->fcmp.cc]; + + if (is_fmov != 0) + ccstr = (f->fmv.cc < 4) ? fcc_names[f->fmv.cc & 0x3] + : icc_names[f->fmv.cc & 0x3]; + + if (ccstr == NULL) + return (-1); + + p_cc = (is_compat == 0 || is_v9 != 0 || + (is_cmp != 0 && f->fcmp.cc != 0) || + (is_fmov != 0 && f->fmv.cc != 0)); + + if (p_cc != 0) + bprintf(dhp, "%s, ", ccstr); + + prt_aluargs(dhp, instr, flags); + + return (0); +} + +int +fmt_vis(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx) +{ + ifmt_t *f = (ifmt_t *)&instr; + int flags = inp->in_data.in_def.in_flags; + + if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) { + prt_field("op", f->f3.op, 2); + prt_field("op3", f->f3.op3, 6); + prt_field("opf", f->fcmp.opf, 9); + + if (idx == 0x081) { + prt_field("mode", instr & 02L, 2); + } else { + prt_field("rs1", f->f3.rs1, 5); + prt_field("rs2", f->f3.rs2, 5); + prt_field("rd", f->f3.rd, 5); + } + } + + prt_name(dhp, inp->in_data.in_def.in_name, 1); + + if (idx == 0x081) { + /* siam */ + bprintf(dhp, "%d", instr & 0x7L); + return (0); + } + + prt_aluargs(dhp, instr, flags); + + return (0); +} + +/* ARGSUSED3 */ +int +fmt_fused(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx) +{ + ifmt_t *f = (ifmt_t *)&instr; + int flags = inp->in_data.in_def.in_flags; + + prt_name(dhp, inp->in_data.in_def.in_name, 1); + bprintf(dhp, "%s, %s, %s, %s", + get_regname(dhp, FLG_P1_VAL(flags), f->fused.rs1), + get_regname(dhp, FLG_P1_VAL(flags), f->fused.rs2), + get_regname(dhp, FLG_P1_VAL(flags), f->fused.rs3), + get_regname(dhp, FLG_P1_VAL(flags), f->fused.rd)); + + return (0); +} +/* + * put name into the output buffer + * if add_space !=0, append a space after it + */ +static void +prt_name(dis_handle_t *dhp, const char *name, int add_space) +{ + bprintf(dhp, (add_space == 0) ? "%s" : "%-9s ", name); +} + +/* + * For debugging, print out a field of the instruction + * field is the name of the field + * val is the value of the field + * len is the length of the field (in bits) + */ +#if defined(DIS_STANDALONE) +/* ARGSUSED */ +static void +prt_field(const char *field, uint32_t val, int len) +{ + +} + +#else +static void +prt_field(const char *field, uint32_t val, int len) +{ + (void) fprintf(stderr, "DISASM: %8s = 0x%-8ulx (", field, val); + prt_binary(val, len); + (void) fprintf(stderr, ")\n"); +} +#endif /* DIS_STANDALONE */ + +/* + * sign extend a val (that is 'bits' bits in length) to a 32-bit signed + * integer + */ +static int32_t +sign_extend(int32_t val, int32_t bits) +{ + if ((val & (1L << (bits - 1))) == 0) + return (val); + + return ((-1L << bits) | val); +} + +/* + * print out an immediate (i.e. constant) value + * val is the value + * format indicates if it is: + * 0 Unsigned + * IMM_SIGNED A signed value (prepend +/- to the value) + * IMM_ADDR Part of an address expression (prepend +/- but with a space + * between the sign and the value for things like [%i1 + 0x55] + */ +static void +prt_imm(dis_handle_t *dhp, uint32_t val, int format) +{ + const char *fmtstr = NULL; + int32_t sv = (int32_t)val; + int octal = dhp->dh_flags & DIS_OCTAL; + + switch (format) { + case IMM_ADDR: + if (sv < 0) { + sv = -sv; + fmtstr = (octal != 0) ? "- 0%lo" : "- 0x%lx"; + } else { + fmtstr = (octal != 0) ? "+ 0%lo" : "+ 0x%lx"; + } + break; + + case IMM_SIGNED: + if (sv < 0) { + sv = -sv; + fmtstr = (octal != 0) ? "-0%lo" : "-0x%lx"; + break; + } + /* fall through */ + + default: + fmtstr = (octal != 0) ? "0%lo" : "0x%lx"; + } + + bprintf(dhp, fmtstr, sv); +} + +/* + * return the symbolic name of a register + * regset is one of the REG_* values indicating which type of register it is + * such as integer, floating point, etc. + * idx is the numeric value of the register + * + * If regset is REG_NONE, an empty, but non-NULL string is returned + * NULL may be returned if the index indicates an invalid register value + * such as with the %icc/%xcc sets + */ +static const char * +get_regname(dis_handle_t *dhp, int regset, uint32_t idx) +{ + const char *regname = NULL; + + switch (regset) { + case REG_INT: + regname = reg_names[idx]; + break; + + case REG_FP: + regname = freg_names[idx]; + break; + + case REG_FPD: + if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0) + regname = fdreg_names[idx]; + else + regname = compat_fdreg_names[idx]; + + break; + + case REG_FPQ: + if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0) + regname = fqreg_names[idx]; + else + regname = freg_names[idx]; + + break; + + case REG_CP: + regname = cpreg_names[idx]; + break; + + case REG_ICC: + regname = icc_names[idx]; + break; + + case REG_FCC: + regname = fcc_names[idx]; + break; + + case REG_FSR: + regname = "%fsr"; + break; + + case REG_CSR: + regname = "%csr"; + break; + + case REG_CQ: + regname = "%cq"; + break; + + case REG_NONE: + regname = ""; + break; + } + + return (regname); +} + +/* + * output the asi value from the instruction + * + * TODO: investigate if this should perhaps have a mask -- are undefined ASI + * values for an instruction still disassembled?? + */ +static void +prt_asi(dis_handle_t *dhp, uint32_t instr) +{ + ifmt_t *f = (ifmt_t *)&instr; + int octal = ((dhp->dh_flags & DIS_OCTAL) != 0); + + if (f->f3.i != 0) + bprintf(dhp, "%%asi"); + else + bprintf(dhp, (octal != 0) ? "0%03o" : "0x%02x", f->f3.asi); + +} + +/* + * put an address expression into the output buffer + * + * instr is the instruction to use + * if nobrackets != 0, [] are not added around the instruction + * + * Currently this option is set when printing out the address portion + * of a jmpl instruction, but otherwise 0 for load/stores + * + * If no debug flags are set, the full expression is output, even when + * %g0 or 0x0 appears in the address + * + * If DIS_DEBUG_SYN_ALL or DIS_DEBUG_COMPAT are set, when %g0 or 0x0 + * appear in the address, they are not output. If the wierd (and probably + * shouldn't happen) address of [%g0 + %g0] or [%g0 + 0x0] is encountered, + * [%g0] is output + */ +static void +prt_address(dis_handle_t *dhp, uint32_t instr, int nobrackets) +{ + ifmt_t *f = (ifmt_t *)&instr; + int32_t simm13; + int octal = ((dhp->dh_flags & DIS_OCTAL) != 0); + int p1 = ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) == 0); + int p2 = ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) == 0); + + if (f->f3a.i == 0) { + p1 |= ((f->f3a.rs1 != 0) || f->f3.rs2 == 0); + p2 |= (f->f3.rs2 != 0); + + bprintf(dhp, "%s%s%s%s%s", + (nobrackets == 0) ? "[" : "", + (p1 != 0) ? reg_names[f->f3a.rs1] : "", + (p1 != 0 && p2 != 0) ? " + " : "", + (p2 != 0) ? reg_names[f->f3.rs2] : "", + (nobrackets == 0) ? "]" : ""); + } else { + const char *sign; + + simm13 = sign_extend(f->f3a.simm13, 13); + sign = (simm13 < 0) ? "-" : "+"; + + p1 |= (f->f3a.rs1 != 0); + p2 |= (p1 == 0 || simm13 != 0); + + if (p1 == 0 && simm13 == 0) + p2 = 1; + + if (p1 == 0 && simm13 >= 0) + sign = ""; + + if (p2 != 0) + bprintf(dhp, + (octal != 0) ? "%s%s%s%s%s0%lo%s" : + "%s%s%s%s%s0x%lx%s", + (nobrackets == 0) ? "[" : "", + (p1 != 0) ? reg_names[f->f3a.rs1] : "", + (p1 != 0) ? " " : "", + sign, + (p1 != 0) ? " " : "", + (simm13 < 0) ? -(simm13) : simm13, + (nobrackets == 0) ? "]" : ""); + else + bprintf(dhp, "%s%s%s", + (nobrackets == 0) ? "[" : "", + reg_names[f->f3a.rs1], + (nobrackets == 0) ? "]" : ""); + } +} + +/* + * print out the arguments to an alu operation (add, sub, etc.) + * conatined in 'instr' + * + * alu instructions have the following format: + * %rs1, %rs2, %rd (i == 0) + * %rs1, 0xnnn, %rd (i == 1) + * ^ ^ ^ + * | | | + * p1 p2 p3 + * + * flags indicates the register set to use for each position (p1, p2, p3) + * as well as if immediate values (i == 1) are allowed + * + * if flags indicates a specific position has REG_NONE set as it's register + * set, it is omitted from the output. This is primarly used for certain + * floating point operations + */ +static void +prt_aluargs(dis_handle_t *dhp, uint32_t instr, uint32_t flags) +{ + ifmt_t *f = (ifmt_t *)&instr; + const char *r1, *r2, *r3; + int p1, p2, p3; + + r1 = get_regname(dhp, FLG_P1_VAL(flags), f->f3.rs1); + r2 = get_regname(dhp, FLG_P2_VAL(flags), f->f3.rs2); + r3 = get_regname(dhp, FLG_P3_VAL(flags), f->f3.rd); + + p1 = (FLG_P1_VAL(flags) != REG_NONE); + p2 = (((flags & FLG_NOIMM) == 0) || (FLG_P2_VAL(flags) != REG_NONE)); + p3 = (FLG_RD_VAL(flags) != REG_NONE); + + if (r1 == NULL || r1[0] == '\0') + p1 = 0; + + if (f->f3a.i == 0 && (r2 == NULL || r2[0] == '\0')) + p2 = 0; + + if (r3 == NULL || r3[0] == '\0') + p3 = 0; + + if (p1 != 0) { + (void) strlcat(dhp->dh_buf, r1, dhp->dh_buflen); + if (p2 != 0 || p3 != 0) + (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen); + } + + if (p2 != 0) { + if (f->f3.i == 0 || ((flags & FLG_NOIMM) != 0)) + (void) strlcat(dhp->dh_buf, r2, dhp->dh_buflen); + else + prt_imm(dhp, sign_extend(f->f3a.simm13, 13), + IMM_SIGNED); + + if (p3 != 0) + (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen); + } + + if (p3 != 0) + (void) strlcat(dhp->dh_buf, r3, dhp->dh_buflen); +} + +/* + * just a handy function that takes care of managing the buffer length + * w/ printf + */ + +/* + * PRINTF LIKE 1 + */ +static void +bprintf(dis_handle_t *dhp, const char *fmt, ...) +{ + size_t curlen; + va_list ap; + + curlen = strlen(dhp->dh_buf); + + va_start(ap, fmt); + (void) vsnprintf(dhp->dh_buf + curlen, dhp->dh_buflen - curlen, fmt, + ap); + va_end(ap); +} diff --git a/usr/src/lib/libdisasm/sparc/dis_sparc_fmt.h b/usr/src/lib/libdisasm/sparc/dis_sparc_fmt.h new file mode 100644 index 0000000000..4630c8114e --- /dev/null +++ b/usr/src/lib/libdisasm/sparc/dis_sparc_fmt.h @@ -0,0 +1,124 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Copyright 2007 Jason King. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifndef _DIS_SPARC_FMT_H +#define _DIS_SPARC_FMT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include "libdisasm.h" +#include "dis_sparc.h" + +/* which set of registers are used with an instruction */ +#define REG_INT 0x00 /* regular integer registers */ +#define REG_FP 0x01 /* single-precision fp registers */ +#define REG_FPD 0x02 /* double-precision fp registers */ +#define REG_FPQ 0x03 /* quad-precision fp registers */ +#define REG_CP 0x04 /* coprocessor registers (v8) */ +#define REG_ICC 0x05 /* %icc / % xcc */ +#define REG_FCC 0x06 /* %fccn */ +#define REG_FSR 0x07 /* %fsr */ +#define REG_CSR 0x08 /* %csr */ +#define REG_CQ 0x09 /* %cq */ +#define REG_NONE 0x0a /* no registers */ + +/* the size fo the displacement for branches */ +#define DISP22 0x00 +#define DISP19 0x01 +#define DISP16 0x02 +#define CONST22 0x03 + +/* get/set the register set name for the rd field of an instruction */ +#define FLG_RD(x) (x) +#define FLG_RD_VAL(x) (x & 0xfL) + +#define FLG_STORE (0x1L << 24) /* the instruction is not a load */ +#define FLG_ASI (0x2L << 24) /* the load/store includes an asi value */ + + +/* flags for ALU instructions */ + +/* set/get register set name for 1st argument position */ +#define FLG_P1(x) (x << 8) +#define FLG_P1_VAL(x) ((x >> 8) & 0xfL) + +/* get/set reg set for 2nd argument position */ +#define FLG_P2(x) (x << 4) +#define FLG_P2_VAL(x) ((x >> 4) & 0xfL) + +/* get/set for 3rd argument position */ +#define FLG_P3(x) (x) +#define FLG_P3_VAL(x) (x & 0xfL) + +/* set if the arguments do not contain immediate values */ +#define FLG_NOIMM (0x01L << 24) + + + +/* flags for branch instructions */ + +/* has branch prediction */ +#define FLG_PRED (0x01L << 24) + +/* get/set condition code register set -- usually REG_NONE */ +#define FLG_RS1(x) (x) +#define FLG_RS1_VAL(x) (x & 0xfL) + +/* get/set displacement size */ +#define FLG_DISP(x) (x << 4L) +#define FLG_DISP_VAL(x) ((x >> 4L) & 0x0fL) + + +int fmt_call(dis_handle_t *, uint32_t, const inst_t *, int); +int fmt_ls(dis_handle_t *, uint32_t, const inst_t *, int); +int fmt_alu(dis_handle_t *, uint32_t, const inst_t *, int); +int fmt_branch(dis_handle_t *, uint32_t, const inst_t *, int); +int fmt_sethi(dis_handle_t *, uint32_t, const inst_t *, int); +int fmt_fpop1(dis_handle_t *, uint32_t, const inst_t *, int); +int fmt_fpop2(dis_handle_t *, uint32_t, const inst_t *, int); +int fmt_vis(dis_handle_t *, uint32_t, const inst_t *, int); +int fmt_trap(dis_handle_t *, uint32_t, const inst_t *, int); +int fmt_regwin(dis_handle_t *, uint32_t, const inst_t *, int); +int fmt_trap_ret(dis_handle_t *, uint32_t, const inst_t *, int); +int fmt_movcc(dis_handle_t *, uint32_t, const inst_t *, int); +int fmt_movr(dis_handle_t *, uint32_t, const inst_t *, int); +int fmt_fused(dis_handle_t *, uint32_t, const inst_t *, int); + +#ifdef __cplusplus +} +#endif + +#endif /* _DIS_SPARC_FMT_H */ diff --git a/usr/src/lib/libdisasm/sparc/instr.c b/usr/src/lib/libdisasm/sparc/instr.c new file mode 100644 index 0000000000..4be67e5949 --- /dev/null +++ b/usr/src/lib/libdisasm/sparc/instr.c @@ -0,0 +1,1625 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Copyright 2007 Jason King. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include "libdisasm.h" +#include "libdisasm_impl.h" +#include "dis_sparc.h" +#include "dis_sparc_fmt.h" + +#define INVALID \ +{ \ + .in_type = INST_NONE, \ + .in_arch = 0, \ + .in_data = { \ + .in_tbl = NULL \ + } \ +} + +#define INVALIDA(_arch) \ +{ \ + .in_type = INST_NONE, \ + .in_arch = _arch, \ + .in_data = { \ + .in_tbl = NULL \ + } \ +} + +#define INST(_name, _arch, _flags) \ +{ \ + .in_type = INST_DEF, \ + .in_arch = _arch, \ + .in_data = { \ + .in_def = { \ + .in_name = _name, \ + .in_flags = _flags \ + } \ + } \ +} + +#define TABLE(_name, _arch) \ +{ \ + .in_type = INST_TBL, \ + .in_arch = _arch, \ + .in_data = { \ + .in_tbl = &_name \ + } \ +} + +#define OVERLAY(_idx, _inst) \ +{ \ + .ov_idx = _idx, \ + .ov_inst = _inst \ +} + +#define OVERLAY_END { .ov_idx = -1, .ov_inst = INVALID } + +#define V8 DIS_SPARC_V8 +#define V9 DIS_SPARC_V9 +#define V9S DIS_SPARC_V9_SGI +#define V9O DIS_SPARC_V9_OPL +#define VALL V8|V9|V9S|V9O + +/* branches */ +static const inst_t BPcc_table_def[16] = { + INST("bn", V9|V9S, FLG_PRED|FLG_RS1(REG_ICC)|FLG_DISP(DISP19)), + INST("be", V9|V9S, FLG_PRED|FLG_RS1(REG_ICC)|FLG_DISP(DISP19)), + INST("ble", V9|V9S, FLG_PRED|FLG_RS1(REG_ICC)|FLG_DISP(DISP19)), + INST("bl", V9|V9S, FLG_PRED|FLG_RS1(REG_ICC)|FLG_DISP(DISP19)), + + INST("bleu", V9|V9S, FLG_PRED|FLG_RS1(REG_ICC)|FLG_DISP(DISP19)), + INST("bcs", V9|V9S, FLG_PRED|FLG_RS1(REG_ICC)|FLG_DISP(DISP19)), + INST("bneg", V9|V9S, FLG_PRED|FLG_RS1(REG_ICC)|FLG_DISP(DISP19)), + INST("bvs", V9|V9S, FLG_PRED|FLG_RS1(REG_ICC)|FLG_DISP(DISP19)), + + INST("ba", V9|V9S, FLG_PRED|FLG_RS1(REG_ICC)|FLG_DISP(DISP19)), + INST("bne", V9|V9S, FLG_PRED|FLG_RS1(REG_ICC)|FLG_DISP(DISP19)), + INST("bg", V9|V9S, FLG_PRED|FLG_RS1(REG_ICC)|FLG_DISP(DISP19)), + INST("bge", V9|V9S, FLG_PRED|FLG_RS1(REG_ICC)|FLG_DISP(DISP19)), + + INST("bgu", V9|V9S, FLG_PRED|FLG_RS1(REG_ICC)|FLG_DISP(DISP19)), + INST("bcc", V9|V9S, FLG_PRED|FLG_RS1(REG_ICC)|FLG_DISP(DISP19)), + INST("bpos", V9|V9S, FLG_PRED|FLG_RS1(REG_ICC)|FLG_DISP(DISP19)), + INST("bvc", V9|V9S, FLG_PRED|FLG_RS1(REG_ICC)|FLG_DISP(DISP19)) +}; + +static const table_t BPcc_table = { + .tbl_field = 28, + .tbl_len = 4, + .tbl_ovp = NULL, + .tbl_fmt = fmt_branch, + .tbl_inp = BPcc_table_def +}; + +static const inst_t Bicc_table_def[16] = { + INST("bn", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("be", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("ble", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("bl", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + + INST("bleu", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + /* docs say it's 'bcs' but disassembler calles it synonym 'blu' */ + INST("blu", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("bneg", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("bvs", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + + INST("ba", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("bne", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("bg", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("bge", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + + INST("bgu", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + /* + * while the docs say it's officially 'bcc', existing disassembler + * uses the synonym bgeu + */ + INST("bgeu", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("bpos", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("bvc", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)) +}; + +static const table_t Bicc_table = { + .tbl_field = 28, + .tbl_len = 4, + .tbl_ovp = NULL, + .tbl_fmt = fmt_branch, + .tbl_inp = Bicc_table_def +}; + +static const inst_t BPr_table_def[16] = { + INVALID, + INST("brz", V9|V9S, FLG_PRED|FLG_DISP(DISP16)|FLG_RS1(REG_INT)), + INST("brlez", V9|V9S, FLG_PRED|FLG_DISP(DISP16)|FLG_RS1(REG_INT)), + INST("brlz", V9|V9S, FLG_PRED|FLG_DISP(DISP16)|FLG_RS1(REG_INT)), + + INVALID, + INST("brnz", V9|V9S, FLG_PRED|FLG_DISP(DISP16)|FLG_RS1(REG_INT)), + INST("brgz", V9|V9S, FLG_PRED|FLG_DISP(DISP16)|FLG_RS1(REG_INT)), + INST("brgez", V9|V9S, FLG_PRED|FLG_DISP(DISP16)|FLG_RS1(REG_INT)), + + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID +}; + +static const table_t BPr_table = { + .tbl_field = 28, + .tbl_len = 4, + .tbl_ovp = NULL, + .tbl_fmt = fmt_branch, + .tbl_inp = BPr_table_def +}; + +static const inst_t FBPfcc_table_def[16] = { + INST("fbn", V9|V9S, FLG_PRED|FLG_DISP(DISP19)|FLG_RS1(REG_FCC)), + INST("fbne", V9|V9S, FLG_PRED|FLG_DISP(DISP19)|FLG_RS1(REG_FCC)), + INST("fblg", V9|V9S, FLG_PRED|FLG_DISP(DISP19)|FLG_RS1(REG_FCC)), + INST("fbul", V9|V9S, FLG_PRED|FLG_DISP(DISP19)|FLG_RS1(REG_FCC)), + + INST("fbl", V9|V9S, FLG_PRED|FLG_DISP(DISP19)|FLG_RS1(REG_FCC)), + INST("fbug", V9|V9S, FLG_PRED|FLG_DISP(DISP19)|FLG_RS1(REG_FCC)), + INST("fbg", V9|V9S, FLG_PRED|FLG_DISP(DISP19)|FLG_RS1(REG_FCC)), + INST("fbu", V9|V9S, FLG_PRED|FLG_DISP(DISP19)|FLG_RS1(REG_FCC)), + + INST("fba", V9|V9S, FLG_PRED|FLG_DISP(DISP19)|FLG_RS1(REG_FCC)), + INST("fbe", V9|V9S, FLG_PRED|FLG_DISP(DISP19)|FLG_RS1(REG_FCC)), + INST("fbue", V9|V9S, FLG_PRED|FLG_DISP(DISP19)|FLG_RS1(REG_FCC)), + INST("fbge", V9|V9S, FLG_PRED|FLG_DISP(DISP19)|FLG_RS1(REG_FCC)), + + INST("fbuge", V9|V9S, FLG_PRED|FLG_DISP(DISP19)|FLG_RS1(REG_FCC)), + INST("fble", V9|V9S, FLG_PRED|FLG_DISP(DISP19)|FLG_RS1(REG_FCC)), + INST("fbule", V9|V9S, FLG_PRED|FLG_DISP(DISP19)|FLG_RS1(REG_FCC)), + INST("fbo", V9|V9S, FLG_PRED|FLG_DISP(DISP19)|FLG_RS1(REG_FCC)) +}; + +static const table_t FBPfcc_table = { + .tbl_field = 28, + .tbl_len = 4, + .tbl_ovp = NULL, + .tbl_fmt = fmt_branch, + .tbl_inp = FBPfcc_table_def +}; + +static const inst_t FBfcc_table_def[16] = { + INST("fbn", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("fbne", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("fblg", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("fbul", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + + INST("fbl", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("fbug", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("fbg", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("fbu", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + + INST("fba", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("fbe", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("fbue", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("fbge", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + + INST("fbuge", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("fble", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("fbule", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("fbo", VALL, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)) +}; + +static const table_t FBfcc_table = { + .tbl_field = 28, + .tbl_len = 4, + .tbl_ovp = NULL, + .tbl_fmt = fmt_branch, + .tbl_inp = FBfcc_table_def +}; + +static const inst_t CBccc_table_def[16] = { + INST("cbn", V8, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("cb123", V8, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("cb12", V8, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("cb13", V8, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("cb1", V8, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("cb23", V8, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("cb2", V8, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("cb3", V8, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("cba", V8, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("cb0", V8, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("cb03", V8, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("cb02", V8, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("cb023", V8, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("cb01", V8, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("cb013", V8, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)), + INST("cb012", V8, FLG_DISP(DISP22)|FLG_RS1(REG_NONE)) +}; + +static const table_t CBccc_table = { + .tbl_field = 28, + .tbl_len = 4, + .tbl_ovp = NULL, + .tbl_fmt = fmt_branch, + .tbl_inp = CBccc_table_def +}; + +static const inst_t branch_table_def[8] = { + INST("unimp", VALL, 0), + TABLE(BPcc_table, V9|V9S), + TABLE(Bicc_table, VALL), + TABLE(BPr_table, V9|V9S), + + INST("sethi", VALL, 0), + TABLE(FBPfcc_table, V9|V9S), + TABLE(FBfcc_table, VALL), + TABLE(CBccc_table, V8) +}; + +static const overlay_t branch_ov_table[] = { + OVERLAY(0x00, INST("illtrap", V9|V9S, 0)), + OVERLAY_END +}; + +static const table_t branch_table = { + .tbl_field = 24, + .tbl_len = 3, + .tbl_ovp = branch_ov_table, + .tbl_fmt = fmt_sethi, + .tbl_inp = branch_table_def +}; + +/* load/stores */ +static const inst_t ls_table_def[64] = { + /* 0x00 */ + INST("ld", VALL, 0), + INST("ldub", VALL, 0), + INST("lduh", VALL, 0), + INST("ldd", VALL, 0), + + INST("st", VALL, FLG_STORE), + INST("stb", VALL, FLG_STORE), + INST("sth", VALL, FLG_STORE), + INST("std", VALL, FLG_STORE), + + /* 0x08 */ + INST("ldsw", V9|V9S, 0), + INST("ldsb", VALL, 0), + INST("ldsh", VALL, 0), + INST("ldx", V9|V9S, 0), + + INVALID, + INST("ldstub", VALL, 0), + INST("stx", V9|V9S, FLG_STORE), + INST("swap", VALL, 0), + + /* 0x10 */ + INST("lda", VALL, FLG_ASI), + INST("lduba", VALL, FLG_ASI), + INST("lduha", VALL, FLG_ASI), + INST("ldda", VALL, FLG_ASI), + + INST("sta", VALL, FLG_STORE|FLG_ASI), + INST("stba", VALL, FLG_STORE|FLG_ASI), + INST("stha", VALL, FLG_STORE|FLG_ASI), + INST("stda", VALL, FLG_STORE|FLG_ASI), + + /* 0x18 */ + INST("ldswa", V9|V9S, FLG_ASI), + INST("ldsba", VALL, FLG_ASI), + INST("ldsha", VALL, FLG_ASI), + INST("ldxa", V9|V9S, FLG_ASI), + + INVALID, + INST("ldstuba", VALL, FLG_ASI), + INST("stxa", V9|V9S, FLG_STORE|FLG_ASI), + INST("swapa", VALL, FLG_ASI), + + /* 0x20 */ + INST("ld", VALL, FLG_RD(REG_FP)), + /* ldx on v9 */ + INST("ld", VALL, FLG_RD(REG_FSR)), + INST("ldq", V9|V9S, FLG_RD(REG_FPQ)), + INST("ldd", VALL, FLG_RD(REG_FPD)), + + INST("st", VALL, FLG_STORE|FLG_RD(REG_FP)), + /* stx on v9 */ + INST("st", VALL, FLG_STORE|FLG_RD(REG_FSR)), + INST("stq", VALL, FLG_STORE|FLG_RD(REG_FPQ)), + INST("std", VALL, FLG_STORE|FLG_RD(REG_FPD)), + + /* 0x28 */ + INVALID, + INVALID, + INVALID, + INVALID, + + INVALID, + INST("prefetch", V9|V9S, 0), + INVALID, + INVALID, + + /* 0x30 */ + INST("ld", V8, FLG_RD(REG_CP)), + INST("ld", V8, FLG_RD(REG_CSR)), + INST("ldqa", V9|V9S, FLG_ASI|FLG_RD(REG_FPQ)), + INST("ldd", V8, FLG_RD(REG_CP)), + + INST("st", V8, FLG_STORE|FLG_RD(REG_CP)), + INST("st", V8, FLG_STORE|FLG_RD(REG_CSR)), + INST("std", V8, FLG_STORE|FLG_RD(REG_CQ)), + INST("std", V8, FLG_STORE|FLG_RD(REG_CP)), + + /* 0x38 */ + INVALID, + INVALID, + INVALID, + INVALID, + + INST("casa", V9|V9S, 0), + INST("prefetcha", V9|V9S, FLG_STORE|FLG_ASI), + INST("casxa", V9|V9S, 0), + INVALID +}; + +static const overlay_t ld_ov_table[] = { + OVERLAY(0x10, INST("lduwa", V9|V9S, FLG_ASI|FLG_RD(REG_INT))), + OVERLAY(0x14, INST("stwa", V9|V9S, + FLG_STORE|FLG_ASI|FLG_RD(REG_INT))), + OVERLAY(0x30, INST("lda", V9|V9S, FLG_ASI|FLG_RD(REG_FP))), + OVERLAY(0x33, INST("ldda", V9|V9S, FLG_ASI|FLG_RD(REG_FPD))), + + OVERLAY(0x34, INST("sta", V9|V9S, FLG_STORE|FLG_ASI|FLG_RD(REG_FP))), + OVERLAY(0x36, INST("stqa", V9|V9S, + FLG_STORE|FLG_ASI|FLG_RD(REG_FPQ))), + OVERLAY(0x37, INST("stda", V9|V9S, + FLG_STORE|FLG_ASI|FLG_RD(REG_FPD))), + + OVERLAY_END +}; + +static const table_t ls_table = { + .tbl_field = 24, + .tbl_len = 6, + .tbl_ovp = ld_ov_table, + .tbl_fmt = fmt_ls, + .tbl_inp = ls_table_def +}; + +/* ALU operations */ +static const inst_t Tcc_table_def[16] = { + INST("tn", VALL, 0), + INST("te", VALL, 0), + INST("tle", VALL, 0), + INST("tl", VALL, 0), + + INST("tleu", VALL, 0), + INST("tcs", VALL, 0), + INST("tneg", VALL, 0), + INST("tvs", VALL, 0), + + INST("ta", VALL, 0), + INST("tne", VALL, 0), + INST("tg", VALL, 0), + INST("tge", VALL, 0), + + INST("tgu", VALL, 0), + INST("tcc", VALL, 0), + INST("tpos", VALL, 0), + INST("tvc", VALL, 0) +}; + +static const table_t Tcc_table = { + .tbl_field = 28, + .tbl_len = 4, + .tbl_ovp = NULL, + .tbl_fmt = fmt_trap, + .tbl_inp = Tcc_table_def +}; + +static const inst_t rwin_table_def[32] = { + /* 0x00 */ + INST("saved", V9|V9S, 0), + INST("restored", V9|V9S, 0), + INST("allclean", V9|V9S, 0), + INST("otherw", V9|V9S, 0), + + INST("normalw", V9|V9S, 0), + INST("invalw", V9|V9S, 0), + INVALID, + INVALID, + + /* 0x08 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x10 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID +}; + +static const table_t rwin_table = { + .tbl_field = 29, + .tbl_len = 5, + .tbl_ovp = NULL, + .tbl_fmt = fmt_regwin, + .tbl_inp = rwin_table_def +}; + +static const inst_t tr_table_def[32] = { + /* 0x00 */ + INST("done", V9|V9S, 0), + INST("retry", V9|V9S, 0), + INVALID, + INVALID, + + INVALID, + INVALID, + INVALID, + INVALID, + + /* 0x08 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x10 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID +}; + +static const table_t tr_table = { + .tbl_field = 29, + .tbl_len = 5, + .tbl_ovp = NULL, + .tbl_fmt = fmt_trap_ret, + .tbl_inp = tr_table_def +}; + +static const inst_t movicc_table_def[16] = { + INST("movn", V9|V9S, 0), + INST("move", V9|V9S, 0), + INST("movle", V9|V9S, 0), + INST("movl", V9|V9S, 0), + + INST("movleu", V9|V9S, 0), + INST("movcs", V9|V9S, 0), + INST("movneg", V9|V9S, 0), + INST("movvs", V9|V9S, 0), + + INST("mova", V9|V9S, 0), + INST("movne", V9|V9S, 0), + INST("movg", V9|V9S, 0), + INST("movge", V9|V9S, 0), + + INST("movgu", V9|V9S, 0), + INST("movcc", V9|V9S, 0), + INST("movpos", V9|V9S, 0), + INST("movvc", V9|V9S, 0) +}; + +static const inst_t movfcc_table_def[16] = { + INST("movn", V9|V9S, 0), + INST("movne", V9|V9S, 0), + INST("movlg", V9|V9S, 0), + INST("movul", V9|V9S, 0), + + INST("movl", V9|V9S, 0), + INST("movug", V9|V9S, 0), + INST("movg", V9|V9S, 0), + INST("movu", V9|V9S, 0), + + INST("mova", V9|V9S, 0), + INST("move", V9|V9S, 0), + INST("movue", V9|V9S, 0), + INST("movge", V9|V9S, 0), + + INST("movuge", V9|V9S, 0), + INST("movle", V9|V9S, 0), + INST("movule", V9|V9S, 0), + INST("movo", V9|V9S, 0) +}; + +static const table_t movfcc_table = { + .tbl_field = 17, + .tbl_len = 4, + .tbl_ovp = NULL, + .tbl_fmt = fmt_movcc, + .tbl_inp = movfcc_table_def +}; + +static const table_t movicc_table = { + .tbl_field = 17, + .tbl_len = 4, + .tbl_ovp = NULL, + .tbl_fmt = fmt_movcc, + .tbl_inp = movicc_table_def +}; + +static const inst_t movcc_table_def[2] = { + TABLE(movfcc_table, V9|V9S), + TABLE(movicc_table, V9|V9S) +}; + +static const table_t movcc_table = { + .tbl_field = 18, + .tbl_len = 1, + .tbl_ovp = NULL, + .tbl_fmt = NULL, + .tbl_inp = movcc_table_def +}; + +static const inst_t movr_table_def[8] = { + INVALID, + /* aka movrz */ + INST("movre", V9|V9S, 0), + INST("movrlez", V9|V9S, 0), + INST("movrlz", V9|V9S, 0), + + INVALID, + /* aka movrnz */ + INST("movrne", V9|V9S, 0), + INST("movrgz", V9|V9S, 0), + INST("movrgez", V9|V9S, 0) +}; + +static const table_t movr_table = { + .tbl_field = 12, + .tbl_len = 3, + .tbl_ovp = NULL, + .tbl_fmt = fmt_movr, + .tbl_inp = movr_table_def +}; + +static const inst_t FPop1_table_def[512] = { + /* 0x000 */ + INVALID, + INST("fmovs", VALL, + FLG_P1(REG_NONE)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FP)), + INST("fmovd", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FPD)|FLG_NOIMM|FLG_P3(REG_FPD)), + INST("fmovq", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FPQ)|FLG_NOIMM|FLG_P3(REG_FPQ)), + + INVALID, + INST("fnegs", VALL, + FLG_P1(REG_NONE)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FP)), + INST("fnegd", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FPD)|FLG_NOIMM|FLG_P3(REG_FPD)), + INST("fnegq", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FPQ)|FLG_NOIMM|FLG_P3(REG_FPQ)), + + /* 0x008 */ + INVALID, + INST("fabss", VALL, + FLG_P1(REG_NONE)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FP)), + INST("fabsd", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FPD)|FLG_NOIMM|FLG_P3(REG_FPD)), + INST("fabsq", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FPQ)|FLG_NOIMM|FLG_P3(REG_FPQ)), + + INVALID, INVALID, INVALID, INVALID, + + /* 0x010 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x020 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x028 */ + INVALID, + INST("fsqrts", VALL, + FLG_P1(REG_NONE)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FP)), + INST("fsqrtd", VALL, + FLG_P1(REG_NONE)|FLG_P2(REG_FPD)|FLG_NOIMM|FLG_P3(REG_FPD)), + INST("fsqrtq", VALL, + FLG_P1(REG_NONE)|FLG_P2(REG_FPQ)|FLG_NOIMM|FLG_P3(REG_FPQ)), + + INVALID, INVALID, INVALID, INVALID, + + /* 0x30 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x40 */ + INVALID, + INST("fadds", VALL, + FLG_P1(REG_FP)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FP)), + INST("faddd", VALL, + FLG_P1(REG_FPD)|FLG_P2(REG_FPD)|FLG_NOIMM|FLG_P3(REG_FPD)), + INST("faddq", VALL, + FLG_P1(REG_FPQ)|FLG_P2(REG_FPQ)|FLG_NOIMM|FLG_P3(REG_FPQ)), + + INVALID, + INST("fsubs", VALL, + FLG_P1(REG_FP)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FP)), + INST("fsubd", VALL, + FLG_P1(REG_FPD)|FLG_P2(REG_FPD)|FLG_NOIMM|FLG_P3(REG_FPD)), + INST("fsubq", VALL, + FLG_P1(REG_FPQ)|FLG_P2(REG_FPQ)|FLG_NOIMM|FLG_P3(REG_FPQ)), + + /* 0x048 */ + INVALID, + INST("fmuls", VALL, + FLG_P1(REG_FP)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FP)), + INST("fmuld", VALL, + FLG_P1(REG_FPD)|FLG_P2(REG_FPD)|FLG_NOIMM|FLG_P3(REG_FPD)), + INST("fmulq", VALL, + FLG_P1(REG_FPQ)|FLG_P2(REG_FPQ)|FLG_NOIMM|FLG_P3(REG_FPQ)), + + INVALID, + INST("fdivs", VALL, + FLG_P1(REG_FP)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FP)), + INST("fdivd", VALL, + FLG_P1(REG_FPD)|FLG_P2(REG_FPD)|FLG_NOIMM|FLG_P3(REG_FPD)), + INST("fdivq", VALL, + FLG_P1(REG_FPQ)|FLG_P2(REG_FPQ)|FLG_NOIMM|FLG_P3(REG_FPQ)), + + /* 0x050 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x060 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x068 */ + INVALID, + INST("fsmuld", VALL, + FLG_P1(REG_FP)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FPD)), + INVALID, + INVALID, + + INVALID, + INVALID, + INST("fdmulq", VALL, + FLG_P1(REG_FPD)|FLG_P2(REG_FPD)|FLG_NOIMM|FLG_P3(REG_FPQ)), + INVALID, + + /* 0x070 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x080 */ + INVALID, + INST("fstox", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FPD)), + INST("fdtox", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FPD)|FLG_NOIMM|FLG_P3(REG_FPD)), + INST("fqtox", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FPQ)|FLG_NOIMM|FLG_P3(REG_FPD)), + + INST("fxtos", V9|V9S, FLG_P1(REG_NONE)|FLG_P2(REG_FPD)|FLG_NOIMM| + FLG_P3(REG_FP)), + INVALID, + INVALID, + INVALID, + + /* 0x088 */ + INST("fxtod", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FPD)|FLG_NOIMM|FLG_P3(REG_FPD)), + INVALID, + INVALID, + INVALID, + + INST("fxtoq", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FPD)|FLG_NOIMM|FLG_P3(REG_FPQ)), + INVALID, + INVALID, + INVALID, + + /* 0x090 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x0a0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x0b0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x0c0 */ + INVALID, INVALID, INVALID, INVALID, + + INST("fitos", VALL, + FLG_P1(REG_NONE)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FP)), + INVALID, + INST("fdtos", VALL, + FLG_P1(REG_NONE)|FLG_P2(REG_FPD)|FLG_NOIMM|FLG_P3(REG_FP)), + INST("fqtos", VALL, + FLG_P1(REG_NONE)|FLG_P2(REG_FPQ)|FLG_NOIMM|FLG_P3(REG_FP)), + + /* 0x0c8 */ + INST("fitod", VALL, + FLG_P1(REG_NONE)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FPD)), + INST("fstod", VALL, + FLG_P1(REG_NONE)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FPD)), + INVALID, + INST("fqtod", VALL, + FLG_P1(REG_NONE)|FLG_P2(REG_FPQ)|FLG_NOIMM|FLG_P3(REG_FPD)), + + INST("fitoq", VALL, + FLG_P1(REG_NONE)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FPQ)), + INST("fstoq", VALL, + FLG_P1(REG_NONE)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FPQ)), + INST("fdtoq", VALL, + FLG_P1(REG_NONE)|FLG_P2(REG_FPD)|FLG_NOIMM|FLG_P3(REG_FPQ)), + INVALID, + + /* 0x0d0 */ + INVALID, + INST("fstoi", VALL, + FLG_P1(REG_NONE)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FP)), + INST("fdtoi", VALL, + FLG_P1(REG_NONE)|FLG_P2(REG_FPD)|FLG_NOIMM|FLG_P3(REG_FP)), + INST("fqtoi", VALL, + FLG_P1(REG_NONE)|FLG_P2(REG_FPQ)|FLG_NOIMM|FLG_P3(REG_FP)), + INVALID, INVALID, INVALID, INVALID, + + /* 0x0d8 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x0e0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x0f0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x100 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x110 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x120 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x130 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x140 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x150 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x160 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x170 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x180 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x190 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x1a0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x1b0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x1c0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x1d0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x1e0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x1f0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID +}; + +static const table_t FPop1_table = { + .tbl_field = 13, + .tbl_len = 9, + .tbl_ovp = NULL, + .tbl_fmt = fmt_fpop1, + .tbl_inp = FPop1_table_def +}; + +static const inst_t FPop2_table_def[512] = { + /* 0x000 */ + INVALID, + INST("fmovs", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FP)), + INST("fmovd", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FPD)|FLG_NOIMM|FLG_P3(REG_FPD)), + INST("fmovq", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FPQ)|FLG_NOIMM|FLG_P3(REG_FPQ)), + + INVALID, INVALID, INVALID, INVALID, + + /* 0x008 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x010 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x020 */ + INVALID, INVALID, INVALID, INVALID, + + INST("fmovrsz", V9|V9S, + FLG_P1(REG_INT)|FLG_NOIMM|FLG_P2(REG_FP)|FLG_P3(REG_FP)), + INST("fmovrdz", V9|V9S, + FLG_P1(REG_INT)|FLG_NOIMM|FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fmovrqz", V9|V9S, + FLG_P1(REG_INT)|FLG_NOIMM|FLG_P2(REG_FPQ)|FLG_P3(REG_FPQ)), + INVALID, + + /* 0x028 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x030 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x040 */ + INVALID, + INST("fmovs", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FP)), + INST("fmovd", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FPD)|FLG_NOIMM|FLG_P3(REG_FPD)), + INST("fmovq", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FPQ)|FLG_NOIMM|FLG_P3(REG_FPQ)), + + INST("fmovrslez", V9|V9S, + FLG_P1(REG_INT)|FLG_NOIMM|FLG_P2(REG_FP)|FLG_P3(REG_FP)), + INST("fmovrdlez", V9|V9S, + FLG_P1(REG_INT)|FLG_NOIMM|FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fmovrqlez", V9|V9S, + FLG_P1(REG_INT)|FLG_NOIMM|FLG_P2(REG_FPQ)|FLG_P3(REG_FPQ)), + INVALID, + + /* 0x048 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x050 */ + INVALID, + INST("fcmps", VALL, FLG_P1(REG_FP)|FLG_P2(REG_FP)|FLG_P3(REG_NONE) + |FLG_NOIMM), + INST("fcmpd", VALL, FLG_P1(REG_FPD)|FLG_P2(REG_FPD)|FLG_P3(REG_NONE) + |FLG_NOIMM), + INST("fcmpq", VALL, FLG_P1(REG_FPQ)|FLG_P2(REG_FPQ)|FLG_P3(REG_NONE) + |FLG_NOIMM), + + INVALID, + INST("fcmpes", VALL, FLG_P1(REG_FP)|FLG_P2(REG_FP)|FLG_P3(REG_NONE) + |FLG_NOIMM), + INST("fcmped", VALL, FLG_P1(REG_FPD)|FLG_P2(REG_FPD)|FLG_P3(REG_NONE) + |FLG_NOIMM), + INST("fcmpeq", VALL, FLG_P1(REG_FPQ)|FLG_P2(REG_FPQ)|FLG_P3(REG_NONE) + |FLG_NOIMM), + + /* 0x058 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x060 */ + INVALID, INVALID, INVALID, INVALID, + + INVALID, + INST("fmovrslz", V9|V9S, + FLG_P1(REG_INT)|FLG_NOIMM|FLG_P2(REG_FP)|FLG_P3(REG_FP)), + INST("fmovrdlz", V9|V9S, + FLG_P1(REG_INT)|FLG_NOIMM|FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fmovrqlz", V9|V9S, + FLG_P1(REG_INT)|FLG_NOIMM|FLG_P2(REG_FPQ)|FLG_P3(REG_FPQ)), + + /* 0x068 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x070 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x080 */ + INVALID, + INST("fmovs", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FP)|FLG_NOIMM|FLG_P3(REG_FP)), + INST("fmovd", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FPD)|FLG_NOIMM|FLG_P3(REG_FPD)), + INST("fmovq", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_FPQ)|FLG_NOIMM|FLG_P3(REG_FPQ)), + + INVALID, INVALID, INVALID, INVALID, + + /* 0x088 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x090 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x0a0 */ + INVALID, INVALID, INVALID, INVALID, + + INVALID, + INST("fmovrsnz", V9|V9S, + FLG_P1(REG_INT)|FLG_NOIMM|FLG_P2(REG_FP)|FLG_P3(REG_FP)), + INST("fmovrdnz", V9|V9S, + FLG_P1(REG_INT)|FLG_NOIMM|FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fmovrqnz", V9|V9S, + FLG_P1(REG_INT)|FLG_NOIMM|FLG_P2(REG_FPQ)|FLG_P3(REG_FPQ)), + + /* 0x0a8 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x0b0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x0c0 */ + INVALID, + INST("fmovs", V9|V9S, FLG_P1(REG_NONE)|FLG_P2(REG_FP)| + FLG_NOIMM|FLG_P3(REG_FP)), + INST("fmovd", V9|V9S, FLG_P1(REG_NONE)|FLG_P2(REG_FPD)| + FLG_NOIMM|FLG_P3(REG_FPD)), + INST("fmovq", V9|V9S, FLG_P1(REG_NONE)|FLG_P2(REG_FPQ)| + FLG_NOIMM|FLG_P3(REG_FPQ)), + + INVALID, + INST("fmovrsgz", V9|V9S, FLG_P1(REG_INT)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FP)), + INST("fmovrdgz", V9|V9S, FLG_P1(REG_INT)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fmovrqgz", V9|V9S, FLG_P1(REG_INT)|FLG_NOIMM| + FLG_P2(REG_FPQ)|FLG_P3(REG_FPQ)), + + /* 0x0c8 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x0d0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x0e0 */ + INVALID, INVALID, INVALID, INVALID, + + INVALID, + INST("fmovrsgez", V9|V9S, FLG_P1(REG_INT)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FP)), + INST("fmovrdgez", V9|V9S, FLG_P1(REG_INT)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fmovrqgez", V9|V9S, FLG_P1(REG_INT)|FLG_NOIMM| + FLG_P2(REG_FPQ)|FLG_P3(REG_FPQ)), + + /* 0x0e8 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x0f0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x100 */ + INVALID, + INST("fmovs", V9|V9S, FLG_P1(REG_NONE)|FLG_P2(REG_FP)| + FLG_NOIMM|FLG_P3(REG_FP)), + INST("fmovd", V9|V9S, FLG_P1(REG_NONE)|FLG_P2(REG_FPD)| + FLG_NOIMM|FLG_P3(REG_FPD)), + INST("fmovq", V9|V9S, FLG_P1(REG_NONE)|FLG_P2(REG_FPQ)| + FLG_NOIMM|FLG_P3(REG_FPQ)), + + INVALID, INVALID, INVALID, INVALID, + + /* 0x108 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x110 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x120 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x130 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x140 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x150 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x160 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x170 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x180 */ + INVALID, + INST("fmovs", V9|V9S, FLG_P1(REG_NONE)|FLG_P2(REG_FP)| + FLG_NOIMM|FLG_P3(REG_FP)), + INST("fmovd", V9|V9S, FLG_P1(REG_NONE)|FLG_P2(REG_FPD)| + FLG_NOIMM|FLG_P3(REG_FPD)), + INST("fmovq", V9|V9S, FLG_P1(REG_NONE)|FLG_P2(REG_FPQ)| + FLG_NOIMM|FLG_P3(REG_FPQ)), + + INVALID, INVALID, INVALID, INVALID, + + /* 0x188 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x190 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x1a0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x1b0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x1c0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x1d0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x1e0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x1f0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID +}; + +static const table_t FPop2_table = { + .tbl_field = 13, + .tbl_len = 9, + .tbl_ovp = NULL, + .tbl_fmt = fmt_fpop2, + .tbl_inp = FPop2_table_def +}; + +static const inst_t vis_table_def[512] = { + /* 0x000 */ + INST("edge8cc", V9S, FLG_NOIMM), + INST("edge8n", V9S, FLG_NOIMM), + INST("edge8lcc", V9S, FLG_NOIMM), + INST("edge8ln", V9S, FLG_NOIMM), + + INST("edge16cc", V9S, FLG_NOIMM), + INST("edge16n", V9S, FLG_NOIMM), + INST("edge16lcc", V9S, FLG_NOIMM), + INST("edge16ln", V9S, FLG_NOIMM), + + /* 0x008 */ + INST("edge32cc", V9S, FLG_NOIMM), + INST("edge32n", V9S, FLG_NOIMM), + INST("edge32lcc", V9S, FLG_NOIMM), + INST("edge32ln", V9S, FLG_NOIMM), + + INVALID, INVALID, INVALID, INVALID, + + /* 0x010 */ + INST("array8", V9S, FLG_NOIMM), + INVALID, + INST("array16", V9S, FLG_NOIMM), + INVALID, + + INST("array32", V9S, FLG_NOIMM), + INVALID, + INVALID, + INVALID, + + /* 0x018 */ + INST("alignaddr", V9S, FLG_NOIMM), + INST("bmask", V9S, FLG_NOIMM), + INST("alignaddrl", V9S, FLG_NOIMM), + INVALID, + + INVALID, INVALID, INVALID, INVALID, + + /* 0x020 */ + INST("fcmple16", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_INT)), + INVALID, + INST("fcmpne16", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_INT)), + INVALID, + + INST("fcmple32", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_INT)), + INVALID, + INST("fcmpne32", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_INT)), + INVALID, + + /* 0x028 */ + INST("fcmpgt16", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_INT)), + INVALID, + INST("fcmpeq16", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_INT)), + INVALID, + + INST("fcmpgt32", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_INT)), + INVALID, + INST("fcmpeq32", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_INT)), + INVALID, + + /* 0x030 */ + INVALID, + INST("fmul8x16", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INVALID, + INST("fmul8x16au", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FPD)), + + INVALID, + INST("fmul8x16al", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FPD)), + INST("fmul8sux16", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fmul8ulx16", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + + /* 0x038 */ + INST("fmuld8sux16", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FPD)), + INST("fmuld8ulx16", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FPD)), + INST("fpack32", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fpack16", V9S, FLG_P1(REG_NONE)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FP)), + + INVALID, + INST("fpackfix", V9S, FLG_P1(REG_NONE)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FP)), + INST("pdist", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INVALID, + + /* 0x040 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x048 */ + INST("faligndata", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INVALID, + INVALID, + INST("fpmerge", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FPD)), + + INST("bshuffle", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fexpand", V9S, FLG_P1(REG_NONE)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FPD)), + INVALID, + INVALID, + + /* 0x050 */ + INST("fpadd16", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fpadd16s", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FP)), + INST("fpadd32", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fpadd32s", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FP)), + + INST("fpsub16", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fpsub16s", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FP)), + INST("fpsub32", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fpsub32s", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FP)), + + /* 0x058 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x060 */ + INST("fzero", V9S, FLG_P1(REG_NONE)|FLG_P2(REG_NONE)| + FLG_P3(REG_FPD)), + INST("fzeros", V9S, FLG_P1(REG_NONE)|FLG_P2(REG_NONE)| + FLG_P3(REG_FP)), + INST("fnor", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fnors", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FP)), + + INST("fandnot2", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fandnot2s", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FP)), + INST("fnot2", V9S, FLG_P1(REG_NONE)|FLG_P2(REG_FPD)| + FLG_P3(REG_FPD)), + INST("fnot2s", V9S, FLG_P1(REG_NONE)|FLG_P2(REG_FP)| + FLG_P3(REG_FP)), + + /* 0x068 */ + INST("fandnot1", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fandnot1s", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FP)), + INST("fnot1", V9S, FLG_P1(REG_FPD)|FLG_P2(REG_NONE)| + FLG_P3(REG_FPD)), + INST("fnot1s", V9S, FLG_P1(REG_FP)|FLG_P2(REG_NONE)| + FLG_P3(REG_FP)), + + INST("fxor", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fxors", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FP)), + INST("fnand", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fnands", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FP)), + + /* 0x070 */ + INST("fand", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fands", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FP)), + INST("fxnor", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fxnors", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FP)), + + INST("fsrc1", V9S, FLG_P1(REG_FPD)|FLG_P2(REG_NONE)| + FLG_P3(REG_FPD)), + INST("fsrc1s", V9S, FLG_P1(REG_FP)|FLG_P2(REG_NONE)| + FLG_P3(REG_FP)), + INST("fornot2", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fornot2s", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FP)), + + /* 0x078 */ + INST("fsrc2", V9S, FLG_P1(REG_NONE)|FLG_P2(REG_FPD)| + FLG_P3(REG_FPD)), + INST("fsrc2s", V9S, FLG_P1(REG_NONE)|FLG_P2(REG_FP)| + FLG_P3(REG_FP)), + INST("fornot1", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fornot1s", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FP)), + + INST("for", V9S, FLG_P1(REG_FPD)|FLG_NOIMM| + FLG_P2(REG_FPD)|FLG_P3(REG_FPD)), + INST("fors", V9S, FLG_P1(REG_FP)|FLG_NOIMM| + FLG_P2(REG_FP)|FLG_P3(REG_FP)), + INST("fone", V9S, FLG_P1(REG_NONE)|FLG_P2(REG_NONE)| + FLG_P3(REG_FPD)), + INST("fones", V9S, FLG_P1(REG_NONE)|FLG_P2(REG_NONE)| + FLG_P3(REG_FP)), + + /* 0x080 */ + INST("shutdown", V9S, 0), + INST("siam", V9S, 0), + INVALID, + INVALID, + + INVALID, INVALID, INVALID, INVALID, + + /* 0x088 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x090 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x0a0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x0b0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x0c0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x0d0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x0e0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x0f0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x100 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x110 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x120 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x130 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x140 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x150 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x160 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x170 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x180 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x190 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x1a0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x1b0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x1c0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x1d0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x1e0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + + /* 0x1f0 */ + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID +}; + +static const table_t vis_table = { + .tbl_field = 13, + .tbl_len = 9, + .tbl_ovp = NULL, + .tbl_fmt = fmt_vis, + .tbl_inp = vis_table_def +}; + +static const inst_t fused_table_def[16] = { + /* 0x0 */ + INVALID, + INST("fmadds", V9O, FLG_P1(REG_FP)), + INST("fmaddd", V9O, FLG_P1(REG_FPD)), + INVALID, + + /* 0x4 */ + INVALID, + INST("fmsubs", V9O, FLG_P1(REG_FP)), + INST("fmsubd", V9O, FLG_P1(REG_FPD)), + INVALID, + + /* 0x8 */ + INVALID, + INST("fnmsubs", V9O, FLG_P1(REG_FP)), + INST("fnmsubd", V9O, FLG_P1(REG_FPD)), + INVALID, + + /* 0xc */ + INVALID, + INST("fnmadds", V9O, FLG_P1(REG_FP)), + INST("fnmaddd", V9O, FLG_P1(REG_FPD)), + INVALID +}; + +static const table_t fused_table = { + .tbl_field = 5, + .tbl_len = 4, + .tbl_ovp = NULL, + .tbl_fmt = fmt_fused, + .tbl_inp = fused_table_def +}; + +static const inst_t alu_table_def[64] = { + /* 0x00 */ + INST("add", VALL, 0), + INST("and", VALL, 0), + INST("or", VALL, 0), + INST("xor", VALL, 0), + + INST("sub", VALL, 0), + INST("andn", VALL, 0), + INST("orn", VALL, 0), + INST("xnor", VALL, 0), + + /* 0x08 */ + INST("addx", VALL, 0), + INST("mulx", V9|V9S, 0), + INST("umul", VALL, 0), + INST("smul", VALL, 0), + + INST("subx", VALL, 0), + INST("udivx", V9|V9S, 0), + INST("udiv", VALL, 0), + INST("sdiv", VALL, 0), + + /* 0x10 */ + INST("addcc", VALL, 0), + INST("andcc", VALL, 0), + INST("orcc", VALL, 0), + INST("xorcc", VALL, 0), + + INST("subcc", VALL, 0), + INST("andncc", VALL, 0), + INST("orncc", VALL, 0), + INST("xnorcc", VALL, 0), + + /* 0x18 */ + INST("addxcc", VALL, 0), + INVALID, + INST("umulcc", VALL, 0), + INST("smulcc", VALL, 0), + + INST("subxcc", VALL, 0), + INVALID, + INST("udivcc", VALL, 0), + INST("sdivcc", VALL, 0), + + /* 0x20 */ + INST("taddcc", VALL, 0), + INST("tsubcc", VALL, 0), + INST("taddcctv", VALL, 0), + INST("tsubcctv", VALL, 0), + + INST("mulscc", VALL, 0), + INST("sll", VALL, 0), + INST("srl", VALL, 0), + INST("sra", VALL, 0), + + /* 0x28 */ + INST("rd", VALL, 0), + INST("rd", V8, 0), + INST("rd", V8, 0), + INST("rd", V8, 0), + + TABLE(movcc_table, V9|V9S), + INST("sdivx", V9|V9S, 0), + INST("popc", V9|V9S, + FLG_P1(REG_NONE)|FLG_P2(REG_INT)|FLG_P3(REG_INT)), + TABLE(movr_table, V9|V9S), + + /* 0x30 */ + INST("wr", VALL, 0), + INST("wr", V8, 0), + INST("wr", V8, 0), + INST("wr", V8, 0), + + TABLE(FPop1_table, VALL), + TABLE(FPop2_table, VALL), + INST("cpop1", V8, 0), + INST("cpop2", V8, 0), /* impdep2 */ + + /* 0x38 */ + INST("jmpl", VALL, 0), + INST("rett", VALL, 0), + TABLE(Tcc_table, VALL), + INST("flush", VALL, 0), + + INST("save", VALL, 0), + INST("restore", VALL, 0), + TABLE(tr_table, V9|V9S), + INVALID +}; + +static const overlay_t alu_ov_table[] = { + OVERLAY(0x08, INST("addc", V9|V9S, 0)), + OVERLAY(0x0c, INST("subc", V9|V9S, 0)), + OVERLAY(0x18, INST("addccc", V9|V9S, 0)), + OVERLAY(0x1c, INST("subccc", V9|V9S, 0)), + + OVERLAY(0x29, INVALIDA(V9|V9S)), + OVERLAY(0x2a, INST("rdpr", V9|V9S, 0)), + OVERLAY(0x2b, INST("flushw", V9|V9S, 0)), + OVERLAY(0x31, TABLE(rwin_table, V9|V9S)), + + OVERLAY(0x32, INST("wrpr", V9|V9S, 0)), + OVERLAY(0x33, INVALIDA(V9|V9S)), + OVERLAY(0x36, TABLE(vis_table, V9S)), + OVERLAY(0x37, TABLE(fused_table, V9O)), + OVERLAY(0x39, INST("return", VALL, 0)), + + OVERLAY_END +}; + +static const table_t alu_table = { + .tbl_field = 24, + .tbl_len = 6, + .tbl_ovp = alu_ov_table, + .tbl_fmt = fmt_alu, + .tbl_inp = alu_table_def +}; + +static const inst_t initial_table_def[4] = { + TABLE(branch_table, VALL), + INST("call", VALL, 0), + TABLE(alu_table, VALL), + TABLE(ls_table, VALL) +}; + +/* NOTE: this must not be made static */ +const table_t initial_table = { + .tbl_field = 31, + .tbl_len = 2, + .tbl_ovp = NULL, + .tbl_fmt = fmt_call, + .tbl_inp = initial_table_def +}; diff --git a/usr/src/lib/libdisasm/sparcv9/Makefile b/usr/src/lib/libdisasm/sparcv9/Makefile new file mode 100644 index 0000000000..fcf90265a1 --- /dev/null +++ b/usr/src/lib/libdisasm/sparcv9/Makefile @@ -0,0 +1,39 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" + +ISASRCDIR=../$(MACH)/ + +include ../Makefile.com +include ../../Makefile.lib.64 + +TYPES=library standalone + +INSTALL_DEPS_library = $(ROOTLINKS64) $(ROOTLINT64) $(ROOTLIBS64) +INSTALL_DEPS_standalone = $(ROOTLIBS64) + +include ../Makefile.targ + +C99MODE = $(C99_ENABLE) |