/* +----------------------------------------------------------------+ */
/* |            Copyright (c) 1994 Stanford University.             | */
/* |                      All Rights Reserved.                      | */
/* |                                                                | */
/* |   This software is distributed with *ABSOLUTELY NO SUPPORT*    | */
/* |   and *NO WARRANTY*.   Use or reproduction of this code for    | */
/* |   commerical gains is strictly prohibited.   Otherwise, you    | */
/* |   are given permission to use or modify this code as long      | */
/* |   as you do not remove this notice.                            | */
/* +----------------------------------------------------------------+ */
/* --------------------------------------------------- */
/* | Copyright (c) 1986 MIPS Computer Systems, Inc.  | */
/* | All Rights Reserved.                            | */
/* --------------------------------------------------- */

/*
 * Copyright 1985 by MIPS Computer Systems, Inc.
 */

/* TORCH disassembler */
/* derived from MIPS instruction dissassembler by PGL October 91 */

#include <stdio.h>
#include <string.h>
#include "mips_dis.h"

#define false 0
#define true 1
typedef int boolean;
char *strcat();

#define ZERO 0

#define COMPILER_NAMES tdis_reg_names[0]
#define HARDWARE_NAMES tdis_reg_names[1]
#define ASSEMBLER_NAMES tdis_reg_names[2]
#define DIS_REG_NAMES(x)	tdis_reg_names[x]

union extension_byte {
    unsigned char byte;
    struct {	/* extension byte bits in little-endian order */
#if (defined __MIPSEB || defined _MIPSEB || defined MIPSEB)
	unsigned reserved:1;
	unsigned dyn_nop:1;
	unsigned rs_boost:2;
	unsigned rt_boost:2;
	unsigned rd_boost:2;
#elif (defined __MIPSEL || defined _MIPSEL || defined MIPSEL)
	unsigned rd_boost:2;
	unsigned rt_boost:2;
	unsigned rs_boost:2;
	unsigned dyn_nop:1;
	unsigned reserved:1;
#endif /*MIPSEB*/
    } e;
};

#define blez_op_T	blez_op
#define blez_op_N	(blez_op | 0x10)
#define bgtz_op_T	bgtz_op
#define bgtz_op_N	(bgtz_op | 0x10)
#define beq_op_T	beq_op
#define beq_op_N	(beq_op | 0x10)
#define bne_op_T	bne_op
#define bne_op_N	(bne_op | 0x10)
#define bc_op_T		bc_op
#define bc_op_N		(bc_op | 0x02)

static char *op_name[64] = {
/* 0 */	"special",	"regimm","j",	"jal",	"beq",  "bne",  "blez", "bgtz",
/* 8 */	"addi",	"addiu","slti",	"sltiu","andi",	"ori",	"xori",	"lui",
/*16 */	"cop0",	"cop1",	"cop2",	"cop3",	"beql","bnel","blezl","bgtzl",
/*24 */	"op60",	"op64",	"op68",	"op6c",	"op70",	"op74",	"op78",	"op7c",
/*32 */	"lb",	"lh",	"lwl",	"lw",	"lbu",	"lhu",	"lwr",	"ld",
/*40 */	"sb",	"sh",	"swl",	"sw",	"opb0",	"opb4",	"swr",	"sd",
/*48 */	"lwc0",	"lwc1",	"lwc2",	"lwc3",	"ldc0",	"ldc1",	"ldc2",	"ldc3",
/*56 */	"swc0",	"swc1",	"swc2",	"swc3",	"sdc0",	"sdc1",	"sdc2",	"sdc3"
};

static char *spec_name[64] = {
/* 0*/ "sll",	"spec01","srl",	"sra",	"sllv",	"spec05","srlv","srav",
/* 8*/ "jr",	"jalr",	"spec12","spec13","syscall","break","vcall","spec17",
/*16*/ "mfhi",	"mthi",	"mflo",	"mtlo",	"spec24","spec25","spec26","spec27",
/*24*/ "mult",	"multu","div",	"divu",	"spec34","spec35","spec36","spec37",
/*32*/ "add",	"addu",	"sub",	"subu",	"and",	"or",	"xor",	"nor",
/*40*/ "spec50","spec51","slt","sltu",	"spec54","spec55","spec56","spec57",
/*48*/ "spec60","spec61","spec62","spec63","spec64","spec65","spec66","spec67",
/*56*/ "spec70","spec71","spec72","spec73","spec74","spec75","spec76","spec77"
};

static char *bcond_name[32] = {
	"bltz",
	"bgez",
	"bltzl",
	"bgezl",
	"bcond04",
	"bcond05",
	"bcond06",
	"bcond07",
	"tgei",
	"tgeiu",
	"tlti",
	"tltiu",
	"teqi",
	"bcond0d",
	"tnei",
	"bcond0f",
	"bltzal",
	"bgezal",
	"bltzall",
	"bgezall",
	"bcond14",
	"bcond15",
	"bcond16",
	"bcond17",
	"bcond18",
	"bcond19",
	"bcond1a",
	"bcond1b",
	"bcond1c",
	"bcond1d",
	"bcond1e",
	"bcond1f"
};

static char *cop1_name[64] = {
/* 0 */	"add",	"sub",	"mul",	"div",	"sqrt", "abs",	"mov",	"neg",
/* 8 */	"fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f",
/*16 */	"fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17",
/*24 */	"fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f",
/*32 */	"cvt.s","cvt.d","cvt.e","fop23","cvt.w","fop25","fop26","fop27",
/*40 */	"fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f",
/*48 */	"c.f", "c.un","c.eq","c.ueq","c.olt","c.ult","c.ole","c.ule",
/*56 */	"c.sf","c.ngle","c.seq","c.ngl","c.lt","c.nge","c.le","c.ngt"
};

static char *fmt_name[16] = {
	"s",	"d",	"e",	"q",
	"w",	"fmt5",	"fmt6",	"fmt7",
	"fmt8",	"fmt9",	"fmta",	"fmtb",
	"fmtc",	"fmtd",	"fmte",	"fmtf"
};

/* public */
/* Three sets of commonly used register names */
const char *tdis_reg_names[3][64] = {
    {   /* compiler names */
	"zero",	"at",	"v0",	"v1",	"a0",	"a1",	"a2",	"a3",
	"t0",	"t1",	"t2",	"t3",	"t4",	"t5",	"t6",	"t7",
	"s0",	"s1",	"s2",	"s3",	"s4",	"s5",	"s6",	"s7",
	"t8",	"t9",	"k0",	"k1",	"gp",	"sp",	"s8",	"ra",
	"zero.B","at.B","v0.B",	"v1.B",	"a0.B",	"a1.B",	"a2.B",	"a3.B",
	"t0.B",	"t1.B",	"t2.B",	"t3.B",	"t4.B",	"t5.B",	"t6.B",	"t7.B",
	"s0.B",	"s1.B",	"s2.B",	"s3.B",	"s4.B",	"s5.B",	"s6.B",	"s7.B",
	"t8.B",	"t9.B",	"k0.B",	"k1.B",	"gp.B",	"sp.B",	"s8.B",	"ra.B"
    },
    {	/* hardware names */
	"r0",	"r1",	"r2",	"r3",	"r4",	"r5",	"r6",	"r7",
	"r8",	"r9",	"r10",	"r11",	"r12",	"r13",	"r14",	"r15",
	"r16",	"r17",	"r18",	"r19",	"r20",	"r21",	"r22",	"r23",
	"r24",	"r25",	"r26",	"r27",	"gp",	"sp",	"r30",	"r31",
	"r0.B",	"r1.B",	"r2.B",	"r3.B",	"r4.B",	"r5.B",	"r6.B",	"r7.B",
	"r8.B",	"r9.B",	"r10.B","r11.B","r12.B","r13.B","r14.B","r15.B",
	"r16.B","r17.B","r18.B","r19.B","r20.B","r21.B","r22.B","r23.B",
	"r24.B","r25.B","r26.B","r27.B","gp.B",	"sp.B",	"r30.B","r31.B"
    },
    {	/* assembler names */
	"$0",	"$at",	"$2",	"$3",	"$4",	"$5",	"$6",	"$7",
	"$8",	"$9",	"$10",	"$11",	"$12",	"$13",	"$14",	"$15",
	"$16",	"$17",	"$18",	"$19",	"$20",	"$21",	"$22",	"$23",
	"$24",	"$25",	"$26",	"$27",	"$gp",	"$sp",	"$30",	"$31",
	"$0.B",	"$at.B","$2.B",	"$3.B",	"$4.B",	"$5.B",	"$6.B",	"$7.B",
	"$8.B",	"$9.B",	"$10.B","$11.B","$12.B","$13.B","$14.B","$15.B",
	"$16.B","$17.B","$18.B","$19.B","$20.B","$21.B","$22.B","$23.B",
	"$24.B","$25.B","$26.B","$27.B","$gp.B","$sp.B","$30.B","$31.B"
    }
};

static char *c0_opname[64] = {
    "c0op0","tlbr","tlbwi","c0op3","c0op4","c0op5","tlbwr","c0op7",
    "tlbp","c0op9","c0op10","c0op11","c0op12","c0op13","c0op14","c0op15",
    "rfe","c0op17","c0op18","c0op19","c0op20","c0op21","c0op22","c0op23",
    "c0op24","c0op25","c0op26","c0op27","c0op28","c0op29","c0op30","c0op31",
    "c0op32","c0op33","c0op34","c0op35","c0op36","c0op37","c0op38","c0op39",
    "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47",
    "c0op48","c0op49","c0op50","c0op51","c0op52","c0op53","c0op54","c0op55",
    "c0op56","c0op57","c0op58","c0op59","c0op60","c0op61","c0op62","c0op63"
};

static char *c0_reg[32] = {
    "index","random","tlblo","c0r3","context","c0r5","c0r6","c0r7",
    "badvaddr","c0r9","tlbhi","epcn","sr",	"cause","epc",	"c0r15",
    "c0r16","c0r17","c0r18","c0r19","c0r20","c0r21","c0r22","c0r23",
    "c0r24","c0r25","c0r26","c0r27","c0r28","c0r29","c0r30","c0r31"
};

/* Remember the options set by dis_init */
//#define ADDR_DEFAULT "%#010x:\t"
#define ADDR_DEFAULT 0
//#define VALUE_DEFAULT "%#010x\t"
#define VALUE_DEFAULT 0
#define NAME_DEFAULT COMPILER_NAMES
static struct {
    char *addr_format;
    char *value_format;
    const char **reg_names;
    int print_jal_targets;
} save = {
    ADDR_DEFAULT,
    VALUE_DEFAULT,
    NAME_DEFAULT,
    true
};

/* Update regmask to reflect the use of this general-purpose (not fp)
  register, and return its name */
static const char *
register_name(ireg, boosted, regmask)
unsigned ireg, *regmask;
int boosted;
{
    if (!boosted)
	*regmask |= (1 << ireg);
    return save.reg_names[boosted ? ireg + 32 : ireg];
}

/* public -- see dissassembler.h */
int
tdisasm(buffer, address, iword, ext, regmask, symbol_value, ls_register)
char *buffer;
unsigned char ext;	/* extension byte */
unsigned address, iword, *regmask, *symbol_value, *ls_register;
{
    int return_value = 0;
    char *bufptr = buffer;
    boolean do_b_displacement = false;
    boolean do_loadstore = false;
    union mips_instruction i;
    union extension_byte e;

	*bufptr = 0;
    i.word = iword;
    e.byte = ext;
    *regmask = *symbol_value = *ls_register = 0;

    /* Put out the address and hex value of the instruction,
       leaving bufptr set at the end */
    if (save.addr_format) {
	sprintf(bufptr, save.addr_format, address);
	bufptr += strlen(bufptr);
    }
    if (save.value_format) {
	sprintf(bufptr, save.value_format, iword);
	bufptr += strlen(bufptr);
    }

    /* check for dynamic NOP */
    if (e.e.dyn_nop) {
	strcat(bufptr, "D.");
	bufptr += 2;
    }

    /* decode the instruction */
    switch (i.j_format.opcode) {

    case spec_op:

	if (i.word == 0x20) {
	    strcat(bufptr, "nop");
	    if (e.e.rd_boost)
		strcat(bufptr, ".B");
	    bufptr += strlen(bufptr);
	    break;
	} else if (i.r_format.func == addu_op && i.r_format.rt == ZERO) {
	    sprintf(bufptr, "move%s\t%s,%s",
		    e.e.rd_boost ? ".B" : "",
		    register_name(i.r_format.rd, e.e.rd_boost, regmask),
		    register_name(i.r_format.rs, e.e.rs_boost, regmask));
	    bufptr += strlen(bufptr);
	    break;
	}
	strcat(bufptr, spec_name[i.r_format.func]);
	if (e.e.rd_boost)
	    strcat(bufptr, ".B");
	bufptr += strlen(bufptr);

	switch (i.r_format.func) {
	case sll_op:
	case srl_op:
	case sra_op:
	    sprintf(bufptr, "\t%s,%s,%d",
		    register_name(i.r_format.rd, e.e.rd_boost, regmask),
		    register_name(i.r_format.rt, e.e.rt_boost, regmask),
		    i.r_format.re);
	    break;
	case sllv_op:
	case srlv_op:
	case srav_op:
	    sprintf(bufptr, "\t%s,%s,%s",
		    register_name(i.r_format.rd, e.e.rd_boost, regmask),
		    register_name(i.r_format.rt, e.e.rt_boost, regmask),
		    register_name(i.r_format.rs, e.e.rs_boost, regmask));
	    break;
	case mfhi_op:
	case mflo_op:
	    sprintf(bufptr, "\t%s",
		    register_name(i.r_format.rd, e.e.rd_boost, regmask));
	    break;
	case jalr_op:
	    return_value = 3;
	    sprintf(bufptr, "\t%s,%s",
		    register_name(i.r_format.rd, e.e.rd_boost, regmask),
		    register_name(i.r_format.rs, e.e.rs_boost, regmask));
	    *ls_register = i.r_format.rs;
	    break;
	case jr_op:
	    return_value = 3;
	    *ls_register = i.r_format.rs;
	    /* fall through */
	case mtlo_op:
	case mthi_op:
	    sprintf(bufptr, "\t%s",
		    register_name(i.r_format.rs, e.e.rs_boost, regmask));
	    break;
	case mult_op:
	case multu_op:
	case div_op:
	case divu_op:
	    sprintf(bufptr, "\t%s,%s",
		    register_name(i.r_format.rs, e.e.rs_boost, regmask),
		    register_name(i.r_format.rt, e.e.rt_boost, regmask));
	    break;
	case syscall_op:
	    break;
	case break_op:
	case vcall_op:
	    {
		char *format = "\t%d";
		unsigned op2 = i.r_format.rd * 32 + i.r_format.re;

		if (op2)
		    format = "\t%d,%d";
		sprintf(bufptr, format, i.r_format.rs*32+i.r_format.rt,
			op2);
	    }
	    break;
	default:
	    sprintf(bufptr, "\t%s,%s,%s",
		    register_name(i.r_format.rd, e.e.rd_boost, regmask),
		    register_name(i.r_format.rs, e.e.rs_boost, regmask),
		    register_name(i.r_format.rt, e.e.rt_boost, regmask));
	    break;
	};
	break;

    case bcond_op:
	sprintf(bufptr, "%s%s\t%s,",
		bcond_name[i.i_format.rt],
		e.e.rd_boost ? ".B" : "",
		register_name(i.i_format.rs, e.e.rs_boost, regmask));
	do_b_displacement = true;
	break;

    case blez_op_T:
    case bgtz_op_T:
    case blez_op_N:
    case bgtz_op_N:
	sprintf(bufptr, "%s%s\t%s,", op_name[i.i_format.opcode],
		e.e.rd_boost ? ".B" : "",
		register_name(i.i_format.rs, e.e.rs_boost, regmask));
	do_b_displacement = true;
	break;
    case beq_op_T:
    case beq_op_N:
	if (i.i_format.rs == ZERO && i.i_format.rt == ZERO) {
	    strcat(bufptr, "b");
	    if (i.j_format.opcode == beq_op_T)
		strcat(bufptr, ".T");
	    else
		strcat(bufptr, ".N");
	    if (e.e.rd_boost)
		strcat(bufptr, ".B\t");
	    else
		strcat(bufptr, "\t");
	    do_b_displacement = true;
	    break;
	}
	/* fall through */
    case bne_op_T:
    case bne_op_N:
	sprintf(bufptr, "%s%s\t%s,%s,", op_name[i.i_format.opcode],
		e.e.rd_boost ? ".B" : "",
		register_name(i.i_format.rs, e.e.rs_boost, regmask),
		register_name(i.i_format.rt, e.e.rt_boost, regmask));
	do_b_displacement = true;
	break;

    case cop0_op:
    case cop1_op:
    case cop2_op:
    case cop3_op:
	{
	    unsigned which_cop = i.j_format.opcode - cop0_op;
	    char *f_or_r = "rf";

	    switch (i.r_format.rs) {
	    case bc_op_T:
		sprintf(bufptr, "bc%d%c.T%s\t", which_cop,
			"ft"[i.r_format.rt],
			e.e.rd_boost ? ".B" : "");
		do_b_displacement = true;
		break;
	    case bc_op_N:
		sprintf(bufptr, "bc%d%c.N%s\t", which_cop,
			"ft"[i.r_format.rt],
			e.e.rd_boost ? ".B" : "");
		do_b_displacement = true;
		break;
	    case mtc_op:
		if (which_cop == 0)
		    sprintf(bufptr, "mtc%d%s\t%s,%s", which_cop,
			    e.e.rd_boost ? ".B" : "",
			    register_name(i.r_format.rt, e.e.rt_boost,regmask),
			    c0_reg[i.f_format.rd]);
		else
		    sprintf(bufptr, "mtc%d%s\t%s,%c%d", which_cop,
			    e.e.rd_boost ? ".B" : "",
			    register_name(i.r_format.rt, e.e.rt_boost,regmask),
			    f_or_r[(which_cop == 1)],
			    i.f_format.rd);
		break;
	    case mfc_op:
		if (which_cop == 0)
		    sprintf(bufptr, "mfc%d%s\t%s,%s", which_cop,
			    e.e.rd_boost ? ".B" : "",
			    register_name(i.r_format.rt, e.e.rt_boost,regmask),
			    c0_reg[i.f_format.rd]);
		else
		    sprintf(bufptr, "mfc%d%s\t%s,%c%d", which_cop,
			    e.e.rd_boost ? ".B" : "",
			    register_name(i.r_format.rt, e.e.rt_boost,regmask),
			    f_or_r[(which_cop == 1)],
			    i.f_format.rd);
		break;
	    case cfc_op:
		sprintf(bufptr, "cfc%d%s\t%s,%c%d", which_cop,
			e.e.rd_boost ? ".B" : "",
			register_name(i.r_format.rt, e.e.rt_boost, regmask),
			f_or_r[(which_cop == 1)],
			i.f_format.rd);
		break;
	    case ctc_op:
		sprintf(bufptr, "ctc%d%s\t%s,%c%d", which_cop,
			e.e.rd_boost ? ".B" : "",
			register_name(i.r_format.rt, e.e.rt_boost, regmask),
			f_or_r[(which_cop == 1)],
			i.f_format.rd);
		break;
	    default:
		if (which_cop != 1)
		    sprintf(bufptr, "c0%s\t%s", e.e.rd_boost ? ".B" : "",
			    c0_opname[i.f_format.func]);
		else
		    {
			sprintf(bufptr, "%s.%s%s\t",
				cop1_name[i.f_format.func],
				fmt_name[i.f_format.fmt],
				e.e.rd_boost ? ".B" : "");
			bufptr += strlen(bufptr);
			switch (i.f_format.func) {
			case fsqrt_op:
			case fabs_op:
			case fmov_op:
			case fcvts_op:
			case fcvtd_op:
			case fcvte_op:
			case fcvtw_op:
			    sprintf(bufptr, "f%d,f%d",
				    i.f_format.re,
				    i.f_format.rd);
			    break;
			case fcmp_op+0x0:
			case fcmp_op+0x1:
			case fcmp_op+0x2:
			case fcmp_op+0x3:
			case fcmp_op+0x4:
			case fcmp_op+0x5:
			case fcmp_op+0x6:
			case fcmp_op+0x7:
			case fcmp_op+0x8:
			case fcmp_op+0x9:
			case fcmp_op+0xa:
			case fcmp_op+0xb:
			case fcmp_op+0xc:
			case fcmp_op+0xd:
			case fcmp_op+0xe:
			case fcmp_op+0xf:
			    sprintf(bufptr, "f%d,f%d",
				    i.f_format.rd,
				    i.f_format.rt);
			    break;
			default:
			    sprintf(bufptr, "f%d,f%d,f%d",
				    i.f_format.re,
				    i.f_format.rd,
				    i.f_format.rt);
			    break;
			}	/* switch on func */
		    }
		break;		/* End of default */
	    }			/* switch on rs */
	}
	break;			/* End of cop0, cop1, cop2, cop3 */

    case jal_op:
    case j_op:
	sprintf(bufptr, "%s%s\t", op_name[i.j_format.opcode],
		e.e.rd_boost ? ".B" : "");
	*symbol_value = (address & 0xF0000000) | i.j_format.target << 2;
	if (save.print_jal_targets)
	    {
		bufptr += strlen(bufptr);
		sprintf(bufptr, "%#x", *symbol_value);
	    }
	return_value = 1;
	break;

    case swc1_op:
    case sdc1_op:
    case lwc1_op:
    case ldc1_op:
	sprintf(bufptr, "%s%s\tf%d,", op_name[i.i_format.opcode],
		e.e.rd_boost ? ".B" : "",
		i.i_format.rt);
	do_loadstore = true;
	break;

    case lb_op:
    case lh_op:
    case lw_op:
    case ld_op:
    case lbu_op:
    case lhu_op:
    case sb_op:
    case sh_op:
    case sw_op:
    case sd_op:
    case lwl_op:
    case lwr_op:
	sprintf(bufptr, "%s%s\t%s,", op_name[i.i_format.opcode],
		e.e.rd_boost ? ".B" : "",
		register_name(i.i_format.rt, e.e.rt_boost, regmask));
	do_loadstore = true;
	break;

    case ori_op:
    case xori_op:
	if (i.u_format.rs == ZERO) {
	    sprintf(bufptr, "li%s\t%s,%d",
		    e.e.rd_boost ? ".B" : "",
		    register_name(i.u_format.rt, e.e.rt_boost, regmask),
		    i.u_format.uimmediate);
	    break;
	}
	/* fall through */
    case andi_op:
	sprintf(bufptr, "%s%s\t%s,%s,%#x", op_name[i.u_format.opcode],
		e.e.rd_boost ? ".B" : "",
		register_name(i.u_format.rt, e.e.rt_boost, regmask),
		register_name(i.u_format.rs, e.e.rs_boost, regmask),
		i.u_format.uimmediate);
	break;
    case lui_op:
	sprintf(bufptr, "%s%s\t%s,%#x", op_name[i.u_format.opcode],
		e.e.rd_boost ? ".B" : "",
		register_name(i.u_format.rt, e.e.rt_boost, regmask),
		i.u_format.uimmediate);
	break;
    case addi_op:
    case addiu_op:
	if (i.i_format.rs == ZERO) {
	    short sign_extender = i.i_format.simmediate;
	    sprintf(bufptr, "li%s\t%s,%d",
		    e.e.rd_boost ? ".B" : "",
		    register_name(i.i_format.rt, e.e.rt_boost, regmask),
		    sign_extender);
	    break;
	}
	/* fall through */
    default:
	{
	    short sign_extender = i.i_format.simmediate;
	    sprintf(bufptr, "%s%s\t%s,%s,%d", op_name[i.i_format.opcode],
		    e.e.rd_boost ? ".B" : "",
		    register_name(i.i_format.rt, e.e.rt_boost, regmask),
		    register_name(i.i_format.rs, e.e.rs_boost, regmask),
		    sign_extender);
	}
	break;
    }

    /* Some instructions require more than just registers */

    if (do_loadstore)
	{
	    short sign_extender = i.i_format.simmediate;
	    *symbol_value = sign_extender;
	    *ls_register = i.i_format.rs;
	    bufptr += strlen(bufptr);
	    sprintf(bufptr, "%d(%s)", sign_extender,
		    register_name(i.i_format.rs, e.e.rs_boost, regmask));
	    return_value = -1;
	}
    else if (do_b_displacement)
	{
	    short sign_extender = i.i_format.simmediate;
	    bufptr += strlen(bufptr);
	    *symbol_value = 4 + address + ((((long)sign_extender & 0xFFFD0000) | (0x3FFFF & (sign_extender << 2))));
	    sprintf(bufptr, "%#x", *symbol_value);
	    return_value = 2;
	}

    return return_value;
}

