static char *sccsid = "@(#) dishand.c, Ver. 2.1 created 00:00:00 87/09/01";

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  *  Copyright (C) 1987 G. M. Harding, all rights reserved  *
  *                                                         *
  * Permission to copy and  redistribute is hereby granted, *
  * provided full source code,  with all copyright notices, *
  * accompanies any redistribution.                         *
  *                                                         *
  * This file contains the source code for most of the spe- *
  * cialized handler routines of the disassembler  program. *
  * (The file disfp.c contains handler routines specific to *
  * the 8087 numeric  co-processor.)  Each handler  routine *
  * interprets the opcode byte  (and subsequent data bytes, *
  * if any)  of a particular family of opcodes,  and is re- *
  * sponsible for generating appropriate output. All of the *
  * code in this file is highly MACHINE-SPECIFIC, and would *
  * have to be rewritten for a different  CPU.  The handler *
  * routines are accessed  only via pointers in the optab[] *
  * array, however, so machine dependencies are confined to *
  * this file, its sister file "disfp.c", and the data file *
  * "distabs.c".                                            *
  *                                                         *
  * All of the code in this file is based on the assumption *
  * of sixteen-bit integers.                                *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "dis.h"		/* Disassembler declarations  */

int segflg;			/* Segment-override flag      */

unsigned char objbuf[OBJMAX];	/* Buffer for object code     */

int objptr;			/* Index into objbuf[]        */

unsigned long PC;		/* Current program counter    */

 /* * * * * *  MISCELLANEOUS SUPPORTING ROUTINES  * * * * * */


void objini(register int j)
{				/* Object code init routine   */
    if ((segflg == 1) || (segflg == 2))
	segflg *= 3;
    else
	segflg = 0;
    objptr = 0;
    objbuf[objptr++] = (unsigned char) (j);
}

void objout(void)
{				/* Object-code output routine */
    register int k;

    if (objflg) {
	printf("\t|");
	if (symptr >= 0)
	    printf(" %05.5lx:", (PC + 1L - (long) (objptr)));
	for (k = 0; k < objptr; ++k)
	    printf(" %02.2x", objbuf[k]);
	putchar('\n');
    }
}

void badseq(register int j, register int k)
{				/* Invalid-sequence routine   */
    printf("\t.byte\t$%02.2x\t\t| invalid code sequence\n", j);
    printf("\t.byte\t$%02.2x\n", k);
}

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This  routine  is the first of several  opcode-specific *
  * handlers,  each of which is  dedicated  to a particular *
  * opcode family.  A pointer to a handler  routine is con- *
  * tained in the second field of each optab[]  entry.  The *
  * dfhand()  routine is the default handler,  invoked when *
  * no other handler is appropriate (generally, when an in- *
  * valid opcode is encountered).                           *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void dfhand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF dfhand()  * * * * * * * * * */

    segflg = 0;

    printf("\t.byte\t$%02.2x", j);

    if (optab[j].min || optab[j].max)
	putchar('\n');
    else
	printf("\t\t| unimplemented opcode\n");

}				/* * * * * * * * * * * END OF dfhand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the  single-byte  handler,  invoked  whenever a *
  * one-byte opcode is encountered.                         *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void sbhand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF sbhand()  * * * * * * * * * */

    objini(j);

    if (j == 0x2e)		/* seg cs   */
	segflg = 1;

    if ((j == 0x26)		/* seg es   */
	||(j == 0x36)		/* seg ss   */
	||(j == 0x3e))		/* seg ds   */
	segflg = 2;

    printf("%s\n", optab[j].text);

    objout();

}				/* * * * * * * * * * * END OF sbhand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the handler for most of the processor's regular *
  * arithmetic operations.                                  *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void aohand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF aohand()  * * * * * * * * * */
    char b[80];
    register int k;
    int m, n;

    objini(j);

    switch (j & 7) {
    case 0:
    case 1:
    case 2:
    case 3:
	printf("%s\t", optab[j].text);
	FETCH(k);
	printf("%s\n", mtrans(j, k, TR_STD));
	break;
    case 4:
	FETCH(k);
	if (k < 16)
	    printf("%s\tal,*%d\n", optab[j].text, k);
	else
	    printf("%s\tal,*$%02.2x\n", optab[j].text, k);
	break;
    case 5:
	FETCH(m);
	FETCH(n);
	k = (n << 8) | m;
	if (lookext((long) (k), (PC - 1), b))
	    printf("%s\tax,#%s\n", optab[j].text, b);
	else {
	    if (k < 100 || k > 65436)
		printf("%s\tax,#%d\n", optab[j].text, (short) k);
	    else
		printf("%s\tax,#$%04x\n", optab[j].text, k);
	}
	break;
    default:
	dfhand(j);
	break;
    }

    objout();

}				/* * * * * * * * * * * END OF aohand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the  handler for opcodes  which  perform  short *
  * (eight-bit) relative jumps.                             *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void sjhand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF sjhand()  * * * * * * * * * */

    register int k;
    int m;
    unsigned short dest;

    objini(j);

    FETCH(m);

    if (m & 0x80)
	k = 0xff00;
    else
	k = 0;

    k |= m;
    dest = (PC + k + 1);

    printf("%s\t%s\t\t| loc %05.5lx\n", optab[j].text,
	   lookup((long) dest, N_TEXT, LOOK_REL, -1L), (long) dest);

    objout();

}				/* * * * * * * * * * * END OF sjhand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the  handler for a  loosely-knit  family of op- *
  * codes which perform  arithmetic and logical operations, *
  * and which take immediate  data.  The routine's logic is *
  * rather complex,  so,  in an effort to avoid  additional *
  * complexity,  the search for external  references in the *
  * relocation table has been dispensed with. Eager hackers *
  * can try their hand at coding such a search.             *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void imhand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF imhand()  * * * * * * * * * */

    static char a[128], b[32];
    unsigned long pc;
    register int k;
    int offset, oflag, immed, iflag, mod, opi, w, rm;
    int m, n;

    objini(j);

    FETCH(k);

    pc = PC + 1;

    offset = 0;
    mod = (k & 0xc0) >> 6;
    opi = (k & 0x38) >> 3;
    w = j & 1;
    rm = k & 7;

    if ((j & 2)
	&& ((opi == 1)
	    || (opi == 4)
	    || (opi == 6))) {
	badseq(j, k);
	return;
    }

    strcpy(a, OPFAM[opi]);

    if (!w)
	strcat(a, "b");

    if ((oflag = mod) > 2)
	oflag = 0;

    if ((mod == 0) && (rm == 6)) {
	FETCH(m);
	FETCH(n);
	offset = (n << 8) | m;
    } else if (oflag)
	if (oflag == 2) {
	    FETCH(m);
	    FETCH(n);
	    offset = (n << 8) | m;
	} else {
	    FETCH(m);
	    if (m & 0x80)
		n = -0xFF;
	    else
		n = 0;
	    offset = n | m;
	}

    switch (j & 3) {
    case 0:
    case 2:
	FETCH(immed);
	iflag = 0;
	break;
    case 1:
	FETCH(m);
	FETCH(n);
	immed = (n << 8) | m;
	iflag = 1;
	break;
    case 3:
	FETCH(immed);
	if (immed & 0x80)
	    immed &= 0xff00;
	iflag = 0;
	break;
    }

    strcat(a, "\t");

    switch (mod) {
    case 0:
	if (rm == 6)
	    strcat(a, lookup((long) (offset), N_DATA, LOOK_ABS, pc));
	else {
	    sprintf(b, "(%s)", REGS0[rm]);
	    strcat(a, b);
	}
	break;
    case 1:
    case 2:
	if (mod == 1) {
	    strcat(a, "*");
	    sprintf(b, "%d(", (short) offset);
	} else {
	    strcat(a, "#");
	    if (offset < 100 || offset > 65436)
		sprintf(b, "%d(", (short) offset);
	    else
		sprintf(b, "$%04x(", offset);
	}
	strcat(a, b);
	strcat(a, REGS1[rm]);
	strcat(a, ")");
	break;
    case 3:
	strcat(a, REGS[(w << 3) | rm]);
	break;
    }

    strcat(a, ",");
    if (iflag) {
	strcat(a, "#");
	if (immed < 100 || immed > 65436)
	    sprintf(b, "%d", (short) immed);
	else
	    sprintf(b, "$%04x", immed);
    } else {
	strcat(a, "*");
	sprintf(b, "%d", immed);
    }
    strcat(a, b);

    printf("%s\n", a);

    objout();

}				/* * * * * * * * * * * END OF imhand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the  handler  for  various  "mov"-type  opcodes *
  * which use the mod,  reg,  and r/m  fields of the second *
  * code byte in a standard, straightforward way.           *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void mvhand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF mvhand()  * * * * * * * * * */

    register int k, m = j;

    objini(j);

    FETCH(k);

    if ((m == 0x84) || (m == 0x85)	/* Kind of kludgey   */
	||(m == 0xc4) || (m == 0xc5)
	|| (m == 0x8d))
	if (m & 0x40)
	    m |= 0x03;
	else
	    m |= 0x02;

    printf("%s\t%s\n", optab[j].text, mtrans(m, k, TR_STD));

    objout();

}				/* * * * * * * * * * * END OF mvhand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the handler for segment-register "mov" opcodes. *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void mshand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF mshand()  * * * * * * * * * */

    register int k;

    objini(j);

    FETCH(k);

    if (k & 0x20) {
	badseq(j, k);
	return;
    }

    printf("%s\t%s\n", optab[j].text, mtrans(j, k, TR_SEG));

    objout();

}				/* * * * * * * * * * * END OF mshand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the  handler for pops,  other than  single-byte *
  * pops.  (The 8088 allows  popping into any register,  or *
  * directly into memory,  accessed  either  immediately or *
  * through a register and an index.)                       *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void pohand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF pohand()  * * * * * * * * * */

    char *a;
    register int k;

    objini(j);

    FETCH(k);

    if (k & 0x38) {
	badseq(j, k);
	return;
    }

    printf("%s\t", optab[j].text);

    a = mtrans((j & 0xfd), k, TR_STD);

    mtrunc(a);

    printf("%s\n", a);

    objout();

}				/* * * * * * * * * * * END OF pohand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the handler routine for intersegment  calls and *
  * jumps.  Its output is never symbolic,  because the host *
  * linker  does not allow  symbolic  intersegment  address *
  * references except by means of symbolic  constants,  and *
  * any such  constants in the symbol  table,  even if they *
  * are of the  appropriate  value,  may be misleading.  In *
  * compiled code,  intersegment  references  should not be *
  * encountered,  and even in assembled  code,  they should *
  * occur infrequently. If and when they do occur, however, *
  * they will be disassembled in absolute form.             *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void cihand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF cihand()  * * * * * * * * * */

    register int m, n;

    objini(j);

    printf("%s\t", optab[j].text);

    FETCH(m);
    FETCH(n);

    printf("#$%04.4x,", ((n << 8) | m));

    FETCH(m);
    FETCH(n);

    printf("#$%04.4x\n", ((n << 8) | m));

    objout();

}				/* * * * * * * * * * * END OF cihand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the handler for  "mov"  opcodes with  immediate *
  * data.                                                   *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void mihand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF mihand()  * * * * * * * * * */

    register int k;
    int m, n;
    char b[80];

    objini(j);

    printf("%s", optab[j].text);

    if (j & 8) {
	FETCH(m);
	FETCH(n);
	k = ((n << 8) | m);
	if (lookext((long) (k), (PC - 1), b))
	    printf("#%s\n", b);
	else {
	    if (k < 100 || k > 65436)
		printf("#%d\n", (short) k);
	    else
		printf("#$%04x\n", k);
	}
    } else {
	FETCH(m);
	printf("*%d\n", m);
    }

    objout();

}				/* * * * * * * * * * * END OF mihand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the handler for a family of quick-move opcodes. *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void mqhand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF mqhand()  * * * * * * * * * */

    unsigned long pc;
    register int m, n;

    objini(j);

    pc = PC + 1;

    FETCH(m);
    FETCH(n);

    m = (n << 8) | m;

    printf("%s\t", optab[j].text);

    if (j & 2)
	printf("%s,%s\n",
	       lookup((long) (m), N_DATA, LOOK_ABS, pc), REGS[(j & 1) << 3]);
    else
	printf("%s,%s\n",
	       REGS[(j & 1) << 3], lookup((long) (m), N_DATA, LOOK_ABS, pc));

    objout();

}				/* * * * * * * * * * * END OF mqhand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the handler for a family of quick-test opcodes. *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void tqhand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF tqhand()  * * * * * * * * * */

    char b[80];
    register int m, n;
    int k;

    objini(j);

    printf("%s\t%s,", optab[j].text, REGS[(j & 1) << 3]);

    FETCH(m);

    if (j & 1) {
	FETCH(n);
	k = ((n << 8) | m);
	if (lookext((long) (k), (PC - 1), b))
	    printf("#%s\n", b);
	else {
	    if (k < 100 || k > 65436)
		printf("#%d\n", (short) k);
	    else
		printf("#$%04x\n", k);
	}
    } else {
	if (m & 80)
	    m |= -0xFF;
	printf("*%d\n", m);
    }

    objout();

}				/* * * * * * * * * * * END OF tqhand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the handler for multiple-byte "return" opcodes. *
  * The 8088 allows returns to take an optional  16-bit ar- *
  * gument,  which  reflects  the  amount to be added to SP *
  * after  the pop of the  return  address.  The idea is to *
  * facilitate  the use of local  parameters  on the stack. *
  * After some  rumination,  it was decided to  disassemble *
  * any such arguments as absolute quantities,  rather than *
  * rummaging  through the symbol table for possible corre- *
  * sponding constants.                                     *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void rehand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF rehand()  * * * * * * * * * */

    register int m, n;

    objini(j);

    FETCH(m);
    FETCH(n);

    m = (n << 8) | m;

    printf("%s\t#0x%04.4x\n", optab[j].text, m);

    objout();

}				/* * * * * * * * * * * END OF rehand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the handler for "mov"  opcodes involving memory *
  * and immediate data.                                     *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void mmhand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF mmhand()  * * * * * * * * * */

    char b[80];
    char *a;
    register int k;

    objini(j);

    FETCH(k);

    if (k & 0x38) {
	badseq(j, k);
	return;
    }

    printf("%s", optab[j].text);

    if (!(j & 1))
	putchar('b');

    a = mtrans((j & 0xfd), (k & 0xc7), TR_STD);

    mtrunc(a);

    printf("\t%s,", a);

    if (j & 1) {
	FETCH(j);
	FETCH(k);
	k = (k << 8) | j;
	if (lookext((long) (k), (PC - 1), b))
	    printf("#%s\n", b);
	else {
	    if (k < 100 || k > 65436)
		printf("#%d\n", (short) k);
	    else
		printf("#$%04x\n", k);
	}
    } else {
	FETCH(k);
	printf("*%d\n", k);
    }

    objout();

}				/* * * * * * * * * * * END OF mmhand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the  handler  for the 8088  family of shift and *
  * rotate instructions.                                    *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void srhand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF srhand()  * * * * * * * * * */

    char *a;
    register int k;

    objini(j);

    FETCH(k);

    if ((k & 0x38) == 0x30) {
	badseq(j, k);
	return;
    }

    printf("%s", OPFAM[((k & 0x38) >> 3) + 16]);

    if (!(j & 1))
	putchar('b');

    a = mtrans((j & 0xfd), (k & 0xc7), TR_STD);

    mtrunc(a);

    printf("\t%s", a);

    if (j & 2)
	printf(",cl\n");
    else
	printf(",*1\n");

    objout();

}				/* * * * * * * * * * * END OF srhand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the handler for the ASCII-adjust opcodes.       *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void aahand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF aahand()  * * * * * * * * * */

    register int k;

    objini(j);

    FETCH(k);

    if (k != 0x0a) {
	badseq(j, k);
	return;
    }

    printf("%s\n", optab[j].text);

    objout();

}				/* * * * * * * * * * * END OF aahand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the handler for port I/O opcodes  which specify *
  * the port address as an immediate operand.               *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void iohand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF iohand()  * * * * * * * * * */

    register int k;

    objini(j);

    FETCH(k);

    printf("%s\t$%02.2x\n", optab[j].text, k);

    objout();

}				/* * * * * * * * * * * END OF iohand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the  handler  for opcodes  which  perform  long *
  * (sixteen-bit) relative jumps and calls.                 *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void ljhand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF ljhand()  * * * * * * * * * */

    register int k;
    int m, n;
    unsigned short dest;

    objini(j);

    FETCH(m);
    FETCH(n);

    k = (n << 8) | m;
    dest = PC + k + 1;

    printf("%s\t%s\t\t| loc %05.5lx\n", optab[j].text,
	   lookup((long) dest, N_TEXT, LOOK_LNG, (PC - 1L)), (long) dest);

    objout();

}				/* * * * * * * * * * * END OF ljhand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the handler for a pair of oddball opcodes (0xf6 *
  * and 0xf7) which perform miscellaneous arithmetic opera- *
  * tions not dealt with elsewhere.                         *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void mahand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF mahand()  * * * * * * * * * */

    char *a;
    register int k;
    char b[80];

    objini(j);

    FETCH(k);

    a = mtrans((j & 0xfd), (k & 0xc7), TR_STD);

    mtrunc(a);

    switch (((k = objbuf[1]) & 0x38) >> 3) {
    case 0:
	printf("\ttest");
	break;
    case 1:
	badseq(j, k);
	return;
    case 2:
	printf("\tnot");
	break;
    case 3:
	printf("\tneg");
	break;
    case 4:
	printf("\tmul");
	break;
    case 5:
	printf("\timul");
	break;
    case 6:
	printf("\tdiv");
	break;
    case 7:
	printf("\tidiv");
	break;
    }

    if (!(j & 1))
	putchar('b');

    printf("\t%s", a);

    if (k & 0x38)
	putchar('\n');
    else if (j & 1) {
	FETCH(j);
	FETCH(k);
	k = (k << 8) | j;
	if (lookext((long) (k), (PC - 1), b))
	    printf(",#%s\n", b);
	else
	    printf(",#$%04x\n", k);
    } else {
	FETCH(k);
	printf(",*%d\n", k);
    }

    objout();

}				/* * * * * * * * * * * END OF mahand() * * * * * * * * * * */

 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *                                                         *
  * This is the handler for miscellaneous jump, call, push, *
  * and increment/decrement opcodes  (0xfe and 0xff)  which *
  * are not dealt with elsewhere.                           *
  *                                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void mjhand(register int j)
{				/* Pointer to optab[] entry   *//* * * * * * * * * *  START OF mjhand()  * * * * * * * * * */

    char *a;
    register int k;

    objini(j);

    FETCH(k);

    a = mtrans((j & 0xfd), (k & 0xc7), TR_STD);

    mtrunc(a);

    switch (((k = objbuf[1]) & 0x38) >> 3) {
    case 0:
	printf("\tinc");
	if (!(j & 1))
	    putchar('b');
	putchar('\t');
	break;
    case 1:
	printf("\tdec");
	if (!(j & 1))
	    putchar('b');
	putchar('\t');
	break;
    case 2:
	if (j & 1)
	    printf("\tcall\t@");
	else
	    goto BAD;
	break;
    case 3:
	if (j & 1)
	    printf("\tcalli\t@");
	else
	    goto BAD;
	break;
    case 4:
	if (j & 1)
	    printf("\tjmp\t@");
	else
	    goto BAD;
	break;
    case 5:
	if (j & 1)
	    printf("\tjmpi\t@");
	else
	    goto BAD;
	break;
    case 6:
	if (j & 1)
	    printf("\tpush\t");
	else
	    goto BAD;
	break;
    case 7:
      BAD:
	badseq(j, k);
	return;
    }

    printf("%s\n", a);

    objout();

}				/* * * * * * * * * * * END OF mjhand() * * * * * * * * * * */
