/*** Z80Em: Portable Z80 emulator *******************************************/
/***                                                                      ***/
/***                               z80dasm.c                              ***/
/***                                                                      ***/
/*** This file contains a portable Z80 disassembler                       ***/
/***                                                                      ***/
/*** Copyright (C) Marcel de Kogel 1996,1997                              ***/
/***     You are not allowed to distribute this software commercially     ***/
/***     Please, notify me, if you make any changes to this file          ***/
/****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#ifndef TRUE
#define TRUE (0==0)
#define FALSE (0!=0)
#endif
extern int deflab(int pc);
extern int Z80_Translate (int pc);

//#define MSPAC 1
//#define BERZERK 1
#define DKONG 1

static long icount[0x10000];
int pass;

#include "Z80Dasm.h"
extern int lab[0x10000];
extern char *tags[0x10000];
static char *Options[]=
{
 "begin","end","offset",NULL
};

static void usage (void)
{
 printf ("Usage: z80dasm [options] <filename>\n"
         "Available options are:\n"
         " -begin  - Specify begin offset in file to disassemble [0]\n"
         " -end    - Specify end offset in file to disassemble [none]\n"
         " -offset - Specify address to load program [0]\n"
         "All values should be entered in hexadecimal\n");
 exit (1);
}

extern unsigned char mem[0x10000];

int main (int argc,char *argv[])
{
 int i,j,n;
 char buf[20+3];
 unsigned char *filebuf;
 unsigned begin=0,end=(unsigned)-1,offset=0,filelen,len,pc;


 int LOAD(char *filename, int offset, int size) {
 FILE *f;
 f=fopen (filename, "rb");
 if (!f)
 {
  printf ("Unable to open %s\n",filename);
  return 2;
 }
 if (fread(mem+offset,1,size,f)!=size)
 {
  printf ("Read error\n");
  fclose (f);
  exit(4);
 }
 fclose (f);
}

 for (pc = 0; pc < 0x10000; pc++) { lab[pc] = FALSE; tags[pc] = NULL; }
 // should be in disasm.info file, but can't be bothered extending
 // the format yet...  these ones are for RST
//#ifdef MSPAC
 lab[0x0008] = TRUE;
 lab[0x0010] = TRUE;
 lab[0x0018] = TRUE;
 lab[0x0020] = TRUE;
 lab[0x0028] = TRUE;
 lab[0x0030] = TRUE;
 lab[0x0038] = TRUE;
//#endif
 
 printf ("//z80dasm: Portable Z80 disassembler\n"
         "//Copyright (C) Marcel de Kogel 1996,1997\n");

#ifdef MSPAC
 LOAD("BOOT1", 0x0000, 0x1000);
 LOAD("BOOT2", 0x1000, 0x1000);
 LOAD("BOOT3", 0x2000, 0x1000);
 LOAD("BOOT4", 0x3000, 0x1000);
 LOAD("BOOT5", 0x8000, 0x1000);
 LOAD("BOOT6", 0x9000, 0x1000);
#endif
#ifdef BERZERK
 LOAD("berzerk.rom", 0x0000, 0x1000);
#endif
#ifdef DKONG
 LOAD("dkong.rom", 0x0000, 0x4000);
#endif

 pass = 1;
 freopen("/dev/null", "w", stdout);

 {
  int low, high;
  int rc;
  char line[128], tag[128];
  char addr[16];
  char *s;
  char info[256];
  FILE *range;

  strcpy(info, "");
#ifdef MSPAC
  strcpy(info, "mspac.info");
#endif
#ifdef BERZERK
  strcpy(info, "berzerk.info");
#endif
#ifdef DKONG
  strcpy(info, "dkong.info");
#endif

  range=fopen(info, "r");
  if (range == NULL) {
    fprintf(stderr, "z80dasm: cannot open \"%s\" - %s\n", info, strerror(errno));
    exit(1);
  }

  /* first pass */

 pc=0; low = -1;
 for (;;) {
  while (low < (int)pc) {
    s = fgets(line, 127, range);
    if (s == NULL) break;
    s = strchr(line, '\n');
    if (s != NULL) *s = '\0';
    if (*line == '#') continue;
    if (*line == '@') {
      int sym; // no vetting yet, assume strict format is correct
      line[5] = '\0';
      sprintf(addr, "0x%s", line+1); rc = sscanf(addr+2, "%04x", &sym);
      tags[sym] = strdup(line+6);
      //fprintf(stderr, "Added %s at %04x\n", tags[sym], sym);
      continue;
    }
    if (*line == '\0') continue;
    if (line[4] != '-') {
      fprintf(stderr, "Bad format: %s\n", line); exit(2);
    }
    line[4] = '\0'; s = line+5;
    sprintf(addr, "0x%s", line); rc = sscanf(line, "%04x", &low); // BUG???!
    sprintf(addr, "0x%s", s); rc = sscanf(s, "%04x", &high); // wrong string???
//    fprintf(stdout, "// Range: %04x to %04x\n", low, high);
  }

  if (((int)pc >= (int)low) && ((int)pc <= (int)high)) {
//    printf("// Skipping %04x to %04x\n", low, high);
    pc = high+1; deflab(pc);
  }

#ifdef MSPAC
  if (pc >= 0x10000) break;
#endif
#ifdef BERZERK
  if (pc >= 0x3800) break;
#endif
#ifdef DKONG
  if (pc >= 0x4000) break;
#endif
  i=Z80_Dasm(mem+pc, buf, pc);
  for (j=strlen(buf);j<19+3;++j) buf[j]=' ';
  buf[19+3]='\0';
//  printf ("L%04x:                            ",pc);
//  printf ("%s    ; ",buf);
//  for (j=0;j<i;++j) printf("%02X ",mem[pc+j]);
//  printf ("\n");
  Z80_Translate(pc);
// remember to do same for second pass.  Need to clean up code and make that a loop!
#ifdef MSPAC
  if (mem[pc] == 0xe7) i += 4; // RST 20
  if (mem[pc] == 0xef) i += 2;
  if (mem[pc] == 0xf7) i += 3;
#endif
#ifdef BERZERK
#endif
#ifdef DKONG
#endif
  pc+=i;
 }

/* second pass */
  fclose(range);
#ifdef MSPAC
  range=fopen("mspac.info", "r");
#endif
#ifdef BERZERK
  range=fopen("berzerk.info", "r");
#endif
#ifdef DKONG
  range=fopen("dkong.info", "r");
#endif
  if (range == NULL) exit(1);


  {
    FILE *f;
#ifdef MSPAC
    f = fopen("mspac-trace.log", "r");
#endif
#ifdef BERZERK
    f = fopen("berzerk-trace.log", "r");
#endif
#ifdef DKONG
    f = fopen("dkong-trace.log", "r");
#endif
    int i;
    for (i = 0; i < 0x10000; i++) icount[i] = 0;
    if (f != NULL) {
      for (i = 0; i < 0x10000; i++) fscanf(f, "%ld\n", &icount[i]);
      fclose(f);
    }
  }



  freopen("/dev/stderr", "w", stdout);

pass = 2;

 pc=0; low = -1;
 for (;;) {
  while (low < (int)pc) {
    s = fgets(line, 127, range);
    if (s == NULL) break;
    s = strchr(line, '\n');
    if (s != NULL) *s = '\0';
    if (*line == '#') continue;
    if (*line == '\0') continue;
    if (*line == '@') continue;
    if (line[4] != '-') {
      fprintf(stderr, "Bad format: %s\n", line); exit(2);
    }
    line[4] = '\0'; s = line+5;
    sprintf(addr, "0x%s", line); rc = sscanf(line, "%04x", &low);
    sprintf(addr, "0x%s", s); rc = sscanf(s, "%04x", &high);
//    fprintf(stdout, "// Range: %04x to %04x\n", low, high);
  }

  if (((int)pc >= (int)low) && ((int)pc <= (int)high)) {
    printf("                                  // Skipping %04x to %04x\n", low, high);
    pc = high+1;
    deflab(pc);
  }

#ifdef DKONG
  if (pc >= 0x4000) break;
#endif
  if (pc >= 0x10000) break;
  i=Z80_Dasm(mem+pc, buf, pc);
  for (j=strlen(buf);j<19+3;++j) buf[j]=' ';
  buf[19+3]='\0';
  if (lab[pc]) {
    printf ("L%04x:                            ",pc);
    lab[pc] = 2;
  } else {
    printf ("                                  ");
//    printf ("/* L%04x: */                      ",pc);
  }
// need this for interleaved x86 asm listing:  printf ("LINE=0x%04x; //dumpregs(); printf(\"%s    ; [%04x] ",pc,buf,pc);
  printf ("dumpregs(0x%04x, \"%s    ; [%04x] ",pc,buf,pc);
//  printf ("%s    ; [%04x] ",buf,pc);
  for (j=0;j<i;++j) printf("%02X ",mem[pc+j]);
  if (icount[pc]!=0L) printf(" {%ld}", icount[pc]);
  printf ("\\n\");\n");
//  printf ("\n");
  Z80_Translate(pc);
#ifdef MSPAC
  if (mem[pc] == 0xe7) i += 4; // RST 20
  if (mem[pc] == 0xef) i += 2;
  if (mem[pc] == 0xf7) i += 3;
#endif
  pc+=i;
 }


 }
{FILE *labfile;
#ifdef MSPAC
 labfile = fopen("mspac-lab.h", "w");
#endif
#ifdef BERZERK
 labfile = fopen("berzerk-lab.h", "w");
#endif
#ifdef DKONG
 labfile = fopen("dkong-lab.h", "w");
#endif
 if (labfile == NULL) {
#ifdef MSPAC
   fprintf(stderr, "Cannot write to mspac-lab.h\n"); exit(1);
#endif
#ifdef BERZERK
   fprintf(stderr, "Cannot write to berzerk-lab.h\n"); exit(1);
#endif
#ifdef DKONG
   fprintf(stderr, "Cannot write to dkong-lab.h\n"); exit(1);
#endif
 }
 for (pc = 0; pc < 0x10000; pc++) {
   if (lab[pc] == 2) fprintf(labfile, "&&L%04x,\n", pc); else fprintf(labfile, "&&NotSet,\n");
 }
 fclose(labfile);
}
 //free (filebuf);
 return 0;
}
