/* z8dis.c */

/* A z8 (8681/82) Disassembler for PC's .

  Author: Bob Bush (Compuserve-73105,1332) 08-Jul-1990

  Copyright (C) 1990 R.Bush. All rights reserved.

  This program is freely distributable as long as this copyright notice
  is retained. It intended for personal, non-commercial use.

  Compiled with MicroSoft 'C' Ver.5.1, Compact memory model
  
  Changes:
  	06-Jul-2008 - Oliver Lehmann - make it cmdline only
	                             - make it compile on FreeBSD
*/
   
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>


unsigned char *buffer;
unsigned char *bin_pc,*buf_pc;
unsigned char *bufbase;
unsigned int pc;
long size;
int nohex,noadr,quiet;

int within_prog = 0;
long prog_previous;
int death_candidate = 0;

long markno = 0;
typedef struct {
    char label[10];
    long maxaddr;
    int  printed;
} marks;
marks mark[65535];


long progno = 0;
marks prog[65535];

/* define the different operand formations */
/* note: 0 is invalid.. (illegal opcode) */

#define 	R1	1
#define		IR1	2
#define		r1r2	3
#define		r1Ir2	4
#define		R2R1	5
#define		IR2R1	6
#define		R1IM	7
#define		r1R2	8
#define		r2R1	9
#define		ccRA	10
#define		r1IM	11
#define		ccDA	12
#define		r1	13
#define		IR1IM	14
#define		r1RA	15
#define		Implied 16
#define		IRR1	17
#define		IM	18
#define		RR1	19
#define		r1Irr2	20
#define		Ir1Irr2 21
#define		r2Irr1  22
#define		Ir2Irr1 23
#define		r1xR2   24
#define		r2xR1	25
#define		DA	26
#define		Ir1r2	27
#define		R2IR1	28
#define		Direct1	29
#define		Direct2	30
#define		Return  31

/* condition codes. note: hi nibble is the condition code */

struct cc_code {
    char mne[10];
    int  cc_value;
};

#define		ALWAYS "always"

struct cc_code cc[] = {
    "c",0x70,
    "nc",0xf0,
    "z",0x60,
    "nz",0xe0,
    "pl",0xd0,
    "mi",0x50,
    "ov",0x40,
    "nov",0xc0,
    "eq",0x60,
    "ne",0xe0,
    "ge",0x90,
    "lt",0x10,
    "gt",0xa0,
    "le",0x20,
    "uge",0xf0,
    "ult",0x70,
    "ugt",0xb0,
    "ule",0x30,
    ALWAYS,0x80,
    "never",0x00
};

#define CCSIZE sizeof (cc) / sizeof(cc[0])

struct opcode {
        char    mne[10];
	int	operands;
        int     bytecount;
};

/* lookup table of opcodes */

struct opcode optab[] = {
	"dec    ",R1,		2,	/* 00 */
	"dec    ",IR1,		2,	/* 01 */
	"add    ",r1r2,		2,	/* 02 */
	"add    ",r1Ir2,	2,	/* 03 */
	"add    ",R2R1,		3,	/* 04 */
	"add    ",IR2R1,	3,	/* 05 */
	"add    ",R1IM,		3,	/* 06 */
	"add    ",IR1IM,	3,	/* 07 */
	"ld     ",r1R2,		2,	/* 08 */
	"ld     ",r2R1,		2,	/* 09 */
	"djnz   ",r1RA,		2,	/* 0a */
	"jr     ",ccRA,		2,	/* 0b */
	"ld     ",r1IM,		2,	/* 0c */
	"jp     ",ccDA,		3,	/* 0d */
	"inc    ",r1,		1,	/* 0e */
	".byte  ",0,		1,	/* 0f */

	"rlc    ",R1,		2,	/* 10 */
	"rlc    ",IR1,		2,	/* 11 */
	"adc    ",r1r2,		2,	/* 12 */
	"adc    ",r1Ir2,	2,	/* 13 */
	"adc    ",R2R1,		3,	/* 14 */
	"adc    ",IR2R1,	3,	/* 15 */
	"adc    ",R1IM,		3,	/* 16 */
	"adc    ",IR1IM,	3,	/* 17 */
	"ld     ",r1R2,		2,	/* 18 */
	"ld     ",r2R1,		2,	/* 19 */
	"djnz   ",r1RA,		2,	/* 1a */
	"jr     ",ccRA,		2,	/* 1b */
	"ld     ",r1IM,		2,	/* 1c */
	"jp     ",ccDA,		3,	/* 1d */
	"inc    ",r1,		1,	/* 1e */
	".byte  ",0,		1,	/* 1f */

	"inc    ",R1,		2,	/* 20 */
	"inc    ",IR1,		2,	/* 21 */
	"sub    ",r1r2, 	2,	/* 22 */
	"sub    ",r1Ir2,	2,	/* 23 */
	"sub    ",R2R1, 	3,	/* 24 */
	"sub    ",IR2R1,	3,	/* 25 */
	"sub    ",R1IM,		3,	/* 26 */
	"sub    ",IR1IM,	3,	/* 27 */
	"ld     ",r1R2,		2,	/* 28 */
	"ld     ",r2R1,		2,	/* 29 */
	"djnz   ",r1RA,		2,	/* 2a */
	"jr     ",ccRA,		2,	/* 2b */
	"ld     ",r1IM,		2,	/* 2c */
	"jp     ",ccDA,		3,	/* 2d */
	"inc    ",r1,		1,	/* 2e */
	".byte  ",0,		1,	/* 2f */

	"jp     ",IRR1,		2,	/* 30 */
	"srp    ",IM,		2,	/* 31 */
	"sbc    ",r1r2, 	2,	/* 32 */
	"sbc    ",r1Ir2,	2,	/* 33 */
	"sbc    ",R2R1, 	3,	/* 34 */
	"sbc    ",IR2R1,	3,	/* 35 */
	"sbc    ",R1IM,		3,	/* 36 */
	"sbc    ",IR1IM,	3,	/* 37 */
	"ld     ",r1R2,		2,	/* 38 */
	"ld     ",r2R1,		2,	/* 39 */
	"djnz   ",r1RA,		2,	/* 3a */
	"jr     ",ccRA,		2,	/* 3b */
	"ld     ",r1IM,		2,	/* 3c */
	"jp     ",ccDA,		3,	/* 3d */
	"inc    ",r1,		1,	/* 3e */
	".byte  ",0,		1,	/* 3f */

	"da     ",R1,		2,	/* 40 */
	"da     ",IR1,		2,	/* 41 */
	"or     ",r1r2, 	2,	/* 42 */
	"or     ",r1Ir2,	2,	/* 43 */
	"or     ",R2R1, 	3,	/* 44 */
	"or     ",IR2R1,	3,	/* 45 */
	"or     ",R1IM,		3,	/* 46 */
	"or     ",IR1IM,	3,	/* 47 */
	"ld     ",r1R2,		2,	/* 48 */
	"ld     ",r2R1,		2,	/* 49 */
	"djnz   ",r1RA,		2,	/* 4a */
	"jr     ",ccRA,		2,	/* 4b */
	"ld     ",r1IM,		2,	/* 4c */
	"jp     ",ccDA,		3,	/* 4d */
	"inc    ",r1,		1,	/* 4e */
	".byte  ",0,		1,	/* 4f */

	"pop    ",R1,		2,	/* 50 */
	"pop    ",IR1,		2,	/* 51 */
	"and    ",r1r2, 	2,	/* 52 */
	"and    ",r1Ir2,	2,	/* 53 */
	"and    ",R2R1, 	3,	/* 54 */
	"and    ",IR2R1,	3,	/* 55 */
	"and    ",R1IM, 	3,	/* 56 */
	"and    ",IR1IM,	3,	/* 57 */
	"ld     ",r1R2,		2,	/* 58 */
	"ld     ",r2R1,		2,	/* 59 */
	"djnz   ",r1RA,		2,	/* 5a */
	"jr     ",ccRA,		2,	/* 5b */
	"ld     ",r1IM,		2,	/* 5c */
	"jp     ",ccDA,		3,	/* 5d */
	"inc    ",r1,		1,	/* 5e */
	".byte  ",0,		1,	/* 5f */

	"com    ",R1,		2,	/* 60 */
	"com    ",IR1,		2,	/* 61 */
	"tcm    ",r1r2, 	2,	/* 62 */
	"tcm    ",r1Ir2,	2,	/* 63 */
	"tcm    ",R2R1, 	3,	/* 64 */
	"tcm    ",IR2R1,	3,	/* 65 */
	"tcm    ",R1IM,		3,	/* 66 */
	"tcm    ",IR1IM,	3,	/* 67 */
	"ld     ",r1R2,		2,	/* 68 */
	"ld     ",r2R1,		2,	/* 69 */
	"djnz   ",r1RA,		2,	/* 6a */
	"jr     ",ccRA,		2,	/* 6b */
	"ld     ",r1IM,		2,	/* 6c */
	"jp     ",ccDA,		3,	/* 6d */
	"inc    ",r1,		1,	/* 6e */
	".byte  ",0,		1,	/* 6f */

	"push   ",R1,		2,	/* 70  evaluates same as R1 */
	"push   ",IR1,		2,	/* 71  evaluates same as IR1 */
	"tm     ",r1r2, 	2,	/* 72 */
	"tm     ",r1Ir2,	2,	/* 73 */
	"tm     ",R2R1, 	3,	/* 74 */
	"tm     ",IR2R1,	3,	/* 75 */
	"tm     ",R1IM,		3,	/* 76 */
	"tm     ",IR1IM,	3,	/* 77 */
	"ld     ",r1R2,		2,	/* 78 */
	"ld     ",r2R1,		2,	/* 79 */
	"djnz   ",r1RA,		2,	/* 7a */
	"jr     ",ccRA,		2,	/* 7b */
	"ld     ",r1IM,		2,	/* 7c */
	"jp     ",ccDA,		3,	/* 7d */
	"inc    ",r1,		1,	/* 7e */
	".byte  ",0,		1,	/* 7f */

	"decw   ",RR1,		2,	/* 80 */
	"decw	",IR1,		2,	/* 81 */
	"lde    ",r1Irr2,	2,	/* 82 */
	"ldei   ",Ir1Irr2,	2,	/* 83 */
	".byte  ",0,		1,	/* 84 */
	".byte  ",0,		1,	/* 85 */
	".byte  ",0,		1,	/* 86 */
	".byte  ",0,		1,	/* 87 */
	"ld     ",r1R2,		2,	/* 88 */
	"ld     ",r2R1,		2,	/* 89 */
	"djnz   ",r1RA,		2,	/* 8a */
	"jr     ",ccRA,		2,	/* 8b */
	"ld     ",r1IM,		2,	/* 8c */
	"jp     ",ccDA,		3,	/* 8d */
	"inc    ",r1,		1,	/* 8e */
	"di     ",Implied,	1,	/* 8f */

	"rl     ",R1,		2,	/* 90 */
	"rl     ",IR1,		2,	/* 91 */
	"lde    ",r2Irr1,	2,	/* 92 */
	"ldei   ",Ir2Irr1,	2,	/* 93 */
	".byte  ",0,		1,	/* 94 */
	".byte  ",0,		1,	/* 95 */
	".byte  ",0,		1,	/* 96 */
	".byte  ",0,		1,	/* 97 */
	"ld     ",r1R2,		2,	/* 98 */
	"ld     ",r2R1,		2,	/* 99 */
	"djnz   ",r1RA,		2,	/* 9a */
	"jr     ",ccRA,		2,	/* 9b */
	"ld     ",r1IM,		2,	/* 9c */
	"jp     ",ccDA,		3,	/* 9d */
	"inc    ",r1,		1,	/* 9e */
	"ei     ",Implied,	1,	/* 9f */

	"incw   ",RR1,		2,	/* a0 */
	"incw	",IR1,		2,	/* a1 */
	"cp     ",r1r2, 	2,	/* a2 */
	"cp     ",r1Ir2,	2,	/* a3 */
	"cp     ",R2R1, 	3,	/* a4 */
	"cp     ",IR2R1,	3,	/* a5 */
	"cp     ",R1IM,		3,	/* a6 */
	"cp     ",IR1IM,	3,	/* a7 */
	"ld     ",r1R2,		2,	/* a8 */
	"ld     ",r2R1,		2,	/* a9 */
	"djnz   ",r1RA,		2,	/* aa */
	"jr     ",ccRA,		2,	/* ab */
	"ld     ",r1IM,		2,	/* ac */
	"jp     ",ccDA,		3,	/* ad */
	"inc    ",r1,		1,	/* ae */
	"ret    ",Return,	1,	/* af */

	"clr    ",R1,		2,	/* b0 */
	"clr    ",IR1,		2,	/* b1 */
	"xor    ",r1r2, 	2,	/* b2 */
	"xor    ",r1Ir2,	2,	/* b3 */
	"xor    ",R2R1, 	3,	/* b4 */
	"xor    ",IR2R1,	3,	/* b5 */
	"xor    ",R1IM,		3,	/* b6 */
	"xor    ",IR1IM,	3,	/* b7 */
	"ld     ",r1R2,		2,	/* b8 */
	"ld     ",r2R1,		2,	/* b9 */
	"djnz   ",r1RA,		2,	/* ba */
	"jr     ",ccRA,		2,	/* bb */
	"ld     ",r1IM,		2,	/* bc */
	"jp     ",ccDA,		3,	/* bd */
	"inc    ",r1,		1,	/* be */
	"iret   ",Return,	1,	/* bf */

	"rrc    ",R1,		2,	/* c0 */
	"rrc    ",IR1,		2,	/* c1 */
	"ldc    ",r1Irr2,	2,	/* c2 */
	"ldci   ",Ir1Irr2,	2,	/* c3 */
	".byte  ",0,		1,	/* c4 */
	".byte  ",0,		1,	/* c5 */
	".byte  ",0,		1,	/* c6 */
	"ld     ",r1xR2,	3,	/* c7 */
	"ld     ",r1R2,		2,	/* c8 */
	"ld     ",r2R1,		2,	/* c9 */
	"djnz   ",r1RA,		2,	/* ca */
	"jr     ",ccRA,		2,	/* cb */
	"ld     ",r1IM,		2,	/* cc */
	"jp     ",ccDA,		3,	/* cd */
	"inc    ",r1,		1,	/* ce */
	"rcf    ",Implied,	1,	/* cf */

	"sra    ",R1,		2,	/* d0 */
	"sra    ",IR1,		2,	/* d1 */
	"ldc    ",r2Irr1,	2,	/* d2 */
	"ldci   ",Ir2Irr1,	2,	/* d3 */
	"call   ",IRR1,		2,	/* d4 */
	".byte  ",0,		1,	/* d5 */
	"call   ",DA,		3,	/* d6 */
	"ld     ",r2xR1,	3,	/* d7 */
	"ld     ",r1R2,		2,	/* d8 */
	"ld     ",r2R1,		2,	/* d9 */
	"djnz   ",r1RA,		2,	/* da */
	"jr     ",ccRA,		2,	/* db */
	"ld     ",r1IM,		2,	/* dc */
	"jp     ",ccDA,		3,	/* dd */
	"inc    ",r1,		1,	/* de */
	"scf    ",Implied,	1,	/* df */

	"rr     ",R1,		2,	/* e0 */
	"rr     ",IR1,		2,	/* e1 */
	".byte  ",0,		1,	/* e2 */
	"ld     ",r1Ir2,	2,	/* e3 */
	"ld     ",R2R1, 	3,	/* e4 */
	"ld     ",IR2R1,	3,	/* e5 */
	"ld     ",R1IM,		3,	/* e6 */
	"ld     ",IR1IM,	3,	/* e7 */
	"ld     ",r1R2,		2,	/* e8 */
	"ld     ",r2R1,		2,	/* e9 */
	"djnz   ",r1RA,		2,	/* ea */
	"jr     ",ccRA,		2,	/* eb */
	"ld     ",r1IM,		2,	/* ec */
	"jp     ",ccDA,		3,	/* ed */
	"inc    ",r1,		1,	/* ee */
	"ccf    ",Implied,	1,	/* ef */

	"swap   ",R1,		2,	/* f0 */
	"swap   ",IR1,		2,	/* f1 */
	".byte  ",0,		1,	/* f2 */
	"ld     ",Ir1r2,	2,	/* f3 */
	".byte  ",0,		1,	/* f4 */
	"ld     ",R2IR1,	3,      /* f5 */
	".byte  ",0,		1,	/* f6 */
	".byte  ",0,		1,	/* f7 */
	"ld     ",r1R2,		2,	/* f8 */
	"ld     ",r2R1,		2,	/* f9 */
	"djnz   ",r1RA,		2,	/* fa */
	"jr     ",ccRA,		2,	/* fb */
	"ld     ",r1IM,		2,	/* fc */
	"jp     ",ccDA,		3,	/* fd */
	"inc    ",r1,		1,	/* fe */
	"nop    ",Implied,	1,	/* ff */
	".word  ",Direct2,      2,      /* dummy */
	".byte  ",Direct1,      1,      /* dummy */
};

/* the Meat of the disassembler */

void
disp_hex(unsigned char *buf,int count)
{
    switch(count) {
	case 1:	printf("%02x      \t\t",*buf & 0xff);
		break;
	case 2: printf("%02x %02x   \t\t",*buf	& 0xff,*(buf+1) & 0xff);
		break;
	case 3: printf("%02x %02x %02x\t\t",*buf & 0xff,*(buf+1) & 0xff,*(buf+2) & 0xff);
		break;
	}
}


int
working(unsigned char *ptr)
{
    if((*ptr & 0xf0) == 0xe0)	/* pattern signifies working register */
	return(1);
    else
	return(0);
}


static char badcc[4] = "???";

void print_cc(int cond)
{
    int j;


    for(j = 0; j < CCSIZE; j++) {
	if(cond == cc[j].cc_value){
	    if(strcmp(cc[j].mne,ALWAYS) != 0)
		    printf("%s,",cc[j].mne);
	    else
		    death_candidate=1;
	    break;
	}
    }
    if( j == CCSIZE )
	printf("%s,",badcc);
}




void
set_pc(int val)
{
    pc     = val;
    buf_pc = bufbase+val;        /* add in buffer offset */
}

void
inc_pcs(int val)
{
    pc += val;
    buf_pc += val;
}

struct stat fil_stat;

int
read_bin(char *fname,unsigned int addr)
{
    int infile;

    if((infile = open(fname,O_RDONLY)) == -1) {
        printf("\n Unable to open input file\n");
	return(0);
    }

    fstat(infile,&fil_stat);
    size = fil_stat.st_size;

    if(size + (long)addr > 65536L) {
	close(infile);
	printf("\nError: File too big -or- filesize+offset would overwite buffer\n");
	return(0);
    }
    if(size == 65536L) {
        read(infile,buffer,65535); /* max for one read */
        read(infile,buffer+65535L,1);
    }
    else
        read(infile,buffer+addr,65535);
    if(quiet==0)
	printf("%ld bytes read\n",size);
    close(infile);
}

void
print_special_reg(unsigned char *bufptr) {
    	switch( *bufptr & 0xff ) {
            case 0:    printf("P0");
                       break;
            case 1:    printf("P1");
                       break;
            case 2:    printf("P2");
                       break;
            case 3:    printf("P3");
                       break;
            case 240:  printf("SIO");
                       break;
            case 241:  printf("TMR");
                       break;
            case 242:  printf("T1");
                       break;
            case 243:  printf("PRE1");
                       break;
            case 244:  printf("T0");
                       break;
            case 245:  printf("PRE0");
                       break;
            case 246:  printf("P2M");
                       break;
            case 247:  printf("P3M");
                       break;
            case 248:  printf("P01M");
                       break;
            case 249:  printf("IPR");
                       break;
            case 250:  printf("IRQ");
                       break;
            case 251:  printf("IMR");
                       break;
            case 252:  printf("FLAGS");
                       break;
            case 253:  printf("RP");
                       break;
            case 254:  printf("SPH");
                       break;
            case 255:  printf("SPL");
                       break;

            default:   printf("%d",*bufptr & 0xff);
	}
}

void
print_reg(unsigned char *bufptr) {
    if(working(bufptr))
       printf("r%d",*bufptr & 0x0f);
    else {
    	print_special_reg(bufptr);
    }
}

void
addmark(long addr) {
	if(strlen(mark[addr].label) == 0) {
		sprintf(mark[addr].label,"mark_%04d",markno);
		if(strlen(prog[addr].label) > 0 )
			sprintf(prog[addr].label,"%s",mark[addr].label);
		markno++;
	}
}

int
placemark(long addr) {
	if(strlen(mark[addr].label) > 0) {
		if(noadr == 0)
			printf("\t");
		if(nohex == 0)
			printf("\t");
		printf("%s:\n",mark[addr].label);
		return(1);
	}
	return(0);
}

void
jumpmark(long addr) {
	if(strlen(mark[addr].label) > 0)
		printf("%s",mark[addr].label);
	else
		printf("$%04x",addr);
}

void
addprog(long addr) {
	if(strlen(prog[addr].label) == 0) {
		if(strlen(mark[addr].label) == 0) {
			sprintf(prog[addr].label,"prog_%04d",progno);
			progno++;
		} else {
			sprintf(prog[addr].label,"%s",mark[addr].label);
		}
	}
}

void
endprog() {
	if(noadr == 0)
		printf("\t");
	if(nohex == 0)
		printf("\t");
	printf("END %s\n\n",prog[prog_previous].label);
	within_prog=0;
}

void
placeprog(long addr) {
	if(strlen(prog[addr].label) > 0) {
		if(within_prog==1) 
			endprog();
		if(noadr == 0)
			printf("\t");
		if(nohex == 0)
			printf("\t");
		printf("%s PROCEDURE\n",prog[addr].label);
		if(noadr == 0)
			printf("\t");
		if(nohex == 0)
			printf("\t");
		printf("ENTRY\n");
		prog_previous=addr;
		within_prog=1;
	}
}

void
callprog(long addr) {
	if(strlen(prog[addr].label) > 0)
		printf("%s",prog[addr].label);
	else
		printf("$%04x",addr);
}

int
deathcode(long addr) {
	if(strlen(prog[addr].label) == 0 &&
	   strlen(mark[addr].label) == 0)
		return(1);
	else
		return(0);
}

void
display_operands(int index,unsigned char *bufptr)
{
    long addr = 0;

    switch(optab[index].operands) {
	case R1:	bufptr++;
			print_reg(bufptr);
			break;
	case IR1:	bufptr++;
		        printf("@");
			print_reg(bufptr);
			break;
	case r1r2:	bufptr++;
			printf("r%d,r%d",*bufptr >> 4 & 0x0f,*bufptr & 0x0f);
			break;
	case r1Ir2:	bufptr++;
			printf("r%d,@r%d",*bufptr >> 4 & 0x0f,*bufptr & 0x0f);
			break;
	case R2R1:	bufptr+=2;
			print_reg(bufptr);
			printf(",");
			bufptr--;
			print_reg(bufptr);
			break;
	case IR2R1:	bufptr+=2;
		        printf("@");
			print_reg(bufptr);
			printf(",");
			bufptr--;
			print_reg(bufptr);
			break;
	case R1IM:	bufptr++;
			print_reg(bufptr);
			printf(",");
			bufptr++;
			printf("#%d",*bufptr & 0xff);
			break;
	case IR1IM:	bufptr++;
		        printf("@");
			print_reg(bufptr);
			printf(",");
			bufptr++;
			printf("#%d",*bufptr & 0xff);
			break;
	case r1R2:	printf("r%d,",*bufptr >> 4 & 0x0f);
			bufptr++;
			print_reg(bufptr);
			break;	
	case r2R1:	bufptr++;
			print_reg(bufptr);
			printf(",");
			bufptr--;
			printf("r%d",*bufptr >> 4 & 0x0f);
			break;
	case r1RA:	printf("r%d,",*bufptr >> 4 & 0x0f);
			bufptr++;
			if(*bufptr >= 0x80)
			    jumpmark((pc+1) - 0xFF + *bufptr);
			else
			    jumpmark((pc+2) + *bufptr);
			break;	
	case ccRA:	print_cc(*bufptr & 0xf0);
			bufptr++;
			if(*bufptr >= 0x80)
			    jumpmark((pc+1) - 0xFF + *bufptr);
			else
			    jumpmark((pc+2) + *bufptr);
			break;
	case r1IM:	printf("r%d,",*bufptr >> 4 & 0x0f);
			bufptr++;
			printf("#%d",*bufptr & 0xff);
			break;
	case r1:	printf("r%d",*bufptr >> 4 & 0x0f);
			break;
	case IRR1:	bufptr++;
			if(working(bufptr))
			   printf("@rr%d",*bufptr & 0x0f);
			else
			   printf("@rr:%d",*bufptr & 0xff);
			break;
	case IM:	bufptr++;
			printf("#%d",*bufptr & 0xff);
			break;
	case RR1:	bufptr++;
			if(working(bufptr))
			   printf("rr%d",*bufptr & 0x0f);
			else
			   printf("rr:%d",*bufptr & 0xff);
			break;
	case r1Irr2:	bufptr++;
			printf("r%d,",*bufptr >> 4 & 0x0f);
			printf("@rr%d",*bufptr & 0x0f);
			break;
	case Ir1Irr2:	bufptr++;
			printf("@r%d,",*bufptr >> 4 & 0x0f);
			printf("@rr%d",*bufptr & 0x0f);
			break;
	case r2Irr1:	bufptr++;
			printf("@rr%d,",*bufptr & 0x0f);
			printf("r%d",*bufptr >> 4 & 0x0f);
			break;
	case Ir2Irr1:   bufptr++;
			printf("@rr%d,",*bufptr & 0x0f);
			printf("@r%d",*bufptr >> 4 & 0x0f);
			break;
	case r1xR2:	bufptr++;
			printf("r%d,",*bufptr >> 4 & 0x0f);
			bufptr++;
			print_special_reg(bufptr);
			bufptr--;
			printf("(r%d)",*bufptr & 0x0f);
			break;
	case r2xR1:	bufptr+=2;
			printf("r:%d",*bufptr & 0xff);
			bufptr--;
			printf("(r%d),",*bufptr & 0x0f);
			printf("r%d",*bufptr >> 4 & 0x0f);
			break;
	case ccDA:	print_cc(*bufptr & 0xf0);
			bufptr++;
	case Direct2:
			addr = *bufptr++;
			addr <<= 8;
			addr +=*bufptr;
			jumpmark(addr);
			break;
	case DA:	bufptr++;
			addr = *bufptr++;
			addr <<= 8;
			addr +=*bufptr;
			callprog(addr);
	                break;
	case Ir1r2:	bufptr++;
			printf("@r%d,",*bufptr >> 4 & 0x0f);
			printf("r%d",*bufptr & 0x0f);
			break;
	case R2IR1:	bufptr+=2;
			printf("@");
			print_reg(bufptr);
			printf(",");
			bufptr--;
			print_reg(bufptr);
			break;
	case 0:		/* illegal */
	case Direct1:	printf("%02x",*bufptr);
			break;
			break;
	case Implied:	break;
	case Return:	death_candidate = 1;
			break;
    }
}

void
preprocess_operands(int index,unsigned char *bufptr)
{
    long addr = 0;
    
    switch(optab[index].operands) {
	case ccRA:
	case r1RA:	bufptr++;
			if(*bufptr >= 0x80)
			    addmark((pc+1) - 0xFF + *bufptr);
			else
			    addmark((pc+2) + *bufptr);
			break;	
	case ccDA:	bufptr++;
	case Direct2:
			addr = *bufptr++;
			addr <<= 8;
			addr +=*bufptr;
			addmark(addr);
			break;
	case DA:	bufptr++;
        		addr = *bufptr++;
			addr <<= 8;
			addr +=*bufptr;
			addprog(addr);
			break;
    }
}


void
disasm()
{
    int lc;
    unsigned long index;
    unsigned long save_pc;
    unsigned char *save_buf_pc;
     
    save_pc = pc; save_buf_pc = buf_pc;

    lc=0;
    
    while(lc < size) {
	if(lc < 12)
	    index = 256;
	else
	    index = *buf_pc;
	preprocess_operands(index,buf_pc);
	inc_pcs(optab[index].bytecount);
	lc += optab[index].bytecount; 
    }

    set_pc(0);
    lc=0;
    
    while(lc < size) {
/*	death code detection is wrong - think of things like jp @rr2.....
	if((death_candidate == 1) && deathcode(pc) == 1) {
	    if(within_prog==1)
	    	endprog();
	    index = 257;
	} else {
*/	    death_candidate = 0;
	    if(lc < 12)
		index = 256;
	    else
		index = *buf_pc;
/*	}*/
	if(placemark(pc) == 0)
		placeprog(pc);

	if(noadr == 0)
		if(nohex == 1 )
			printf("%04x\t",pc);
		else
			printf("%04x  ",pc);
	if(nohex == 0)
		disp_hex(buf_pc,optab[index].bytecount);
	else
		printf("\t");
	printf("%s",optab[index].mne);
	display_operands(index,buf_pc);
	printf("\n");
	inc_pcs(optab[index].bytecount);
	lc += optab[index].bytecount; 
     }
}


int main(int argc, char** argv)
{
    int c;
    nohex=0;
    noadr=0;
    quiet=0;
    
    buffer = (unsigned char *)malloc(sizeof(char));
    bufbase = buffer;pc = 0;

    while ((c = getopt (argc, argv, "haq")) != -1) {
	switch (c) {
	    case 'h':
		nohex=1;
		break;
	    case 'a':
		noadr=1;
		break;
	    case 'q':
		quiet=1;
		break;
	}
    }

    if(quiet==0)
	printf("\nZ8 Disassembler Ver 1.0\n\n");

    if(optind >= argc) {
       fprintf(stderr,"No input file given -- abort\n");
       return 0;
    }

    read_bin(argv[optind],0);
    buf_pc = bufbase;
    disasm();    
}

