/*
* 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
* 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 2009 Jason King. All rights reserved.
* Use is subject to license terms.
*/
#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 int strcmp(const char *, const char *);
/*
* 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:
* 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 {
} format1_t;
#elif defined(_BIT_FIELDS_LTOH)
typedef struct format1 {
} format1_t;
#else
#endif
#if defined(_BIT_FIELDS_HTOL)
typedef struct format2 {
} format2_t;
#elif defined(_BIT_FIELDS_LTOH)
typedef struct format2 {
} format2_t;
#else
#endif
#if defined(_BIT_FIELDS_HTOL)
typedef struct format2a {
uint32_t a:1;
} format2a_t;
#elif defined(_BIT_FIELDS_LTOH)
typedef struct format2a {
uint32_t a:1;
} format2a_t;
#else
#endif
#if defined(_BIT_FIELDS_HTOL)
typedef struct format2b {
uint32_t a:1;
uint32_t p:1;
} format2b_t;
#elif defined(_BIT_FIELDS_LTOH)
typedef struct format2b {
uint32_t p:1;
uint32_t a:1;
} format2b_t;
#else
#endif
#if defined(_BIT_FIELDS_HTOL)
typedef struct format2c {
uint32_t a:1;
uint32_t p:1;
} format2c_t;
#elif defined(_BIT_FIELDS_LTOH)
typedef struct format2c {
uint32_t p:1;
uint32_t a:1;
} format2c_t;
#else
#endif
#if defined(_BIT_FIELDS_HTOL)
typedef struct format2d {
uint32_t i:1;
} format2d_t;
#elif defined(_BIT_FIELDS_LTOH)
typedef struct format2d {
uint32_t i:1;
} format2d_t;
#else
#endif
#if defined(_BIT_FIELDS_HTOL)
typedef struct format3 {
uint32_t i:1;
} format3_t;
#elif defined(_BIT_FIELDS_LTOH)
typedef struct format3 {
uint32_t i:1;
} format3_t;
#else
#endif
#if defined(_BIT_FIELDS_HTOL)
typedef struct format3a {
uint32_t i:1;
} format3a_t;
#elif defined(_BIT_FIELDS_LTOH)
typedef struct format3a {
uint32_t i:1;
} format3a_t;
#else
#endif
#if defined(_BIT_FIELDS_HTOL)
typedef struct format3b {
uint32_t i:1;
uint32_t x:1;
} format3b_t;
#elif defined(_BIT_FIELDS_LTOH)
typedef struct format3b {
uint32_t x:1;
uint32_t i:1;
} format3b_t;
#else
#endif
#if defined(_BIT_FIELDS_HTOL)
typedef struct format3c {
uint32_t i:1;
} format3c_t;
#elif defined(_BIT_FIELDS_LTOH)
typedef struct format3c {
uint32_t i:1;
} format3c_t;
#else
#endif
#if defined(_BIT_FIELDS_HTOL)
typedef struct format3d {
uint32_t i:1;
} format3d_t;
#elif defined(_BIT_FIELDS_LTOH)
typedef struct format3d {
uint32_t i:1;
} format3d_t;
#else
#endif
#if defined(_BIT_FIELDS_HTOL)
typedef struct formatcp {
} formatcp_t;
#elif defined(_BIT_FIELDS_LTOH)
typedef struct formatcp {
} formatcp_t;
#else
#endif
#if defined(_BIT_FIELDS_HTOL)
typedef struct formattcc {
uint32_t i:1;
} formattcc_t;
#elif defined(_BIT_FIELDS_LTOH)
typedef struct formattcc {
uint32_t i:1;
} formattcc_t;
#else
#endif
#if defined(_BIT_FIELDS_HTOL)
typedef struct formattcc2 {
uint32_t i:1;
} formattcc2_t;
#elif defined(_BIT_FIELDS_LTOH)
typedef struct formattcc2 {
uint32_t i:1;
} formattcc2_t;
#else
#endif
#if defined(_BIT_FIELDS_HTOL)
typedef struct formatmbr {
uint32_t i:1;
} formatmbr_t;
#elif defined(_BIT_FIELDS_LTOH)
typedef struct formatmbr {
uint32_t i:1;
} formatmbr_t;
#else
#endif
#if defined(_BIT_FIELDS_HTOL)
typedef struct formatfcmp {
} formatfcmp_t;
#elif defined(_BIT_FIELDS_LTOH)
typedef struct formatfcmp {
} formatfcmp_t;
#else
#endif
#if defined(_BIT_FIELDS_HTOL)
typedef struct formatfmov {
} formatfmov_t;
#elif defined(_BIT_FIELDS_LTOH)
typedef struct formatfmov {
} formatfmov_t;
#else
#endif
#if defined(_BIT_FIELDS_HTOL)
typedef struct formatfused {
#elif defined(_BIT_FIELDS_LTOH)
typedef struct formatfused {
#else
#endif
#if defined(_BIT_FIELDS_HTOL)
typedef struct formatcrypto {
#elif defined(_BIT_FIELDS_LTOH)
typedef struct formatcrypto {
#else
#endif
typedef union ifmt {
uint32_t i;
} ifmt_t;
/* integer register names */
"%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 */
"%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 */
"%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"
};
"%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"
};
"%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 */
"%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 */
"%fcc0", "%fcc1", "%fcc2", "%fcc3"
};
/* condition code names */
};
/* bitmask values for membar */
"#LoadLoad", "#StoreLoad", "#LoadStore", "#StoreStore"
};
"#Lookaside", "#MemIssue", "#Sync"
};
/* v8 ancillary state register names */
"%y", "%asr1", "%asr2", "%asr3",
"%asr4", "%asr5", "%asr6", "%asr7",
"%asr8", "%asr9", "%asr10", "%asr11",
"%asr12", "%asr13", "%asr14", "%asr15",
};
"%pcr", "%pic", "%dcr", "%gsr",
"%softint_set", "%softint_clr", "%softint", "%tick_cmpr",
"%stick", "%stick_cmpr", "%cfr", "%pause",
};
/*
* on v9, only certain registers are valid for read or writing
* these are bitmasks corresponding to which registers are valid in which
* case. Any access to %dcr is illegal.
*/
/* privledged register names on v9 */
/* TODO: compat - NULL to %priv_nn */
"%tpc", "%tnpc", "%tstate", "%tt",
"%tick", "%tba", "%pstate", "%tl",
"%pil", "%cwp", "%cansave", "%canrestore",
"%cleanwin", "%otherwin", "%wstate", "%fq",
};
/* hyper privileged register names on v9 */
};
"#n_reads", "#one_read",
"#n_writes", "#one_write",
"#n_reads_strong", "#one_read_strong",
"#n_writes_strong", "#one_write_strong",
};
static void prt_name(dis_handle_t *, const char *, int);
static const char *get_asi_name(uint8_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
{
}
#else
void
{
int i;
for (i = bitlen - 1; i >= 0; --i) {
if (i % 4 == 0 && i != 0)
}
}
#endif /* DIS_STANDALONE */
/*
* print out a call instruction
* format: call address <name>
*/
/* ARGSUSED1 */
int
{
}
NULL);
return (0);
}
int
{
}
if (idx == 0) {
/* unimp / illtrap */
return (0);
}
return (0);
}
/* ?? Should we return -1 if rd == 0 && disp != 0 */
"%%hi(0%lo), %s" : "%%hi(0x%lx), %s",
return (0);
}
/* ARGSUSED3 */
int
{
const char *r = NULL;
switch (FLG_DISP_VAL(flags)) {
case DISP22:
break;
case DISP19:
break;
case DISP16:
break;
}
}
name = "iprefetch";
}
switch (FLG_DISP_VAL(flags)) {
case DISP22:
break;
case DISP19:
break;
case DISP16:
break;
}
disp *= 4;
else
if (r == NULL)
return (-1);
if (f->f2a.a == 1)
annul = ",a";
if (f->f2b.p == 0) {
pred = ",pn";
} else {
pred = ",pt";
}
}
switch (FLG_DISP_VAL(flags)) {
case DISP22:
break;
case DISP19:
(octal != 0) ? "%s, %s0%-5lo <" :
"%s, %s0x%-04lx <", r,
break;
case DISP16:
r,
break;
}
return (0);
}
/*
*
* 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
{
int noasi = 0;
noasi = 1;
name = "cas";
}
noasi = 1;
name = "casl";
}
}
noasi = 1;
name = "casx";
}
noasi = 1;
name = "casxl";
}
}
}
if (noasi == 0) {
}
return (0);
}
/*
* 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
{
if (f->f3.i != 0) {
} else {
}
}
/* prefetch / prefetcha */
if (idx == 0x3d) {
}
/* fcn field is the same as rd */
else
}
return (0);
}
/* casa / casxa */
/* synthetic instructions & special cases */
switch (idx) {
case 0x00:
/* ld */
iname = "lduw";
break;
case 0x03:
iname = "ldtw";
break;
case 0x04:
/* stw */
iname = "stuw";
== 0)
break;
iname = "clr";
}
break;
case 0x05:
/* stb */
== 0)
break;
iname = "clrb";
}
break;
case 0x06:
/* sth */
== 0)
break;
iname = "clrh";
}
break;
case 0x07:
iname = "sttw";
break;
case 0x0e:
/* stx */
== 0)
break;
iname = "clrx";
}
break;
case 0x13:
/* ldtwa */
iname = "ldtwa";
break;
case 0x17:
/* sttwa */
iname = "sttwa";
break;
case 0x21:
case 0x25:
/*
* on sparcv8 it merely says that rd != 1 should generate an
* exception, on v9, it is illegal
*/
break;
return (-1);
break;
case 0x31:
/* stda */
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
*/
break;
if (f->f3.i != 0)
break;
return (0);
default:
break;
}
}
if (f->f3.i == 0)
if (regstr[0] != '\0') {
}
}
} else {
}
if (regstr[0] != '\0') {
}
}
return (0);
}
static int
{
}
return (0);
}
static int
{
int i, first;
if (rd == 0)
switch (idx) {
case 0x28:
/* rd */
/* stbar */
return (0);
}
/* membar */
first = 0;
for (i = 0; i < 4; ++i) {
membar_cmask[i]);
first = 1;
}
}
for (i = 0; i < 5; ++i) {
membar_mmask[i]);
first = 1;
}
}
return (0);
}
if (v9 != 0) {
} else {
mask = asr_rdmask;
}
break;
case 0x29:
if (v9 != 0) {
} else {
use_mask = 0;
}
break;
case 0x2a:
if (v9 != 0) {
mask = v9_pr_rdmask;
} else {
use_mask = 0;
}
break;
case 0x2b:
if (v9 != 0) {
/* flushw */
return (0);
}
use_mask = 0;
break;
case 0x30:
if (v9 != 0) {
} else {
mask = asr_wrmask;
}
/*
* sir is shoehorned in here, per Ultrasparc 2007
* hyperprivileged edition, section 7.88, all of
* these must be true to distinguish from WRasr
*/
f->f3.i == 1) {
return (0);
}
/* synth: mov */
== 0)
break;
if (v9 == 0) {
name = "mov";
pr_rs1 = 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
*/
use_mask = 0;
break;
case 0x32:
if (v9 != 0) {
mask = v9_pr_wrmask;
} else {
use_mask = 0;
}
break;
case 0x33:
if (v9 != 0) {
if (ridx == 30) {
/* special case for halt */
return (0);
}
} else {
use_mask = 0;
}
break;
}
return (-1);
return (-1);
if (rd != 0) {
} else {
if (pr_rs1 == 1)
if (pr_rs2 != 0) {
if (f->f3.i == 1)
else
}
}
return (0);
}
/* ARGSUSED3 */
int
{
return (-1);
return (-1);
return (-1);
return (-1);
if (f->ftcc.i == 0) {
} else {
}
return (0);
}
static int
{
name[0] = '\0';
if (f->f3b.i == 1)
}
if (f->f3b.i == 1)
else
return (0);
}
/* ARGSUSED3 */
static int
{
name = "call";
return (0);
}
return (0);
}
}
name = "jmp";
}
return (0);
return (0);
return (0);
}
int
{
int arg = 0;
switch (idx) {
/* TODO: more formats */
default:
if (f->f3.i == 0)
else
}
}
switch (idx) {
case 0x00:
/* add */
break;
name = "inc";
break;
}
name = "inc";
break;
}
break;
case 0x02:
/* or */
== 0)
break;
name = "bset";
break;
}
}
name = "clr";
break;
}
name = "mov";
break;
}
break;
case 0x04:
/* sub */
== 0)
break;
name = "neg";
break;
}
name = "neg";
break;
}
break;
name = "dec";
break;
}
name = "dec";
break;
}
break;
case 0x07:
/* xnor */
== 0)
break;
/*
* xnor -> not when you have:
* xnor %rs1, 0x0 or %g0, %rd
*/
break;
name = "not";
else
break;
case 0x10:
/* addcc */
break;
name = "inccc";
break;
}
name = "inccc";
break;
}
break;
case 0x11:
/* andcc */
break;
== 0)
break;
break;
name = "btst";
break;
case 0x12:
/* orcc */
== 0)
break;
name = "tst";
break;
}
name = "tst";
break;
}
break;
case 0x14:
/* subcc */
== 0)
break;
name = "cmp";
break;
}
break;
name = "deccc";
break;
}
name = "deccc";
break;
}
break;
case 0x25:
case 0x26:
case 0x27:
case 0x28:
case 0x29:
case 0x2a:
case 0x2b:
case 0x30:
case 0x31:
case 0x32:
case 0x33:
case 0x36:
case 0x37:
/* NOTE: overlayed on v9 */
break;
case 0x38:
/* jmpl */
case 0x39:
/* rett / return */
return (0);
case 0x3b:
/* flush */
return (0);
case 0x3c:
case 0x3d:
/* save / restore */
== 0)
break;
break;
break;
return (0);
}
arg = 1;
return (0);
}
/* ARGSUSED1 */
int
{
return (0);
}
/* ARGSUSED1 */
int
{
/* jpriv */
}
return (0);
}
/* ARGSUSED3 */
int
{
if (f->f3c.i == 0)
else
}
} else {
return (-1);
}
if (f->f3c.i == 1)
else
return (0);
}
/* ARGSUSED3 */
int
{
if (f->f3d.i == 1)
else
return (0);
}
/* ARGSUSED3 */
int
{
}
return (0);
}
int
{
"n", "e", "le", "l", "leu", "lu", "neg", "vs",
"a", "nz", "g", "ge", "gu", "geu", "pos", "vc"
};
"n", "nz", "lg", "ul", "l", "ug", "g", "u",
"a", "e", "ue", "ge", "uge", "le", "ule", "o"
};
int p_cc = 0;
switch (idx & 0x3f) {
case 0x51:
case 0x52:
case 0x53:
case 0x55:
case 0x56:
case 0x57:
break;
case 0x01:
case 0x02:
case 0x03:
break;
default:
}
}
name[0] = '\0';
if (is_fmov != 0) {
sizeof (name));
}
if (is_cmp != 0)
if (is_fmov != 0)
return (-1);
if (p_cc != 0)
return (0);
}
int
{
if (idx == 0x081) {
} else {
}
}
if (idx == 0x081) {
/* siam */
return (0);
}
return (0);
}
/* ARGSUSED3 */
int
{
return (0);
}
/* ARGSUSED3 */
int
{
}
disp *= 4;
if (f->f2d.i == 1) {
} else {
}
return (0);
}
/* ARGSUSED3 */
int
{
}
return (0);
}
/* ARGSUSED3 */
int
{
if (idx == 0x8) {
/* aes_kexpand1 */
} else {
}
return (0);
}
/*
* put name into the output buffer
* if add_space !=0, append a space after it
*/
static void
{
}
/*
* 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
{
}
#else
static void
{
}
#endif /* DIS_STANDALONE */
/*
* sign extend a val (that is 'bits' bits in length) to a 32-bit signed
* integer
*/
static int32_t
{
return (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
{
switch (format) {
case IMM_ADDR:
if (sv < 0) {
} else {
}
break;
case IMM_SIGNED:
if (sv < 0) {
break;
}
/* fall through */
default:
}
}
/*
* 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 *
{
switch (regset) {
case REG_INT:
break;
case REG_FP:
break;
case REG_FPD:
else
break;
case REG_FPQ:
else
break;
case REG_CP:
break;
case REG_ICC:
break;
case REG_FCC:
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
{
if (f->f3.i != 0)
else
}
/*
* 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
*
* 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
{
if (f->f3a.i == 0) {
} else {
const char *sign;
p2 = 1;
sign = "";
if (p2 != 0)
(octal != 0) ? "%s%s%s%s%s0%lo%s" :
"%s%s%s%s%s0x%lx%s",
sign,
else
}
}
/*
* print out the arguments to an alu operation (add, sub, etc.)
* contained 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
{
unsigned int opf = 0;
p1 = 0;
p2 = 0;
p3 = 0;
p3 = 0;
}
if (p1 != 0) {
}
if (p2 != 0) {
else if (opf == 0x136) {
/* special case for des_kexpand */
} else {
}
if (p3 != 0)
}
if (p3 != 0)
}
static const char *
{
switch (asi) {
case 0x04:
return ("ASI_N");
case 0x0c:
return ("ASI_NL");
case 0x10:
return ("ASI_AIUP");
case 0x11:
return ("ASI_AIUS");
case 0x14:
return ("ASI_REAL");
case 0x15:
return ("ASI_REAL_IO");
case 0x16:
return ("ASI_BLK_AIUP");
case 0x17:
return ("ASI_BLK_AIUS");
case 0x18:
return ("ASI_AIUPL");
case 0x19:
return ("ASI_AIUSL");
case 0x1c:
return ("ASI_REAL_L");
case 0x1d:
return ("ASI_REAL_IO_L");
case 0x1e:
return ("ASI_BLK_AIUPL");
case 0x1f:
return ("ASI_BLK_AIUS_L");
case 0x20:
return ("ASI_SCRATCHPAD");
case 0x21:
return ("ASI_MMU_CONTEXTID");
case 0x22:
return ("ASI_TWINX_AIUP");
case 0x23:
return ("ASI_TWINX_AIUS");
case 0x25:
return ("ASI_QUEUE");
case 0x26:
return ("ASI_TWINX_R");
case 0x27:
return ("ASI_TWINX_N");
case 0x2a:
return ("ASI_LDTX_AIUPL");
case 0x2b:
return ("ASI_TWINX_AIUS_L");
case 0x2e:
return ("ASI_TWINX_REAL_L");
case 0x2f:
return ("ASI_TWINX_NL");
case 0x30:
return ("ASI_AIPP");
case 0x31:
return ("ASI_AIPS");
case 0x36:
return ("ASI_AIPN");
case 0x38:
return ("ASI_AIPP_L");
case 0x39:
return ("ASI_AIPS_L");
case 0x3e:
return ("ASI_AIPN_L");
case 0x41:
return ("ASI_CMT_SHARED");
case 0x4f:
return ("ASI_HYP_SCRATCHPAD");
case 0x50:
return ("ASI_IMMU");
case 0x52:
return ("ASI_MMU_REAL");
case 0x54:
return ("ASI_MMU");
case 0x55:
return ("ASI_ITLB_DATA_ACCESS_REG");
case 0x56:
return ("ASI_ITLB_TAG_READ_REG");
case 0x57:
return ("ASI_IMMU_DEMAP");
case 0x58:
return ("ASI_DMMU / ASI_UMMU");
case 0x5c:
return ("ASI_DTLB_DATA_IN_REG");
case 0x5d:
return ("ASI_DTLB_DATA_ACCESS_REG");
case 0x5e:
return ("ASI_DTLB_TAG_READ_REG");
case 0x5f:
return ("ASI_DMMU_DEMAP");
case 0x63:
return ("ASI_CMT_PER_STRAND / ASI_CMT_PER_CORE");
case 0x80:
return ("ASI_P");
case 0x81:
return ("ASI_S");
case 0x82:
return ("ASI_PNF");
case 0x83:
return ("ASI_SNF");
case 0x88:
return ("ASI_PL");
case 0x89:
return ("ASI_SL");
case 0x8a:
return ("ASI_PNFL");
case 0x8b:
return ("ASI_SNFL");
case 0xc0:
return ("ASI_PST8_P");
case 0xc1:
return ("ASI_PST8_S");
case 0xc2:
return ("ASI_PST16_P");
case 0xc3:
return ("ASI_PST16_S");
case 0xc4:
return ("ASI_PST32_P");
case 0xc5:
return ("ASI_PST32_S");
case 0xc8:
return ("ASI_PST8_PL");
case 0xc9:
return ("ASI_PST8_SL");
case 0xca:
return ("ASI_PST16_PL");
case 0xcb:
return ("ASI_PST16_SL");
case 0xcc:
return ("ASI_PST32_PL");
case 0xcd:
return ("ASI_PST32_SL");
case 0xd0:
return ("ASI_FL8_P");
case 0xd1:
return ("ASI_FL8_S");
case 0xd2:
return ("ASI_FL16_P");
case 0xd3:
return ("ASI_FL16_S");
case 0xd8:
return ("ASI_FL8_PL");
case 0xd9:
return ("ASI_FL8_SL");
case 0xda:
return ("ASI_FL16_PL");
case 0xdb:
return ("ASI_FL16_SL");
case 0xe0:
return ("ASI_BLK_COMMIT_P");
case 0xe1:
return ("ASI_BLK_SOMMIT_S");
case 0xe2:
return ("ASI_TWINX_P");
case 0xe3:
return ("ASI_TWINX_S");
case 0xea:
return ("ASI_TWINX_PL");
case 0xeb:
return ("ASI_TWINX_SL");
case 0xf0:
return ("ASI_BLK_P");
case 0xf1:
return ("ASI_BLK_S");
case 0xf8:
return ("ASI_BLK_PL");
case 0xf9:
return ("ASI_BLK_SL");
default:
return (NULL);
}
}
/*
* just a handy function that takes care of managing the buffer length
* w/ printf
*/
/*
* PRINTF LIKE 1
*/
static void
{
ap);
}