main zdis.c
  1/*
  2 Copyright 2013 Michael Pavone
  3 This file is part of BlastEm. 
  4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
  5*/
  6#include "z80inst.h"
  7#include <stdio.h>
  8#include <stdlib.h>
  9#include <stdarg.h>
 10
 11uint8_t visited[(64*1024)/8];
 12uint8_t label[(64*1024)/8];
 13
 14void fatal_error(char *format, ...)
 15{
 16	va_list args;
 17	va_start(args, format);
 18	vfprintf(stderr, format, args);
 19	va_end(args);
 20	exit(1);
 21}
 22
 23void visit(uint16_t address)
 24{
 25	visited[address/8] |= 1 << (address % 8);
 26}
 27
 28void reference(uint16_t address)
 29{
 30	//printf("referenced: %X\n", address);
 31	label[address/8] |= 1 << (address % 8);
 32}
 33
 34uint8_t is_visited(uint16_t address)
 35{
 36	return visited[address/8] & (1 << (address % 8));
 37}
 38
 39uint8_t is_label(uint16_t address)
 40{
 41	return label[address/8] & (1 << (address % 8));
 42}
 43
 44typedef struct deferred {
 45	uint16_t address;
 46	struct deferred *next;
 47} deferred;
 48
 49deferred * defer(uint16_t address, deferred * next)
 50{
 51	if (is_visited(address)) {
 52		return next;
 53	}
 54	//printf("deferring %X\n", address);
 55	deferred * d = malloc(sizeof(deferred));
 56	d->address = address;
 57	d->next = next;
 58	return d;
 59}
 60
 61uint8_t labels = 0;
 62uint8_t addr = 0;
 63uint8_t only = 0;
 64
 65int main(int argc, char ** argv)
 66{
 67	long filesize;
 68	uint8_t *filebuf;
 69	char disbuf[1024];
 70	z80inst instbuf;
 71	uint8_t * cur;
 72	FILE * f = fopen(argv[1], "rb");
 73	fseek(f, 0, SEEK_END);
 74	filesize = ftell(f);
 75	fseek(f, 0, SEEK_SET);
 76	filebuf = malloc(filesize);
 77	fread(filebuf, 1, filesize, f);
 78	fclose(f);
 79	deferred *def = NULL, *tmpd;
 80	uint16_t offset = 0;
 81	for(uint8_t opt = 2; opt < argc; ++opt) {
 82		if (argv[opt][0] == '-') {
 83			FILE * address_log;
 84			switch (argv[opt][1])
 85			{
 86			case 'l':
 87				labels = 1;
 88				break;
 89			case 'a':
 90				addr = 1;
 91				break;
 92			case 'o':
 93				only = 1;
 94				break;
 95			case 'f':
 96				opt++;
 97				if (opt >= argc) {
 98					fputs("-f must be followed by a filename\n", stderr);
 99					exit(1);
100				}
101				address_log = fopen(argv[opt], "r");
102				if (!address_log) {
103					fprintf(stderr, "Failed to open %s for reading\n", argv[opt]);
104					exit(1);
105				}
106				while (fgets(disbuf, sizeof(disbuf), address_log)) {
107				 	if (disbuf[0]) {
108						uint16_t address = strtol(disbuf, NULL, 16);
109						if (address) {
110							def = defer(address, def);
111							reference(address);
112						}
113					}
114				}
115				fclose(address_log);
116				break;
117			case 's':
118				opt++;
119				if (opt >= argc) {
120					fputs("-s must be followed by a start offset in hex\n", stderr);
121					exit(1);
122				}
123				offset = strtol(argv[opt], NULL, 16);
124				break;
125			}
126		} else {
127			uint16_t address = strtol(argv[opt], NULL, 16);
128			def = defer(address, def);
129			reference(address);
130		}
131	}
132	uint16_t start = offset;
133	uint8_t *encoded, *next;
134	uint32_t size;
135	if (!def || !only) {
136		def = defer(start, def);
137	}
138	uint16_t address;
139	while(def) {
140		do {
141			encoded = NULL;
142			address = def->address;
143			if (!is_visited(address)) {
144				encoded = filebuf + address - offset;
145			}
146			tmpd = def;
147			def = def->next;
148			free(tmpd);
149		} while(def && encoded == NULL);
150		if (!encoded) {
151			break;
152		}
153		for(;;) {
154			if ((address - offset) > filesize || is_visited(address) || address < offset) {
155				break;
156			}
157			visit(address);
158			next = z80_decode(encoded, &instbuf);
159			address += (next-encoded);
160			encoded = next;
161			
162			//z80_disasm(&instbuf, disbuf);
163			//printf("%X: %s\n", address, disbuf);
164			switch (instbuf.op)
165			{
166			case Z80_JR:
167				address += instbuf.immed;
168				encoded = filebuf + address - offset;
169				break;
170			case Z80_JRCC:
171				reference(address + instbuf.immed);
172				def = defer(address + instbuf.immed, def);
173				break;
174			case Z80_JP:
175				address = instbuf.immed;
176				encoded = filebuf + address - offset;
177				break;
178			case Z80_JPCC:
179			case Z80_CALL:
180			case Z80_CALLCC:
181			case Z80_RST:
182				reference(instbuf.immed);
183				def = defer(instbuf.immed, def);
184				break;
185			default:
186				if (z80_is_terminal(&instbuf)) {
187					address = filesize + 1;
188				}
189			}
190		}
191	}
192	if (labels) {
193		for (address = filesize; address < (64*1024); address++) {
194			if (is_label(address)) {
195				printf("ADR_%X equ $%X\n", address, address);
196			}
197		}
198		puts("");
199	}
200	for (address = offset; address < filesize + offset; address++) {
201		if (is_visited(address)) {
202			encoded = filebuf + address - offset;
203			z80_decode(encoded, &instbuf);
204			if (labels) {
205				/*m68k_disasm_labels(&instbuf, disbuf);
206				if (is_label(instbuf.address)) {
207					printf("ADR_%X:\n", instbuf.address);
208				}
209				if (addr) {
210					printf("\t%s\t;%X\n", disbuf, instbuf.address);
211				} else {
212					printf("\t%s\n", disbuf);
213				}*/
214			} else {
215				z80_disasm(&instbuf, disbuf, address);
216				printf("%X: %s\n", address, disbuf);
217			}
218		}
219	}
220	return 0;
221}