/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:unasm.c 12.0$ */
/* $ACIS:unasm.c 12.0$ */
/* $Source: /ibm/acis/usr/src/bin/adb_ca/RCS/unasm.c,v $ */

#ifndef lint
static char *rcsid = "$Header:unasm.c 12.0$";
#endif

/* disassembler for ibm032 -- 1/84 by J.Christensen */
 
/* instruction formats */
 
#ifdef SYMBOLIC	/* need to know about symbol tables */
#include "defs.h"
#include <stab.h>
#endif

#define UNK   0
#define JI    1
#define RI    2
#define RI16  3
#define RR    4
#define SRI   5
#define SRR   6
#define R00   7
#define R0R   8
#define RRR   9
#define RC   10
#define BI   11
#define BRI  12
#define BA   13
#define DSC  14  /* see note 1 */
#define DSH  15  /* see note 1 */
#define DSL  16  /* see note 1 */
#define DIR  17
#define DRI  18
#define DIIR 19
#define DRIR 20
#define DRUR 21
#define DRRI 22
#define DRRU 23
#define DTI  24
 
/* instruction decode tables */
 
static char ltab[] = {
    2,  /* UNK  */
    2,  /* JI   */
    2,  /* RI   */
    2,  /* RI16 */
    2,  /* RR   */
    2,  /* SRI  */
    2,  /* SRR  */
    2,  /* R00  */
    2,  /* R0R  */
    2,  /* RRR  */
    2,  /* RC   */
    4,  /* BI   */
    4,  /* BRI  */
    4,  /* BA   */
    2,  /* DSC  */
    2,  /* DSH  */
    2,  /* DSL  */
    4,  /* DIR  */
    4,  /* DRI  */
    4,  /* DIIR */
    4,  /* DRIR */
    4,  /* DRUR */
    4,  /* DRRI */
    4,  /* DRRU */
    4,  /* DTI  */
};
 
struct s_tXX {
    char opc[7];
    char fmt;
};
 
static struct s_tXX t0X[] = {
    "j     ",   JI,
};
static struct s_tXX t1X[] = {
    "stcs  ",   DSC,
};
static struct s_tXX t2X[] = {
    "sths  ",   DSH,
};
static struct s_tXX t3X[] = {
    "sts   ",   DSL,
};
static struct s_tXX t4X[] = {
    "lcs   ",   DSC,
};
static struct s_tXX t5X[] = {
    "lhas  ",   DSH,
};
static struct s_tXX t6X[] = {
    "cas   ",   RRR,
};
static struct s_tXX t7X[] = {
    "ls    ",   DSL,
};
static struct s_tXX t8X[] = {
    "???   ",   UNK, /* 0x80 */
    "???   ",   UNK, /* 0x81 */
    "???   ",   UNK, /* 0x82 */
    "???   ",   UNK, /* 0x83 */
    "???   ",   UNK, /* 0x84 */
    "???   ",   UNK, /* 0x85 */
    "???   ",   UNK, /* 0x86 */
    "???   ",   UNK, /* 0x87 */
    "b     ",   BI,  /* 0x88 */
    "b     ",   BI,  /* 0x89 */
    "bala  ",   BA,  /* 0x8A */
    "balax ",   BA,  /* 0x8B */
    "bali  ",   BRI, /* 0x8C */
    "balix ",   BRI, /* 0x8D */
    "b     ",   BI,  /* 0x8E */
    "b     ",   BI,  /* 0x8F */
};
static struct s_tXX t9X[] = {
    "ais   ",   RI,  /* 0x90 */
    "inc   ",   RI,  /* 0x91 */
    "sis   ",   RI,  /* 0x92 */
    "dec   ",   RI,  /* 0x93 */
    "cis   ",   RI,  /* 0x94 */
    "clrsb ",   SRI, /* 0x95 */
    "mfs   ",   SRR, /* 0x96 */
    "setsb ",   SRI, /* 0x97 */
    "clrb  ",   RI,  /* 0x98 */  /* clbbu */
    "clrb  ",   RI16,/* 0x99 */  /* clbbl */
    "setb  ",   RI,  /* 0x9A */  /* setbu */
    "setb  ",   RI16,/* 0x9B */  /* setbl */
    "mftbi ",   RI,  /* 0x9C */  /* mftbiu */
    "mftbi ",   RI16,/* 0x9D */  /* mftbil */
    "mttbi ",   RI,  /* 0x9E */  /* mttbiu */
    "mttbi ",   RI16,/* 0x9F */  /* mttbil */
};
static struct s_tXX tAX[] = {
    "sari  ",   RI,  /* 0xA0 */  /* sari   */
    "sari  ",   RI16,/* 0xA1 */  /* sari16 */
    "???   ",   UNK, /* 0xA2 */
    "???   ",   UNK, /* 0xA3 */
    "lis   ",   RI,  /* 0xA4 */
    "???   ",   UNK, /* 0xA5 */
    "???   ",   UNK, /* 0xA6 */
    "???   ",   UNK, /* 0xA7 */
    "sri   ",   RI,  /* 0xA8 */  /* sri   */
    "sri   ",   RI16,/* 0xA9 */  /* sri16 */
    "sli   ",   RI,  /* 0xAA */  /* sli   */
    "sli   ",   RI16,/* 0xAB */  /* sli16 */
    "srpi  ",   RI,  /* 0xAC */  /* srpi   */
    "srpi  ",   RI16,/* 0xAD */  /* srpi16 */
    "slpi  ",   RI,  /* 0xAE */  /* slpi   */
    "slpi  ",   RI16,/* 0xAF */  /* slpi16 */
};
static struct s_tXX tBX[] = {
    "sar   ",   RR,  /* 0xB0 */
    "exts  ",   RR,  /* 0xB1 */
    "sf    ",   RR,  /* 0xB2 */
    "cl    ",   RR,  /* 0xB3 */
    "c     ",   RR,  /* 0xB4 */
    "mts   ",   SRR, /* 0xB5 */
    "d     ",   RR,  /* 0xB6 */
    "???   ",   UNK, /* 0xB7 */
    "sr    ",   RR,  /* 0xB8 */
    "srp   ",   RR,  /* 0xB9 */
    "sl    ",   RR,  /* 0xBA */
    "slp   ",   RR,  /* 0xBB */
    "mftb  ",   RR,  /* 0xBC */
    "tgte  ",   RR,  /* 0xBD */
    "tlt   ",   RR,  /* 0xBE */
    "mttb  ",   RR,  /* 0xBF */
};
static struct s_tXX tCX[] = {
    "svc   ",   DIR, /* 0xC0 */
    "ai    ",   DRRI,/* 0xC1 */
    "cal16 ",   DRUR,/* 0xC2 */
    "oiu   ",   DRRU,/* 0xC3 */
    "oil   ",   DRRU,/* 0xC4 */
    "nilz  ",   DRRU,/* 0xC5 */
    "nilo  ",   DRRU,/* 0xC6 */
    "xil   ",   DRRU,/* 0xC7 */
    "cal   ",   DRIR,/* 0xC8 */
    "lm    ",   DRIR,/* 0xC9 */
    "lha   ",   DRIR,/* 0xCA */
    "ior   ",   DRIR,/* 0xCB */
    "ti    ",   DTI, /* 0xCC */
    "l     ",   DRIR,/* 0xCD */
    "lc    ",   DRIR,/* 0xCE */
    "tsh   ",   DRIR,/* 0xCF */
};
static struct s_tXX tDX[] = {
    "lps   ",   DIIR,/* 0xD0 */
    "aei   ",   DRRI,/* 0xD1 */
    "sfi   ",   DRRI,/* 0xD2 */
    "cli   ",   DRI, /* 0xD3 */
    "ci    ",   DRI, /* 0xD4 */
    "niuz  ",   DRRU,/* 0xD5 */
    "niuo  ",   DRRU,/* 0xD6 */
    "xiu   ",   DRRU,/* 0xD7 */
    "cau   ",   DRUR,/* 0xD8 */
    "stm   ",   DRIR,/* 0xD9 */
    "lh    ",   DRIR,/* 0xDA */
    "iow   ",   DRIR,/* 0xDB */
    "sth   ",   DRIR,/* 0xDC */
    "st    ",   DRIR,/* 0xDD */
    "stc   ",   DRIR,/* 0xDE */
    "???   ",   UNK, /* 0xDF */
};
static struct s_tXX tEX[] = {
    "abs   ",   RR,  /* 0xE0 */
    "a     ",   RR,  /* 0xE1 */
    "s     ",   RR,  /* 0xE2 */
    "o     ",   RR,  /* 0xE3 */
    "twoc  ",   RR,  /* 0xE4 */
    "n     ",   RR,  /* 0xE5 */
    "m     ",   RR,  /* 0xE6 */
    "x     ",   RR,  /* 0xE7 */
    "b     ",   RC,  /* 0xE8 */
    "b     ",   RC,  /* 0xE9 */
    "???   ",   UNK, /* 0xEA */
    "lhs   ",   R0R, /* 0xEB */
    "balr  ",   RR,  /* 0xEC */
    "balrx ",   RR,  /* 0xED */
    "b     ",   RC,  /* 0xEE */
    "b     ",   RC,  /* 0xEF */
};
static struct s_tXX tFX[] = {
    "wait  ",   R00, /* 0xF0 */
    "ae    ",   RR,  /* 0xF1 */
    "se    ",   RR,  /* 0xF2 */
    "ca16  ",   RR,  /* 0xF3 */
    "onec  ",   RR,  /* 0xF4 */
    "clz   ",   RR,  /* 0xF5 */
    "m     ",   UNK, /* 0xF6 */
    "x     ",   UNK, /* 0xF7 */
    "b     ",   UNK, /* 0xF8 */
    "mc03  ",   RR,  /* 0xF9 */
    "mc13  ",   RR,  /* 0xFA */
    "mc23  ",   RR,  /* 0xFB */
    "mc33  ",   RR,  /* 0xFC */
    "mc30  ",   RR,  /* 0xFD */
    "mc31  ",   RR,  /* 0xFE */
    "mc32  ",   RR,  /* 0xFF */
};
 
static struct s_tXX *p_tXX[] = {
    t0X, t1X, t2X, t3X, t4X, t5X, t6X, t7X,
    t8X, t9X, tAX, tBX, tCX, tDX, tEX, tFX,
};
 
static char bc[17] [4] = {
    "   ",  /* 0 */
    "ge ",  /* 1 */
    "ne ",  /* 2 */
    "le ",  /* 3 */
    "nc ",  /* 4 */
    "?? ",  /* 5 */
    "no ",  /* 6 */
    "ntb",  /* 7 */
    "nop",  /* 8 */
    "lt ",  /* 9 */
    "eq ",  /* A */
    "gt ",  /* B */
    "c  ",  /* C */
    "?? ",  /* D */
    "o  ",  /* E */
    "tb ",  /* F */
    "?? ",  /* undefined */
};
#define BUNK 16  /* index in bc for undefined branch condition */
 
static char tc[8] [4] = {
    "nop",  /* 0 */
    "igt",  /* 1 */
    "ieq",  /* 2 */
    "ige",  /* 3 */
    "ilt",  /* 4 */
    "ine",  /* 5 */
    "ile",  /* 6 */
    "rap",  /* 7 */
};
 
static char sr[16] [6] = {
    "scr0 ", /* 0 */
    "scr1 ", /* 1 */
    "scr2 ", /* 2 */
    "scr3 ", /* 3 */
    "scr4 ", /* 4 */
    "scr5 ", /* 5 */
    "cous ", /* 6 */
    "cou  ", /* 7 */
    "ts   ", /* 8 */
    "scr9 ", /* 9 */
    "mq   ", /* A */
    "mpcs ", /* B */
    "irb  ", /* C */
    "iar  ", /* D */
    "ics  ", /* E */
    "cs   ", /* F */
};
 
#define bits(x,n,m)  ((x >> (31-m)) & ((1 << (m-n+1)) - 1))
#define signed(x,n,m) ((x << n) >> 31-m+n)
 
static char *buf;  /* current append addr for formatted inst */
 
    int    /* 8*(formatted inst length) + (inst byte length) */
unasm( inst, ip, bp )
    register long inst; /* inst to be formatted (in high bytes) */
    register long *ip;  /* addr of inst to be formatted */
    register char *bp;  /* addr of buffer for formatted inst */
{
    register struct s_tXX *tp;
    register int info;
    register char *cp;
    register int ifmt;
    register char *sbp = bp;
    char *zaps();
 
    buf = bp;
 
    tp = p_tXX[ info = bits(inst,0,3) ];
    if( info>7 )
        tp = & tp[ bits(inst,4,7) ];
    info = ltab[ ifmt = tp->fmt ];
 
    fixput( ip, 7 );
    padd( 2 );
    fixput( inst >> 8*(4-info), 2*info - 1 );
    padd( 12 - 2*info );
    cp = tp->opc;
    bp = buf+1;
    while( *buf++ = *cp++ );
    --buf;
 
    switch( ifmt ){
 
        case JI:
            zaps( bp, bc[ bits(inst,4,7) ] );
            symput( (long) ip + 2 * signed(inst,8,15) );
            break;
        case RI:
            reg( bits(inst,8,11) );
            addc( ',' );
            decput( bits(inst,12,15) );
            break;
        case RI16:
            reg( bits(inst,8,11) );
            addc( ',' );
            decput( bits(inst,12,15) + 16 );
            break;
        case RR:
            reg( bits(inst,8,11) );
            addc( ',' );
            reg( bits(inst,12,15) );
            break;
        case SRI:
            sreg( bits(inst,8,11) );
            addc( ',' );
            decput( bits(inst,12,15) + 16 );
            break;
        case SRR:
            sreg( bits(inst,8,11) );
            addc( ',' );
            reg( bits(inst,12,15) );
            break;
        case R0R:
            reg( bits(inst,8,11) );
            addc( ',' );
            addc( '0' );
            addc( '(' );
            reg( bits(inst,12,15) );
            addc( ')' );
            break;
        case RRR:
            reg( bits(inst,4,7) );
            addc( ',' );
            reg( bits(inst,8,11) );
            ireg( ',', bits(inst,12,15) );
            break;
        case RC:
            info = bits(inst,9,11);
            if( bits(inst,5,6) )
                info += 8;
            if( !bits(inst,8,8) )
                info = BUNK;
            bp = zaps( bp, bc[ info ] );
            *bp++ = 'r';
            if( bits(inst,7,7) )
                *bp = 'x';
            reg( bits(inst,12,15) );
            break;
        case BI:
            info = bits(inst,9,11);
            if( bits(inst,5,6) )
                info += 8;
            if( !bits(inst,8,8) )
                info = BUNK;
            bp = zaps( bp, bc[ info ] );
            if( bits(inst,7,7) )
                *bp = 'x';
            symput( (long) ip + 2 * signed(inst,12,31) );
            break;
        case BRI:
            reg( bits(inst,8,11) );
            addc( ',' );
            symput( (long) ip + 2 * signed(inst,12,31) );
            break;
        case BA:
            reg( 15 );
            addc( ',' );
            symput( 2* bits(inst,8,30) );
            break;
        case DSC:
        case DSH:
        case DSL:
            reg( bits(inst,8,11) );
            addc( ',' );
            decput( bits(inst,4,7) << (ifmt-DSC) );  /* <=== NOTE 1 === */
            if( ireg( '(', bits(inst,12,15) ))
                addc( ')' );
            break;
        case DIR:
            varput( bits(inst,16,31) );
            if( ireg( '(', bits(inst,12,15) ))
                addc( ')' );
            break;
        case DRI:
            reg( bits(inst,12,15) );
            addc( ',' );
            vsiput( signed(inst,16,31) );
            break;
        case DIIR:
            decput( bits(inst,8,11) );
            addc( ',' );
            vsiput( signed(inst,16,31) );
            if( ireg( '(', bits(inst,12,15) ))
                addc( ')' );
            break;
        case DRIR:
            reg( bits(inst,8,11) );
            addc( ',' );
            vsiput( signed(inst,16,31) );
            if( ireg( '(', bits(inst,12,15) ))
                addc( ')' );
            break;
        case DRUR:
            reg( bits(inst,8,11) );
            addc( ',' );
            varput( bits(inst,16,31) );
            if( ireg( '(', bits(inst,12,15) ))
                addc( ')' );
            break;
        case DRRI:
            reg( bits(inst,8,11) );
            addc( ',' );
            reg( bits(inst,12,15) );
            addc( ',' );
            vsiput( signed(inst,16,31) );
            break;
        case DRRU:
            reg( bits(inst,8,11) );
            addc( ',' );
            reg( bits(inst,12,15) );
            addc( ',' );
            varput( bits(inst,16,31) );
            break;
        case DTI:
            zaps( bp, tc[ bits(inst,9,11) ] );
            reg( bits(inst,12,15) );
            addc( ',' );
            vsiput( signed(inst,16,31) );
            break;
        case R00:
        case UNK:
            break;
    }
 
    addc( 0x0A );
    addc( 0x0D );
    addc( 0x00 );
    return( 8*(buf-sbp) + ltab[ ifmt ] );
}
 
    static
addc( c )
    register char c;
{
    *buf++ = c;
}
 
    static
padd( n )
    register int n;
{
    while( n-- )
        addc( ' ' );
}
    static
ireg( c, r )
    register char c;
    register int r;
{
    if( r ){
        addc( c );
        reg( r );
    }
    return( r );
}
    static
reg( r )
    register int r;
{
    addc( 'r' );
    decput( r );
}
   static
sreg( r )
    register int r;
{
    register char c, *cp;
 
    for( cp = sr[ r ]; (c = *cp) > ' '; ++cp )
        addc( c );
}
    static
fixput( x, i )  /* output the least significant i+1 hex digits of x */
    register long x;
    register int  i;
{
    static char hexdig[17] = "0123456789abcdef";
 
    i *= 4;
    do
        addc( hexdig[ (x >> i) & 0xF ] );
    while( (i -= 4) >= 0 );
}
    static
decput( n )  /* output n as a small positive (0-60) decimal integer */
    int n;
{
    int d = n/10;
    n = n%10;
    if (d != 0)
	addc(d+'0');
    addc(n+'0');
}
    static
symput( x )  /* output symbolically plus offset value of x */
    register long x;
{
 
#ifdef SYMBOLIC	/* try putting things out symbolically -- assumes adb 
		environment */
	register char *p;
	register off_t displace;

	displace = findsym(x, ISYM);  /* and set cursym as a side effect */
	if (displace < maxoff) {
		for (p = cursym->n_un.n_name; *p != 0; p++) {
			addc(*p);	/* copy symbol name into buffer */
		}
		if (displace == 0)  return;
		addc('+');
		x = displace;
	} /* and continue to use varput on what's left in x */
#endif
	varput(x);
}
	static
varput( x )  /* output all significant hex digits of x */
    register unsigned long x;
{
    register long mask = 0xF;
    register int i, digs=0;
 
    if (x>9) {
	addc( '0' );
	addc( 'x' );
    }
    for( i=0; i < 2*sizeof(long); ++i ){
        if( mask & x )
            digs = i;
        mask <<= 4;
    }
    fixput( x, digs );
}

    static
vsiput( x )  /* output all significant hex digits of x as a signed number */
    register long x;
{
    if( x<0 ){
        addc( '-' );
        x = -x;
    }
    varput( x );
}
 
    static char *
zaps( p, q )  /* modify the substring starting at p with the substring       */
              /* starting at q and ending with the 1st blank or the end of q */
    register char *p, *q;
{
    register char c;
 
    while( (c = *q++) > ' ' ){
        *p++ = c;
    }
    return( p );
}
 
/* end of file */
