[net.sources] z80 disassembler subroutine

duane@anasazi.UUCP (Duane Morse) (11/20/85)

Here's a routine which will disassemble one instruction into z80
mnemonics. It will also indicate whether the instruction references
something which might be in a symbol table, so the calling program
can display the nearest symbol name on the same line.

Note: z80dis.c uses Fred Fish's Debug package, though the current
z80dis.o is compiled with -DDBUG_OFF. If you don't have the debug
package, delete "DBUG_3" and "DBUG_ENTER" statements, change "DBUG_VOID_RETURN"
to "return", and change "DBUG_RETURN(x)" to "return(x)".
-----------------------------Cut here ------------------------------
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by duane on Wed Nov 20 13:50:30 MST 1985
# Contents:  z80dis.3 z80dis.c
 
echo x - z80dis.3
sed 's/^@//' > "z80dis.3" <<'@//E*O*F z80dis.3//'
@.TH Z80DIS 3 "Anasazi Programmer's Manual"
@.SH NAME
z80dis \- disassemble memory into Z80 instructions
@.SH SYNOPSIS
@.nf
int z80dis(op_buf, outbuf, b_addr, lblflag)
unsigned char *op_buf;
char *outbuf;
unsigned short b_addr;
long *lblflag;
@.SH RETURNS
Length of the disassembled instruction in bytes (1 to 4).
@.SH DESCRIPTION
z80dis disassembles one Z80 instruction into an uppercase ASCII string.
The instruction to be disassembled starts at
@.B op_buf
and should be at least 4 bytes long (the longest Z80 instruction uses
4 bytes). The null-terminated ASCII string is returned in
@.B outbuf.
The program counter corresponding to the start of the instruction
is in
@.B b_addr.
On return, lblflag is -1 unless the disassembled instruction contained
a full-word address, in which case lblflag contains that address. (If
the caller has access to a symbol table, lblflag can be used to indicate
the nearest symbol name referenced by the instruction.)
@.SH EXAMPLE
instrlen = z80dis(mem_buf, dumpbuf, baseaddr, &z80addr);
@.SH "BUGS AND CAUTIONS"
If z80dis doesn't understand the instruction, it returns a length of
1 and the string is "??".
@//E*O*F z80dis.3//
chmod u=rw,g=r,o=r z80dis.3
 
echo x - z80dis.c
sed 's/^@//' > "z80dis.c" <<'@//E*O*F z80dis.c//'
/*TITLE z80dis.c - disassemble into Z80 mnemonics - 11/20/85 10:03:34 */
/*SUBTTL Includes, defines, data storage, and declarations */
static char *version = "@(#)z80dis.c	1.1 11/20/85 10:03:34";

/*
** This file contains routine z80dis, which disassembles one z80 instruction.
*/

#include <stdio.h>
#include <dbug.h>

#define STATIC static

#define FAKEHLIDX 0x20		/* Needed for some IX/IY translation */

struct codestring {
  unsigned short simplecode;	/* Op code */
  char *simplestring;		/* String that corresponds to simplecode */
} ;

/* Main variables */

/* Points to next byte to disassemble */
STATIC unsigned char *dis_addr; 

/* Points to where to put the output byte */
STATIC char *outptr;

/* Points to start of ASCII output buffer */
STATIC char *org_buf;

/* Length of the current instruction in bytes */
STATIC int instr_len;

/* If not -1, addr of "label" in instruction. Caller may have symbol table. */
STATIC long labeladdr;

/* address of the current byte being disassembled */
STATIC unsigned short curaddr;

/* 'X' or 'Y' if current instruction uses IX or IY */
STATIC char ixiyop;

/* Current op code */
STATIC unsigned char this_op;

/* Count of characters displayed before the op code string */
STATIC int count;
/*PAGE*/
/* Register names in order by Z80 convention */

STATIC char *rtbl[] = {
  "B", "C", "D", "E", "H", "L", "(HL)", "A"
} ;

/* Register pair names (ends with SP) */

STATIC char *rptbl[] = {
  "BC", "DE", "HL", "SP"
} ;

/* Alternate table of register pair names (ends with afF) */

STATIC char *rptbla[] = {
  "BC", "DE", "HL", "AF"
} ;

/* Condition code strings */

STATIC char *cctbl[] = {
  "NZ", "Z", "NC", "C", "PO", "PE", "P", "M"
} ;

/* String address for STRN routine and for op codes 80 to BF */

STATIC char *strntb[] = {
  "ADD A,", "ADC A,", "SUB ", "SBC A,", "AND ", "XOR ", "OR ", "CP "
} ;

/* String addresses for shft00 */

STATIC char *shfttb[] = {
  "RLC ", "RRC ", "RL ", "RR ", "SLA ", "SRA ", NULL, "SRL "
} ;
/*PAGE*/
/* Allowed IX and IY op codes other than CB xx */
STATIC unsigned char ixytb[] = {
  0x09, 0x19, 0x21, 0x22, 0x23, 0x29, 0x2a,
  0x2b, 0x34, 0x35, 0x36, 0x39, 0x46, 0x4e,
  0x56, 0x5e, 0x66, 0x6e, 0x70, 0x71, 0x72,
  0x73, 0x74, 0x75, 0x77, 0x7e, 0x86, 0x8e,
  0x96, 0x9e, 0xa6, 0xae, 0xb6, 0xbe, 0xe1,
  0xe3, 0xe5, 0xe9, 0xf9
} ;

/* Op code and string tables */
/*
**  The following tables contain pairs of op codes and string addresses.
**  If an op code can be handled entirely by displaying a string, it
**  appears in one of these tables.
*/

/* Op codes 00 to FF, excluding ED combinations. */

STATIC struct codestring strtb1[] = {
  {0x00, "NOP"},
  {0x02, "LD (BC),A"},
  {0x07, "RLCA"},
  {0x08, "EX AF,AF'"},
  {0x0a, "LD A,(BC)"},
  {0x0f, "RRCA"},
  {0x12, "LD (DE),A"},
  {0x17, "RLA"},
  {0x1a, "LD A,(DE)"},
  {0x1f, "RRA"},
  {0x27, "DAA"},
  {0x2f, "CPL"},
  {0x37, "SCF"},
  {0x3f, "CCF"},
  {0x76, "HALT"},
  {0xc9, "RET"},
  {0xd9, "EXX"},
  {0xeb, "EX DE,HL"},
  {0xf3, "DI"},
  {0xfb, "EI"}
} ;
/*PAGE*/
/* Op codes ED 40 through ED BF */

STATIC struct codestring strtb2[] = {
  {0x44, "NEG"},
  {0x45, "RETN"},
  {0x46, "IM 0"},
  {0x47, "LD I,A"},
  {0x4d, "RETI"},
  {0x4f, "LD R,A"},
  {0x56, "IM 1"},
  {0x57, "LD A,I"},
  {0x5e, "IM 2"},
  {0x5f, "LD A,R"},
  {0x67, "RRD"},
  {0x6f, "RLD"},
  {0xa0, "LDI"},
  {0xa1, "CPI"},
  {0xa2, "INI"},
  {0xa3, "OUTI"},
  {0xa8, "LDD"},
  {0xa9, "CPD"},
  {0xaa, "IND"},
  {0xab, "OUTD"},
  {0xb0, "LDIR"},
  {0xb1, "CPIR"},
  {0xb2, "INIR"},
  {0xb3, "OTIR"},
  {0xb8, "LDDR"},
  {0xb9, "CPDR"},
  {0xba, "INDR"},
  {0xbb, "OTDR"}
} ;
/*PAGE*/
/* Declaractions */

STATIC unsigned char nxtbyt();
STATIC int disasm(), doed(), shifts(), exmtbl(), exmstr(), outrpc();
STATIC void jrcom(), dorela(), outchr(), oct1(), hex1(), hex2();
STATIC void outrs0(), outrs3(), outr(), sout(), badop();
STATIC void doixiy(), outrp4(), outrpa(), doaddr(), donpar(), doadrp();
/*SUBTTL z80dis - disassemble an instruction */
/*
** int z80dis(op_buf, outbuf, b_addr, lblflag)
**
**  Disassemble one Z80 instruction.
**
** Parameters:
**  op_buf = points to where object code to be disassembled is found.
**  outbuf = points to where z80dis sends the ASCII output.
**  b_addr = address of the instruction pointed at by op_buf.
**  lblflag = if not -1, address of a possible label in the instruction
**    (e.g. in a jump instruction, call, etc.).
**
** Returns:
**  Length of the instruction disassembled.
*/

int z80dis(op_buf, outbuf, b_addr, lblflag)

unsigned char *op_buf;
char *outbuf;
unsigned short b_addr;
long *lblflag;

{
  DBUG_ENTER("z80dis");
  /* Set up the globals */
  dis_addr = op_buf;
  org_buf = outptr = outbuf;
  curaddr = b_addr;
  labeladdr = -1;
  instr_len = 0;
  count = 5;
  ixiyop = '\0';

  /* Do the work */
  if (disasm())
    badop();
  else if (ixiyop) {
    if (disasm())
      badop();
  }
  *outptr = '\0';
  *lblflag = labeladdr;
  DBUG_RETURN(instr_len);
}
/*SUBTTL disasm - disassemble */
/*
** int disasm()
**
**  Disassemble an instruction. If an IX/IY instruction is encountered,
**  this routine will be called twice.
**
** Parameters:
**
**  ixiyop = null if not an IX or IY instruction, 'X' or 'Y' otherwise.
**
** Returns:
**  0 if successful, -1 if the instruction is invalid.
*/

STATIC int disasm()

{
  unsigned char op;

  DBUG_ENTER("disasm");
  /* Get the next byte in the message */
  this_op = nxtbyt();

  /* Am I in the middle of an IX or IY instruction? */
  if (ixiyop) {
    /* Yes - handle illegal values */
    if (this_op == 0xdd || this_op == 0xfd || this_op == 0xed)
      DBUG_RETURN(-1);
    if (this_op == 0xcb) {
      op = *(dis_addr + 1);
      if (op == 0x36)
	DBUG_RETURN(-1);
      op &= 0xf;
      if (op != 6 && op != 0xe)
	DBUG_RETURN(-1);
      DBUG_RETURN(shifts());
    }

    /* See if op code makes sense with IX/IY */
    if (exmtbl(ixytb, sizeof(ixytb)))
      DBUG_RETURN(-1);
  }
/*PAGE*/
  /* See if a simple string will do */
  if (exmstr(strtb1, sizeof(strtb1) / sizeof(struct codestring)) == 0)
    DBUG_RETURN(0);
  
  /* Try miscellaneous instructions */
  switch (this_op) {
    case 0x10: /* DJNZ */
      dorela("DJNZ ");
      DBUG_RETURN(0);
    case 0x18: /* JR */
      jrcom(NULL);
      DBUG_RETURN(0);
    case 0x20: /* JR NZ */
      jrcom("NZ");
      DBUG_RETURN(0);
    case 0x22: /* LD (addr),HL */
      sout("LD ");
      doadrp();
      this_op = FAKEHLIDX;
      outrp4(",");
      DBUG_RETURN(0);
    case 0x28: /* JR Z */
      jrcom("Z");
      DBUG_RETURN(0);
    case 0x2a: /* LD HL,(addr) */
      this_op = FAKEHLIDX;
      outrp4("LD ");
      outchr(',');
      doadrp();
      DBUG_RETURN(0);
    case 0x30: /* JR NC */
      jrcom("NC");
      DBUG_RETURN(0);
    case 0x32: /* LD (addr),A */
      sout("LD ");
      doadrp();
      sout(",A");
      DBUG_RETURN(0);
    case 0x38: /* JR C */
      jrcom("C");
      DBUG_RETURN(0);
    case 0x3a: /* LD A,(addr) */
      sout("LD A,");
      doadrp();
      DBUG_RETURN(0);
    case 0xc3: /* JP addr */
      sout("JP ");
      doaddr();
      DBUG_RETURN(0);
    case 0xcb: /* shift */
      DBUG_RETURN(shifts());
    case 0xcd: /* CALL */
      sout("CALL ");
      doaddr();
      DBUG_RETURN(0);
    case 0xd3: /* OUT (nn),A */
      sout("OUT ");
      donpar();
      sout(",A");
      DBUG_RETURN(0);
    case 0xdb: /* IN A,(nn) */
      sout("IN A,");
      donpar();
      DBUG_RETURN(0);
    case 0xdd: /* IX instruction */
      ixiyop = 'X';
      DBUG_RETURN(0);
    case 0xe3: /* EX (SP),HL */
      this_op = FAKEHLIDX;
      outrp4("EX (SP),");
      DBUG_RETURN(0);
    case 0xe9: /* JP (HL) */
      this_op = FAKEHLIDX;
      outrp4("JP (");
      outchr(')');
      DBUG_RETURN(0);
    case 0xed: /* various */
      DBUG_RETURN(doed());
    case 0xf9: /* LD SP,HL */
      this_op = FAKEHLIDX;
      outrp4("LD SP,");
      DBUG_RETURN(0);
    case 0xfd: /* IY instruction */
      ixiyop = 'Y';
      DBUG_RETURN(0);
    default:
      break;
  }
/*PAGE*/
  /* Handle op codes from 00 to 3f */
  if (this_op < 0x40) {
    switch (this_op & 0x0f) {
      case 1: /* ld rp,nnnn */
	outrp4("LD ");
	outchr(',');
	doaddr();
	DBUG_RETURN(0);
      case 3: /* inc rp */
	outrp4("INC ");
	DBUG_RETURN(0);
      case 4: case 0xc: /* inc r */
	outrs3("INC ");
	DBUG_RETURN(0);
      case 5: case 0xd: /* dec r */
	outrs3("DEC ");
	DBUG_RETURN(0);
      case 6: case 0xe: /* ld r,nn */
	outrs3("LD ");
	outchr(',');
	hex2((int) nxtbyt());
	DBUG_RETURN(0);
      case 9: /* add hl,rp */
	if (ixiyop) {
	  sout("ADD ");
	  doixiy();
	  outrp4(",");
	}
	else
	  outrp4("ADD HL,");
	DBUG_RETURN(0);
      case 0xb: /* DEC rp */
	outrp4("DEC ");
	DBUG_RETURN(0);
      default: 
	DBUG_RETURN(-1);
    }
  }

  /* Handle op codes from 40 to 7f */
  if (this_op < 0x80) {
    /* Instruction is LD r,r' */
    outrs3("LD ");
    outchr(',');
    outrs0();
    DBUG_RETURN(0);
  }

  /* Handle op codes from 80 to bf */
  if (this_op < 0xc0) {
    sout(strntb[(this_op >> 3) & 0x7]);
    outrs0();
    DBUG_RETURN(0);
  }
/*PAGE*/
  /* Op code is from c0 to ff */
  switch (this_op & 0xf) {
    case 0: case 8: /* RET cc */
      sout("RET ");
      sout(cctbl[(this_op >> 3) & 0x7]);
      DBUG_RETURN(0);
    case 1: /* pop rp */
      outrpa("POP ");
      DBUG_RETURN(0);
    case 2: case 0xa: /* JP cc,addr */
      sout("JP ");
      sout(cctbl[(this_op >> 3) & 0x7]);
      outchr(',');
      doaddr();
      DBUG_RETURN(0);
    case 4: case 0xc: /* CALL cc,addr */
      sout("CALL ");
      sout(cctbl[(this_op >> 3) & 0x7]);
      outchr(',');
      doaddr();
      DBUG_RETURN(0);
    case 5: /* PUSH rp */
      outrpa("PUSH ");
      DBUG_RETURN(0);
    case 6: case 0xe: /* Various */
      sout(strntb[((this_op - 0xc6) >> 3) & 0xf]);
      hex2(nxtbyt());
      DBUG_RETURN(0);
    case 7: case 0xf: /* rst p */
      sout("RST ");
      hex2(this_op & 0x38);
      DBUG_RETURN(0);
    default:
      break;
  }
  DBUG_RETURN(-1);
}
/*SUBTTL Functions for putting addresses and registers together */
/*
** void jrcom(s)
**
**  Handle jr xx,e or jr e instructions.
**
** Parameters:
**  s = NULL or string pointer for condition code.
**
** Returns:
**  Nothing.
*/

STATIC void jrcom(s)

char *s;

{
  DBUG_ENTER("jrcom");
  sout("JR ");
  if (s != NULL) {
    sout(s);
    outchr(',');
  }
  dorela();
  DBUG_VOID_RETURN;
}

/*
** void dorela(s)
**
**  Compute a relative address and save the absolute address for
**  a relative jump.
**
** Parameters:
**  s = string to display before doing other stuff.
**
** Returns:
**  Nothing.
*/

STATIC void dorela(s)

char *s;

{
  unsigned char op;
  int offset;

  sout(s);
  op = nxtbyt();
  offset = (char) op;
  labeladdr = curaddr + offset;
  if (offset < 0) {
    offset = -offset;
    sout(".-");
  }
  else
    sout(".+");
  hex2(offset);
}
/*SUBTTL Handle ED op codes */
/*
** int doed()
**
**  Handle op codes beginning with ED.
**
** Parameters:
**  None.
**
** Returns:
**  0 if successful, -1 otherwise.
*/

STATIC int doed()

{
  DBUG_ENTER("doed");
  this_op = nxtbyt();
  if (exmstr(strtb2, sizeof(strtb2) / sizeof(struct codestring)) == 0)
    DBUG_RETURN(0);
  if (this_op < 0x40 || this_op >= 0x80)
    DBUG_RETURN(-1);
  switch (this_op & 0xf) {
    case 0: case 8: /* IN r,(C) */
      if (this_op == 0x70)
	DBUG_RETURN(-1);
      outrs3("IN ");
      sout(",(C)");
      DBUG_RETURN(0);
    case 1: case 9: /* OUT (C),r */
      if (this_op == 0x71)
	DBUG_RETURN(-1);
      outrs3("OUT (C),");
      DBUG_RETURN(0);
    case 2: /* SBC HL,rp */
      outrp4("SBC HL,");
      DBUG_RETURN(0);
    case 3: /* LD (addr),rp */
      sout("LD ");
      doadrp();
      outrp4(",");
      DBUG_RETURN(0);
    case 0xa: /* ADC HL,rp */
      outrp4("ADC HL,");
      DBUG_RETURN(0);
    case 0xb: /* LD rp,(addr) */
      outrp4("LD ");
      outchr(',');
      doadrp();
      DBUG_RETURN(0);
    default:
      break;
    }
  DBUG_RETURN(-1);
}
/*SUBTTL Handle CB op codes - shifts */
/*
** int shifts()
**
**  Handle shift instructions.
**
** Parameters:
**  None.
**
** Returns:
**  0 if the instruction is valid, -1 otherwise.
*/

STATIC int shifts()

{
  int k;

  DBUG_ENTER("shifts");
  this_op = ixiyop ? *(dis_addr + 1) : nxtbyt();
  if (this_op < 0x40) {
    k = (this_op >> 3) & 0x7;
    if (k == 6)
      DBUG_RETURN(-1);
    sout(shfttb[k]);
    outrs0();
    if (ixiyop)
      nxtbyt();
    DBUG_RETURN(0);
  }
  if (this_op < 0x80)
    sout("BIT ");
  else if (this_op < 0xc0)
    sout("RES ");
  else
    sout("SET ");
    
  k = (this_op >> 3) & 7;
  outchr('0' + k);
  outchr(',');
  outrs0();
  if (ixiyop)
    nxtbyt();
  DBUG_RETURN(0);
}
/*SUBTTL exmtbl & exmstr - see if op code found in table */
/*
** int exmtbl(s, n)
**
**  See of this_op is found in the op code table pointed at by s.
**
** Parameters:
**  s = points to table of op codes.
**  n = number of entries in the table.
**  
**  this_op = op code to seek.
**
** Returns:
**  0 if found, -1 otherwise.
*/

STATIC int exmtbl(s, n)

register unsigned char *s;
register int n;

{
  register unsigned char c;

  DBUG_ENTER("exmtbl");
  for (c = this_op; n--; )
    if (*s++ == c)
      DBUG_RETURN(0);
  DBUG_RETURN(-1);
}
/*PAGE*/
/*
** int exmstr(ptr, n)
**
**  Look for this_op in a table of op code & strings. If the op code is
**  found, display the associated string.
**
** Parameters:
**  ptr = points to the op code/string table.
**  n = number of entries in the table.
**
**  this_op = op code to seek.
**
** Returns:
**  0 if successful, -1 otherwise.
*/

STATIC int exmstr(ptr, n)

register struct codestring *ptr;
register int n;

{
  register short c;

  DBUG_ENTER("exmstr");
  for (c = this_op; n--; ptr++)
    if (ptr->simplecode == c) {
      sout(ptr->simplestring);
      DBUG_RETURN(0);
    }
  DBUG_RETURN(-1);
}
/*SUBTTL String-oriented subroutines */
/*
** outchr(c)
**
**  Display the character in c, making sure that there are always
**  5 characters before the operand.
**
** Parameters:
**  c = character to display.
**
** Returns;
**  Nothing.
*/

STATIC void outchr(c)

{
  count--;
  if (c != ' ') {
    *outptr++ = c;
    return;
  }

  while (count-- > 0)
    *outptr++ = ' ';
  *outptr++ = ' ';
}
/*PAGE*/
/*
** void hex1(k)
**
**  Display a value as one hex digit.
**
** Parameters:
**  k = value to convert to hex.
**
** Returns:
**  Nothing.
*/

STATIC void hex1(k)

int k;

{
  k &= 0xf;
  if (k < 10)
    outchr('0' + k);
  else
    outchr('A' + k - 10);
}

/*
** void hex2(k)
**
**  Display a value as 2 hex digits.
**
** Parameters:
**  k = value to display.
**
** Returns:
**  Nothing.
*/

STATIC void hex2(k)

int k;

{
  hex1(k >> 4);
  hex1(k);
}
/*PAGE*/
/*
** void outrs0()
**
**  Output the name of a register using the last 3 bits of this_op.
**
** Parameters:
**
**  this_op = current op code.
**
** Returns:
**  Nothing.
*/

STATIC void outrs0()

{
  outr(this_op & 0x7);
}

/*
** void outrs3(s)
**
**  Display the name of a register using bits 2-4 of this_op.
**
** Parameters:
**  s = points to string to display first.
**
**  this_op = current op code.
**
** Returns:
**  Nothing.
*/

STATIC void outrs3(s)

char *s;

{
  sout(s);
  outr((this_op >> 3) & 0x7);
}
/*PAGE*/
/*
** void outr(k)
**
**  Display a register based on an index.
**
** Parameters:
**  k = register's index.
**
** Returns:
**  Nothing.
*/

STATIC void outr(k)

int k;

{
  int offset;

  if (k == 6 && ixiyop) {
    /* It's (IX+d) or (IY+d) */
    sout("(I");
    outchr(ixiyop);
    offset = (char) nxtbyt();
    if (offset < 0) {
      outchr('-');
      offset = -offset;
    }
    else
      outchr('+');
    hex2(offset);
    outchr(')');
    return;
  }
  sout(rtbl[k]);
}
/*PAGE*/
/*
** void sout(s)
**
**  Display a string.
**
** Parameters:
**  s = points to string to display.
**
** Returns:
**  Nothing.
*/

STATIC void sout(s)

register char *s;

{
  while (*s)
    outchr(*s++);
}

/*
** int outrpc()
**
**  Compute register pair index and handle IX/IY if necessary.
**
** Parameters:
**
**  this_op = current op code.
**
** Returns:
**  -1 if an IX/IY register pair was displayed, 0 otherwise.
*/

STATIC int outrpc()

{
  int k;

  DBUG_ENTER("outrpc");
  k = (this_op >> 4) & 0x3;
  if (k != 2 || ixiyop == '\0')
    DBUG_RETURN(0);
  doixiy();
  DBUG_RETURN(-1);
}
/*PAGE*/
/*
** void doixiy()
**
**  Display IX or IY.
**
** Parameters:
**
**  ixiyop = 'X' or 'Y'.
**
** Returns:
**  Nothing.
*/

STATIC void doixiy()

{
  outchr('I');
  outchr(ixiyop);
}

/*
** void outrp4(s)
**
**  Output a register pair name. Bits 2-3 of this_op contain the index.
**
** Parameters:
**  s = points to string to display first.
**
**  this_op = current op code.
**
** Returns:
**  Nothing.
*/

STATIC void outrp4(s)

char *s;

{
  DBUG_ENTER("outrp4");
  sout(s);
  if (outrpc())
    DBUG_VOID_RETURN;
  sout(rptbl[(this_op >> 4) & 0x3]);
}
/*PAGE*/
/*
** void outrpa(s)
**
**  Output a register pair name. Bits 2-3 of this_op contain the index.
**  (This is like outrp4 except register pair SP is replaced with AF.
**
** Parameters:
**  s = points to string to display first.
**
**  this_op = current op code.
**
** Returns:
**  Nothing.
*/

STATIC void outrpa(s)

char *s;

{
  DBUG_ENTER("outrpa");
  sout(s);
  if (outrpc())
    DBUG_VOID_RETURN;
  sout(rptbla[(this_op >> 4) & 0x3]);
}
/*PAGE*/
/*
** void doaddr()
**
**  Display the address pointed at by dis_addr.
**
** Parameters:
**
**  dis_addr = points to first byte of address.
**
** Returns:
**  Nothing.
*/

STATIC void doaddr()

{
  unsigned short addr;

  addr = nxtbyt();
  addr |= ((nxtbyt() << 8) & 0xff00);
  hex2(addr >> 8);
  hex2(addr);
  labeladdr = addr;
}

/*
** void donpar()
**
**  Display the next byte in hex surrounded by parentheses.
**
** Parameters:
**
**  dis_addr = points to the byte to fetch.
**
** Returns:
**  Nothing.
*/

STATIC void donpar()

{
  outchr('(');
  hex2((int) nxtbyt());
  outchr(')');
}
/*PAGE*/
/*
** void doadrp()
**
**  Display the address pointed at by dis_addr surrounded by parentheses.
**
** Parameters:
**
**  dis_addr = points to first byte of address.
**
** Returns:
**  Nothing.
*/

STATIC void doadrp()

{
  outchr('(');
  doaddr();
  outchr(')');
}
/*SUBTTL nxtbyt - get next byte to examine */
/*
** unsigned char nxtbyt()
**
**  Return the next byte of the instruction and advance pointers and
**  counters.
**
** Parameters:
**
**  dis_addr = points to the next byte to fetch.
**  instr_len = current instruction length.
**  curaddr = address of the current byte.
**
** Returns:
**  The next byte.
**
** Side effects:
**  dis_addr, instr_len, and curaddr are advanced.
*/

STATIC unsigned char nxtbyt()

{
  DBUG_ENTER("nxtbyt");
  curaddr++;
  instr_len++;
  DBUG_3("nxtbyt", "returning %x", *dis_addr);
  DBUG_RETURN(*dis_addr++);
}
/*SUBTTL badop - handle unknown instruction */
/*
** void badop()
**
**  Replace whatever was being worked on with generic bad operand info.
**
** Parameters:
**  None.
**
** Returns:
**  Nothing.
*/

STATIC void badop()

{
  outptr = org_buf;
  sout("??");
  labeladdr = -1;
  instr_len = 1;
}
@//E*O*F z80dis.c//
chmod u=rw,g=rw,o=rw z80dis.c
 
exit 0
-- 

Duane Morse	...!noao!{terak|mot}!anasazi!duane
(602) 870-3330