diff options
Diffstat (limited to 'usr/src')
| -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 | ||||
| -rw-r--r-- | usr/src/pkgdefs/etc/exception_list_sparc | 1 | ||||
| -rw-r--r-- | usr/src/tools/scripts/mkclosed.sh | 19 |
13 files changed, 4710 insertions, 24 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) diff --git a/usr/src/pkgdefs/etc/exception_list_sparc b/usr/src/pkgdefs/etc/exception_list_sparc index 321746afcb..1c16bebe31 100644 --- a/usr/src/pkgdefs/etc/exception_list_sparc +++ b/usr/src/pkgdefs/etc/exception_list_sparc @@ -866,6 +866,7 @@ usr/include/sys/scsi/adapters/mpapi_scsi_vhci.h sparc # This library is installed in the proto area by the build of libdisasm, and is # only used when building the KMDB disasm module. # +usr/lib/libstanddisasm.so sparc usr/lib/sparcv9/libstanddisasm.so sparc # # TSol: tsol doesn't ship lint source, and tsnet isn't for customers at all. diff --git a/usr/src/tools/scripts/mkclosed.sh b/usr/src/tools/scripts/mkclosed.sh index 55f1f82e4f..3f1c1c410f 100644 --- a/usr/src/tools/scripts/mkclosed.sh +++ b/usr/src/tools/scripts/mkclosed.sh @@ -67,21 +67,8 @@ mkdir -p $closedroot || exit 1 # rather than a tar pipeline to make it easier to detect errors. # # We need /lib/libc_i18n.a & /lib/{sparcv9,amd64}/libc_i18n.a -# libdisasm is open on x86, but closed on sparc - how confusing... # -( - echo lib/libc_i18n.a - [ -n "$plat64" ] && echo lib/$plat64/libc_i18n.a - if [ "$isa" = "sparc" ]; then - echo usr/lib/libdisasm.so.1 - echo usr/lib/libdisasm.so - echo usr/lib/$plat64/libdisasm.so.1 - echo usr/lib/$plat64/libdisasm.so - echo usr/lib/$plat64/libstanddisasm.so - echo usr/lib/$plat64/llib-ldisasm.ln - echo usr/lib/llib-ldisasm - echo usr/lib/mdb/disasm - echo usr/lib/llib-ldisasm.ln - fi -) | cpio -dpu $closedroot +mkdir -p $closedroot/lib/$plat64 +cp lib/libc_i18n.a $closedroot/lib +cp lib/$plat64/libc_i18n.a $closedroot/lib/$plat64 |
