[net.sources] Z-80 disassembler

rees@apollo.UUCP (07/10/84)

# The rest of this file is a shell script which will extract:
# Readme dis.c distab.c
echo x - Readme
cat >Readme <<'Godfather_Of_Soul'
This is an el-cheapo Z-80 disassembler, written in C.  I wrote it myself.
No comments - tough.  It expects to see an input file containing records
of the form

	<start_adr> <count> <bytes>

where <start_adr> and <count> are two byte integers, least significant
first, and there are <count> bytes of data.  There can be an arbitrary
number of these records.

There is some cruft in here for TRS-80 start addresses, in getbyte().
You can probably ignore it, but may want to take it out.

If you give it a "-a" flag, it produces output suitable for input to
a Z-80 assembler.

Some of the Z-80 instructions are not supported.  A special prize for
anyone who adds these.

Let me know if you find any use for this.
Godfather_Of_Soul
echo x - dis.c
cat >dis.c <<'Godfather_Of_Soul'
#include <stdio.h>

extern struct optab {
	short op_mask, op_val;
	char *op_op;
} optab[], toptab[], ddoptab[], edoptab[], fdoptab[];

struct optab *xopt[] = {
	toptab,
	ddoptab,
	edoptab,
	fdoptab,
};

char *f1_op[] = {
	"add\ta,", "adc\ta,", "sub\t", "sbc\ta,",
	"and\t", "xor\t", "or\t", "cp\t"
};

char *rnam[] = {
	"b", "c", "d", "e", "h", "l", "(hl)", "a"
};

char *ssnam[] = {
	"bc", "de", "hl", "sp"
};

char *qqnam[] = {
	"bc", "de", "hl", "af"
};

char *cctab[] = {
	"nz", "z", "nc", "c", "po", "pe", "p", "m"
};

int adr;
char text[64];
int hexcol;
int startadr= -1;
int aflg;

main(ac,av)
int ac;
char *av[];
{
	FILE *in;
	int c,i;
	int f0,f1,f2;
	struct optab *opp;
	char sbuf[32];

	while (ac > 1 && av[1][0] == '-') {
		switch (av[1][1]) {
		case 'a':
			aflg = 1;
			break;
		}
		ac--;
		av++;
	}
	if (ac > 1) {
		if ((in = fopen(av[1], "r")) == NULL) {
			perror(av[1]);
			exit(1);
		}
	} else
		in = stdin;
	while ((c = getbyte(in)) != EOF) {
		if (aflg)
			strcpy(text, "\t");
		else {
			sprintf(text, "%.4x         \t", adr-1);
			hexcol = 5;
			addhex(c);
		}
		docode(c, optab, in, text);
		printf("%s\n", text);
	}
	if (!aflg)
		printf("%.4x         ", adr);
	printf("\tend", adr);
	if (startadr != -1) {
		sphexno(sbuf, "\t%s", startadr);
		printf(sbuf);
	}
	printf("\n");
	exit(0);
}

docode(c, opp, in, text)
int c;
struct optab *opp;
FILE *in;
char *text;
{
	for (; opp->op_mask != 0; opp++)
		if ((c&opp->op_mask) == opp->op_val)
			break;
	expand(c, opp->op_op, in, text);
}

expand(c, op, in, text)
int c;
char *op, *text;
FILE *in;
{
	int i,j;
	char *s,sbuf[32];

	for (s=op; *s; s++) {
		sbuf[0] = '\0';
		switch (*s) {
		case 'B':
			i = getbyte(in);
			addhex(i);
			sphexno(sbuf, "%s", i);
			break;
		case '-':	/* Relative jump */
			i = getbyte(in);
			addhex(i);
			if (i > 127)
				i -= 256;
			i += adr;
			sphexno(sbuf, "%s", i);
			break;
		case 'W':
			addhex(i = getbyte(in));
			addhex(j = getbyte(in));
			i = i | (j << 8);
			sphexno(sbuf, "%s", i);
			break;
		case 'S':
			sprintf(sbuf, "%s", ssnam[(c>>4)&0x3]);
			break;
		case 'Q':
			sprintf(sbuf, "%s", qqnam[(c>>4)&0x3]);
			break;
		case 'P':
			sprintf(sbuf, "%s", rnam[(c>>3)&0x7]);
			break;
		case 'R':
			sprintf(sbuf, "%s", rnam[c&0x7]);
			break;
		case 'F':
			sprintf(sbuf, "%s", f1_op[(c>>3)&0x7]);
			break;
		case 'T':
			sprintf(sbuf, "%d", (c>>3)&0x7);
			break;			
		case 'X':
			c = getbyte(in);
			addhex(c);
			docode(c, xopt[*(++s)-'0'], in, text);
			break;			
		case 'K':
			strcpy(sbuf, (c&0x8) ? "d" : "i");
			if (c & 0x10)
				strcat(sbuf, "r");
			break;
		case 'C':
			sprintf(sbuf, "%s", cctab[(c>>3)&07]);
			break;
		default:
			sbuf[0] = *s;
			sbuf[1] = '\0';
			break;
		}
	strcat(text, sbuf);
	}
}

addhex(x)
int x;
{
	if (aflg)
		return;
	addnib(x >> 4);
	addnib(x & 0xf);
}

addnib(x)
int x;
{
	x += '0';
	if (x > '9')
		x += 'a' - '9' - 1;
	text[hexcol++] = x;
}

getbyte(f)
FILE *f;
{
	static int count;
	int i,oadr;
	char sbuf[32];

	while (count == 0) {
		oadr = adr;
		if ((i = getint(f)) == EOF)
			return(EOF);
		adr = i;
		count = getint(f);
		if (adr == 0x40df && count == 2) {
			if ((startadr = getint(f)) == EOF)
				return(EOF);
			count = 0;
			adr = oadr;
		} else if (adr != oadr) {
			sphexno(sbuf, "%s", adr);
			if (!aflg)
				printf("%.4x         ", oadr);
			printf("\torg\t%s\n", sbuf);
		}
	}
	adr++;
	count--;
	if ((i = getc(f)) == EOF) {
		printf("Premature EOF\n");
		exit(1);
	}
	return(i);
}

getint(f)
FILE *f;
{
	int c,i;

	i = getc(f);
	if ((c = getc(f)) == EOF)
		return(EOF);
	else
		return(i | (c << 8));
}

sphexno(s, sform, n)
char *s, *sform;
int n;
{
	char sbuf[32], *xform;

	if (n < 0 || n > 0xffff) {
		fprintf(stderr, "sphexno(%d)\n", n);
		exit(1);
	}
	if (n <= 9)
		xform = "%d";
	else if ((n > 0x10 && n <= 0x9f) || (n > 0x100 && n <= 0x9ff)
	    || (n > 0x1000 && n <= 0x9fff))
		xform = "%xh";
	else
		xform = "0%xh";
	sprintf(sbuf, xform, n);
	sprintf(s, sform, sbuf);
}
Godfather_Of_Soul
echo x - distab.c
cat >distab.c <<'Godfather_Of_Soul'
struct optab {
	short op_mask, op_val;
	char *op_op;
};

struct optab optab[] = {
	0xff,	0,	"nop",
	0xc0,	0x40,	"ld\tP,R",
	0xc0,	0x80,	"FR",
	0xc7,	0x04,	"inc\tP",
	0xc7,	0x05,	"dec\tP",
	0xc7,	0x06,	"ld\tP,B",
	0xc7,	0xc0,	"ret\tC",
	0xc7,	0xc2,	"jp\tC,W",
	0xc7,	0xc4,	"call\tC,W",
	0xc7,	0xc6,	"FB",
	0xc7,	0xc7,	"rst\tT",
	0xcf,	0x01,	"ld\tS,W",
	0xef,	0x02,	"ld\t(S),a",
	0xef,	0x0a,	"ld\ta,(S)",
	0xcf,	0x03,	"inc\tS",
	0xcf,	0x09,	"add\thl,S",
	0xcf,	0x0b,	"dec\tS",
	0xff,	0x7,	"rlca",
	0xff,	0x8,	"ex\taf,af'",
	0xff,	0x0f,	"rrca",
	0xff,	0x10,	"djnz\t-",
	0xff,	0x17,	"rla",
	0xff,	0x18,	"jr\t-",
	0xff,	0x1f,	"rra",
	0xff,	0x20,	"jr\tnz,-",
	0xff,	0x27,	"daa",
	0xff,	0x28,	"jr\tz,-",
	0xff,	0x2f,	"cpl",
	0xff,	0x30,	"jr\tnc,-",
	0xff,	0x37,	"scf",
	0xff,	0x38,	"jr\tc,-",
	0xff,	0x22,	"ld\t(W),hl",
	0xff,	0x2a,	"ld\thl,(W)",
	0xff,	0x32,	"ld\t(W),a",
	0xff,	0x3a,	"ld\ta,(W)",
	0xff,	0x3f,	"ccf",
	0xcf,	0xc1,	"pop\tQ",
	0xff,	0xc3,	"jp\tW",
	0xcf,	0xc5,	"push\tQ",
	0xff,	0xc9,	"ret",
	0xff,	0xcb,	"X0",
	0xff,	0xcd,	"call\tW",
	0xff,	0xd3,	"out\t(B),a",
	0xff,	0xd9,	"exx",
	0xff,	0xdb,	"in\ta,(B)",
/*	0xff,	0xdd,	"X1",	*/
	0xff,	0xe3,	"ex\t(sp),hl",
	0xff,	0xe9,	"jp\t(hl)",
	0xff,	0xeb,	"ex\tde,hl",
	0xff,	0xed,	"X2",
	0xff,	0xf3,	"di",
	0xff,	0xfb,	"ei",
/*	0xff,	0xfd,	"X3",	*/
	0xff,	0xf9,	"ld\tsp,hl",
	0,	0,	"???",
};

struct optab toptab[] = {
	0xf8,	0,	"rlc\tR",
	0xf8,	0x8,	"rrc\tR",
	0xf8,	0x10,	"rl\tR",
	0xf8,	0x18,	"rr\tR",
	0xf8,	0x20,	"sla\tR",
	0xf8,	0x28,	"sra\tR",
	0xf8,	0x38,	"srl\tR",
	0xc0,	0x40,	"bit\tT,R",
	0xc0,	0x80,	"res\tT,R",
	0xc0,	0xc0,	"set\tT,R",
	0,	0,	"???",
};

struct optab ddoptab[] = {
	0,	0,	"???",
};

struct optab edoptab[] = {
	0xcf,	0x42,	"sbc\thl,S",
	0xcf,	0x43,	"ld\t(W),S",
	0xcf,	0x4a,	"adc\thl,S",
	0xcf,	0x4b,	"ld\tS,(W)",
	0xe7,	0xa0,	"ldK",
	0xe7,	0xa1,	"cpK",
	0xe7,	0xa2,	"inK",
	0xff,	0x2b,	"dec\tix",
	0xff,	0x35,	"dec\t(ix+B)",
	0xff,	0x44,	"neg",
	0xff,	0x46,	"im\t0",
	0xff,	0x4b,	"ld\tbc,(W)",
	0xff,	0x4d,	"reti",
	0xff,	0x56,	"im\t1",
	0xff,	0x5b,	"ld\tde,(W)",
	0xff,	0x66,	"im\t2",
	0xff,	0x67,	"rrd",
	0xff,	0x6f,	"rld",
	0xff,	0x73,	"ld\t(W),sp",
	0xff,	0x7b,	"ld\tsp,(W)",
	0,	0,	"???",
};

struct optab fdoptab[] = {
	0,	0,	"???",
};
Godfather_Of_Soul