home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
messroms.de
/
2007-01-13_www.messroms.de.zip
/
CGENIE
/
TOOLS
/
DZ80.ZIP
/
dz80.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-12-09
|
10KB
|
410 lines
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "z80.h"
#include "dis.h"
#define CGENIE 1
BYTE mem[0x10000]; // memory image
static BOOL flg_dump = 1;
static BOOL flg_cassette = 0;
static BOOL flg_blkinfo = 0;
static BOOL flg_cgdos = 0;
static BOOL flg_colcom = 0;
static WORD dis_offset = 0x0000;
static WORD dis_beg_addr = 0xFFFF;
static WORD dis_end_addr = 0x0000;
static WORD dis_run_addr = 0x0000;
static int dis_line_cnt = 0;
static int dis_line_max = 0x7FFFFFFF;
static char * inp_filename = NULL;
static char * out_filename = NULL;
static char def_filename[160];
static FILE * dis_inp_file = NULL;
static FILE * dis_out_file = NULL;
BOOL dis_output(char * src)
{
while (*src)
{
if (*src == '\n')
{
if (++dis_line_cnt >= dis_line_max)
return 1;
}
fputc(*src, dis_out_file);
src++;
}
fputc('\n', dis_out_file);
if (++dis_line_cnt >= dis_line_max)
return 1;
return 0;
}
void dis_range(WORD beg, WORD end)
{
WORD addr = beg;
WORD old;
do
{
old = addr;
if (dis_output(disasm(&addr, flg_dump)))
return;
} while( addr >= old && addr <= end );
}
int main(int ac, char ** av)
{
int i;
char * dst;
if( ac < 2 )
{
fprintf(stderr, "usage: dz80 [-a|-c|-i|-o xxxx] inputfile [outputfile]\n");
fprintf(stderr, "options:\n");
fprintf(stderr, "\t-a\tASM output (no addr/data columns)\n");
#if CGENIE
fprintf(stderr, "\t-c\tfile is in .CAS format\n");
#else
fprintf(stderr, "\t-v\tfile is in .VZ format\n");
#endif
fprintf(stderr, "\t-i\tprint block info\n");
fprintf(stderr, "\t-o\tload from offset xxxx\n");
fprintf(stderr, "\t-j\tDEF file options\n");
fprintf(stderr, "\t-jd\tinclude CGDOS.DEF\n");
fprintf(stderr, "\t-jc\tfile is Colour Compiler output\n");
exit(1);
}
for (i = 1; i < ac; i++)
{
if (av[i][0] == '-')
{
switch (av[i][1])
{
case 'a': case 'A':
flg_dump = 0;
break;
#if CGENIE
case 'c': case 'C':
flg_cassette = 1;
break;
#else
case 'v': case 'V':
flg_cassette = 1;
break;
#endif
case 'i': case 'I':
flg_blkinfo = 1;
break;
case 'j': case 'J':
if (toupper(av[i][2]) == 'C')
flg_colcom = 1;
if (toupper(av[i][2]) == 'D')
flg_cgdos = 1;
break;
case 'o': case 'O':
i++;
dis_offset = hextoi(av[i]);
dis_run_addr = dis_offset;
break;
default:
fprintf(stderr, "unknown option %x\n", av[i][1]);
exit(1);
break;
}
}
else
{
if (!inp_filename)
inp_filename = av[i];
else
if (!out_filename)
out_filename = av[i];
}
}
if (!inp_filename)
{
fprintf(stderr, "no input filename given\n");
exit(1);
}
dis_inp_file = fopen(inp_filename, "rb");
if (!dis_inp_file)
{
fprintf(stderr, "input file %s not found\n", inp_filename);
exit(1);
}
if (out_filename)
{
dis_out_file = fopen(out_filename, "wa");
if (!dis_out_file)
{
fprintf(stderr, "can't create output file %s\n", out_filename);
exit(1);
}
}
else
{
dis_out_file = stdout;
}
#if CGENIE
if( flg_cassette )
{
WORD cnt;
WORD addr;
BYTE sum;
BYTE c;
if( (c = fgetc(dis_inp_file)) != 0x66 )
{
fprintf(stderr, "file seems to be no .CAS file (0000:%02X != 66)\n", c);
exit(1);
}
if( (c = fgetc(dis_inp_file)) != 0x55 )
{
fprintf(stderr, "file seems to be no machine code .CAS file (0001:%02X != 55)\n", c);
exit(1);
}
for( i = 0; i < 6; i++ )
{
if (!isalnum(c = fgetc(dis_inp_file)) && (c != ' '))
{
fprintf(stderr, "file seems to be no machine code .CAS file (%04X:%02X)\n", (int)ftell(dis_inp_file) - 1, c);
exit(1);
}
}
while( !feof(dis_inp_file) )
{
c = fgetc(dis_inp_file);
if (c == 0x78)
{
c = fgetc(dis_inp_file);
addr = c;
c = fgetc(dis_inp_file);
addr += 256 * c;
dis_run_addr = addr;
if (flg_blkinfo)
printf("entry point is %04X\n", addr);
#if 0
if (!feof(dis_inp_file))
{
if (flg_blkinfo)
printf("reading excess data at %04X\n", (int) ftell(dis_inp_file));
while( !feof(dis_inp_file) )
c = fgetc(dis_inp_file);
}
#else
break;
#endif
continue;
}
if (c != 0x3C)
{
fprintf(stderr, "expected block header 3C (%04X:%02X)\n", (int)ftell(dis_inp_file) - 1, c);
exit(1);
}
cnt = fgetc(dis_inp_file);
if (!cnt)
cnt = 256;
sum = 0;
c = fgetc(dis_inp_file);
sum += c;
addr = c;
c = fgetc(dis_inp_file);
sum += c;
addr+= 256 * c;
if (addr < dis_beg_addr)
dis_beg_addr = addr;
if (flg_blkinfo)
printf("loading %3d bytes to %04X\n", cnt, addr);
while (cnt-- > 0)
{
c = fgetc(dis_inp_file);
sum += c;
mem[addr++] = c;
}
if (addr > dis_end_addr)
dis_end_addr = addr;
c = fgetc(dis_inp_file);
if (c != sum)
{
fprintf(stderr, "bad block checksum (%04X:%02X != %02X)\n", (int)ftell(dis_inp_file) - 1, c, sum);
exit(1);
}
}
if( mem[dis_run_addr] == 0xf3 && // DI
mem[dis_run_addr+1] == 0x21 && // LD HL,....
mem[dis_run_addr+4] == 0x11 && // LD DE,....
mem[dis_run_addr+7] == 0x01 && // LD BC,....
mem[dis_run_addr+10] == 0xed && // LDIR
mem[dis_run_addr+11] == 0xb0 &&
mem[dis_run_addr+12] == 0xc3 ) // JP xxxx
{
WORD src = *(WORD*)&mem[dis_run_addr+2];
WORD dst = *(WORD*)&mem[dis_run_addr+5];
WORD cnt = *(WORD*)&mem[dis_run_addr+8];
if (flg_blkinfo)
printf("DOS offset loader at: %04X\n", dis_run_addr);
dis_run_addr = *(WORD*)&mem[dis_run_addr+13];
memmove(mem + dst, mem + src, cnt);
dis_beg_addr += dst - src;
dis_end_addr += dst - src;
if (flg_blkinfo)
printf("real start:%04X, end:%04X, entry:%04X\n", dis_beg_addr, dis_end_addr, dis_run_addr);
}
}
#else /* CGENIE */
if( flg_cassette )
{
WORD addr;
BYTE c;
if( (c = fgetc(dis_inp_file)) != ' ' )
{
fprintf(stderr, "file seems to be no machine code .VZ file (0000:%02X != 20)\n", c);
exit(1);
}
if( (c = fgetc(dis_inp_file)) != ' ' )
{
fprintf(stderr, "file seems to be no machine code .VZ file (0001:%02X != 20)\n", c);
exit(1);
}
if( (c = fgetc(dis_inp_file)) != 0x00 )
{
fprintf(stderr, "file seems to be no machine code .VZ file (0002:%02X != 00)\n", c);
exit(1);
}
if( (c = fgetc(dis_inp_file)) != 0x00 )
{
fprintf(stderr, "file seems to be no machine code .VZ file (0003:%02X != 00)\n", c);
exit(1);
}
for( i = 0; i < 17; i++ )
{
if( !isalnum(c = fgetc(dis_inp_file)) && (c != ' ') && (c != 0x00) )
{
fprintf(stderr, "file seems to be no machine code .CAS file (%04X:%02X)\n", (int)ftell(dis_inp_file) - 1, c);
exit(1);
}
}
addr = fgetc(dis_inp_file);
addr += 256 * fgetc(dis_inp_file);
dis_run_addr = addr;
dis_end_addr = addr;
if (flg_blkinfo)
printf("entry point is %04X\n", addr);
while( !feof(dis_inp_file) )
{
c = fgetc(dis_inp_file);
mem[addr++] = c;
}
if (flg_blkinfo)
printf("end address is %04X\n", addr);
if( addr > dis_end_addr )
dis_end_addr = addr;
}
#endif
else
{
dis_beg_addr = dis_offset;
while( !feof(dis_inp_file) )
{
int cnt = fread(mem + dis_offset, 1, 0x10000 - dis_offset, dis_inp_file);
if (dis_beg_addr + cnt - 1 > dis_end_addr)
dis_end_addr = dis_beg_addr + cnt - 1;
dis_offset = 0;
}
}
#if CGENIE
DEF_file_read("CGENIE.DEF");
if (flg_cgdos) // include colour genie dos symbols?
DEF_file_read("CGDOS.DEF");
#else
DEF_file_read("VZROM.DEF");
if (flg_cgdos) // include VZ dos symbols?
DEF_file_read("VZDOS.DEF");
#endif
if (flg_colcom) // colour compiler output ?
{
WORD data;
WORD strs;
WORD code;
char strname[6+1] = "str000";
char strchr = 0;
int strcnt = 0;
int i;
dis_run_addr = 0x7C02;
DEF_file_read("COLCOM.DEF");
if (*(WORD*)&mem[0x4802] != 0x4804)
{
dis_beg_addr = 0x5800;
code = *(WORD*)&mem[0x7FBF];
memcpy(mem + 0x5800, mem + 0x7380, 0x880);
memset(mem + 0x7380, 0, 0x800);
}
else
{
code = *(WORD*)&mem[0x7FBC];
dis_beg_addr = 0x4800;
}
data = *(WORD*)&mem[0x7FB5];
OPT_def(data, MEM_DATA, 1, OPT_WORDS);
SYM_add(data, SYM_DATA, "__DATA");
strs = *(WORD*)&mem[0x7FB3];
OPT_def(strs, MEM_DATA, 0, OPT_ASCII);
strchr = 0;
strcnt = 0;
for (i = strs; i < code; i++)
{
if ((strchr == 0) && (strcnt < 500))
{
sprintf(strname, "__STR%03d", strcnt++);
SYM_add(i, SYM_DATA, strname);
}
strchr = mem[i];
}
OPT_def(code, MEM_CODE, 0, OPT_NONE);
SYM_add(code, SYM_CODE, "__LINE1");
}
strcpy(def_filename, inp_filename);
dst = strrchr(def_filename, '.');
if (!dst)
strcat(def_filename, ".DEF");
else
strcpy(dst, ".DEF");
DEF_file_read(def_filename);
dst = strrchr(def_filename, '\\');
if (!dst)
dst = strrchr(def_filename, '/');
if (dst)
{
strcpy(def_filename, dst + 1);
DEF_file_read(def_filename);
}
disasm_init(dis_beg_addr);
SYM_add(dis_run_addr, SYM_CODE, "ENTRY");
dis_range(dis_beg_addr, dis_end_addr);
return 0;
}