Disclaimer: This information is provided as is. There may be errors in this information. You may use this information only if you agree that Minimalist / Coinop.org, its employees, and noted authors will never be held responsible for any damage, injury, death, mayhem, etc. caused by errors in the information. When working with high voltage, never work alone and always follow safety precautions.

Document Title: [mathdis.html (html file)]

Atari mathbox microcode disassembler
/*
 * mathdis.c: Atari math box microcode disassembler for Red Baron,
 *            Battlezone, and Tempest
 *
 * Copyright 1992, 1993, 1997 Eric Smith
 *
 * Permission is granted to reproduce and distribute copies of this program
 * for noncommercial use, provided the copyright notice is not altered.
 * This software is provided on an "AS-IS" basis, with no warranty.
 *
 * The input file should be a series of 256 lines each containing the
 * address and data (in hexadecimal, separated by whitespace) for one
 * microcode ROM word.  For instance: "000  001700"
 *
 * To have any hope of understanding the disassembly, you'd better have the
 * math box schematics, a 2901 data sheet, and a lot of patience.
 *
 * $Header: /usr2/eric/vg/atari/mathbox/RCS/mathdis.c,v 1.5 1997/01/12 03:40:05 eric Exp eric $
 */

#include 
#include 

#define I_MAX 256

unsigned long instruction [I_MAX];
int entry [I_MAX];

char *progname;

void print_usage (FILE *f)
{
  fprintf (f, "Usage: %s [objectfile [listingfile]]\n", progname);
}

void fatal (int retval, char *fmt, ...)
{
  va_list ap;

  if (retval == 1)
    print_usage (stderr);
  else
    {
      fprintf (stderr, "%s: ", progname);
      va_start (ap, fmt);
      vfprintf (stderr, fmt, ap);
      va_end (ap);
    }
  exit (retval);
}

#define BUFSIZE 80

void read_inst (FILE *f)
{
  int addr;
  int addr2;
  unsigned long val;
  char buffer [BUFSIZE];

  for (addr = 0; addr < I_MAX; addr++)
    entry [addr] = -1;

  addr = 0;
  while (addr < I_MAX)
    {
      if (fgets (buffer, BUFSIZE, f) == NULL)
	fatal (2, "error reading object file\n");
      if (strncmp (buffer, "Entry", 5) == 0)
	{
	  sscanf (buffer + 6, "%x", & addr2);
	  entry [addr] = addr2;
	  continue;
	}
      if (strspn (buffer, "0123456789abcdef") != 3)
	continue;
      sscanf (buffer, "%x %x", & addr2, & val);
      if (addr2 != addr)
	fatal (3, "expected addr %02x, got %02x\n", addr, addr2);
      instruction [addr++] = val;
    }
}

void dis_fcn (FILE *file, int f, int s, int a, int b, int c)
{
  static char *pc [2] = { "", " + 1" };
  static char *mc [2] = { " - 1", "" };

  switch ((f << 3) | s)
    {
    case 000: fprintf (file, "R%x + q%s", a, pc [c]);      break;
    case 001: fprintf (file, "R%x + R%x%s", a, b, pc [c]); break;
    case 002: fprintf (file, "q%s", pc [c]);               break;
    case 003: fprintf (file, "R%x%s", b, pc [c]);          break;
    case 004: fprintf (file, "R%x%s", a, pc [c]);          break;
    case 005: fprintf (file, "d + R%x%s", a, pc [c]);      break;
    case 006: fprintf (file, "d + q%s", pc [c]);           break;
    case 007: fprintf (file, "d%s", pc [c]);               break;

    case 010: fprintf (file, "q - R%x%s", a, mc [c]);      break;
    case 011: fprintf (file, "R%x - R%x%s", b, a, mc [c]); break;
    case 012: fprintf (file, "q%s", mc [c]);               break;
    case 013: fprintf (file, "R%x%s", b, mc [c]);          break;
    case 014: fprintf (file, "R%x%s", a, mc [c]);          break;
    case 015: fprintf (file, "R%x - d%s", a, mc [c]);      break;
    case 016: fprintf (file, "q - d%s", mc [c]);           break;
    case 017: fprintf (file, "-d%s", mc [c]);              break;

    case 020: fprintf (file, "R%x - q%s", a, mc [c]);      break;
    case 021: fprintf (file, "R%x - R%x%s", a, b, mc [c]); break;
    case 022: fprintf (file, "-q%s", mc [c]);              break;
    case 023: fprintf (file, "-R%x%s", b, mc [c]);         break;
    case 024: fprintf (file, "-R%x%s", a, mc [c]);         break;
    case 025: fprintf (file, "d - R%x%s", a, mc [c]);      break;
    case 026: fprintf (file, "d - q%s", mc [c]);           break;
    case 027: fprintf (file, "d%s", mc [c]);               break;

    case 030: fprintf (file, "R%x | q", a);           break;
    case 031: fprintf (file, "R%x | R%x", a, b);      break;
    case 032: fprintf (file, "q");                    break;
    case 033: fprintf (file, "R%x", b);               break;
    case 034: fprintf (file, "R%x", a);               break;
    case 035: fprintf (file, "d | R%x", a);           break;
    case 036: fprintf (file, "d | q");                break;
    case 037: fprintf (file, "d");                    break;

    case 040: fprintf (file, "R%x & q", a);           break;
    case 041: fprintf (file, "R%x & R%x", a, b);      break;
    case 042: fprintf (file, "0");                    break;
    case 043: fprintf (file, "0");                    break;
    case 044: fprintf (file, "0");                    break;
    case 045: fprintf (file, "d & R%x", a);           break;
    case 046: fprintf (file, "d & q");                break;
    case 047: fprintf (file, "0");                    break;

    case 050: fprintf (file, "!R%x & q", a);          break;
    case 051: fprintf (file, "!R%x & R%x", a, b);     break;
    case 052: fprintf (file, "q");                    break;
    case 053: fprintf (file, "R%x", b);               break;
    case 054: fprintf (file, "R%x", a);               break;
    case 055: fprintf (file, "!d & R%x", a);          break;
    case 056: fprintf (file, "!d & q");               break;
    case 057: fprintf (file, "0");                    break;

    case 060: fprintf (file, "R%x ^ q", a);           break;
    case 061: fprintf (file, "R%x ^ R%x", a, b);      break;
    case 062: fprintf (file, "q");                    break;
    case 063: fprintf (file, "R%x", b);               break;
    case 064: fprintf (file, "R%x", a);               break;
    case 065: fprintf (file, "d ^ R%x", a);           break;
    case 066: fprintf (file, "d ^ q");                break;
    case 067: fprintf (file, "d");                    break;

    case 070: fprintf (file, "!R%x ^ q", a);          break;
    case 071: fprintf (file, "!R%x ^ R%x", a, b);     break;
    case 072: fprintf (file, "!q");                   break;
    case 073: fprintf (file, "!R%x", b);              break;
    case 074: fprintf (file, "!R%x", a);              break;
    case 075: fprintf (file, "!d & R%x", a);          break;
    case 076: fprintf (file, "!d & q");               break;
    case 077: fprintf (file, "!d");                   break;
    }
}

void disassemble_inst (FILE *file, unsigned long inst, int *eos)
{
  int f, sh, sl, d, a, b, c, m, l, s, h, j, jmp_addr, show_y;

  a = (inst >> 20) & 0x0f;
  b = (inst >> 16) & 0x0f;

  f = (inst >> 8) & 0x07;
  
  sh = (inst >> 12) & 0x0b;
  if (sh > 7)
    sh -= 4;
  sl = (inst >> 12) & 0x07;

  d = (inst >> 4) & 0x07;

  h = inst & 0x000800;
  l = inst & 0x000080;
  s = inst & 0x000008;
  j = inst & 0x000004;
  m = inst & 0x000002;
  c = inst & 0x000001;

  *eos = h || (j && !s);

  show_y = h || (j && s);

  fprintf (file, h ? "H" : " ");
  fprintf (file, s ? "S" : " ");
  fprintf (file, l ? "L" : " ");

  if (l)
    jmp_addr = inst >> 16;

  if (j)
    {
      if (s)
	fprintf (file, " (->%03x) ", jmp_addr);
      else
	fprintf (file, "  ->%03x  ", jmp_addr);
    }
  else
    fprintf (file, "         ");

  if ((inst & 0xfffb) == 0x0090)
    fprintf (file, "--load addr--");
  else
    {
      if (show_y)
	switch (d)
	  {
	  case 0: fprintf (file, "y = q = ("); break;
	  case 1: fprintf (file, "y = ("); break;
	  case 2: fprintf (file, "y = R%x, R%x = (", a, b); break;
	  case 3: fprintf (file, "y = R%x = (", b); break;
	  case 4: fprintf (file, "q = 1/2 * q, R%x = 1/2 * (y = ", b); break;
	  case 5: fprintf (file, "R%x = 1/2 * (y = ", b); break;
	  case 6: fprintf (file, "q = 2 * q, R%x = 2 * (y = ", b); break;
	  case 7: fprintf (file, "R%x = 2 * (y = ", b); break;
	  }
      else
	switch (d)
	  {
	  case 0: fprintf (file, "q = ("); break;
	  case 1: fprintf (file, "y = ("); break;
	  case 2: fprintf (file, "R%x = (", b); break;
	  case 3: fprintf (file, "R%x = (", b); break;
	  case 4: fprintf (file, "q = 1/2 * q, R%x = 1/2 * (", b); break;
	  case 5: fprintf (file, "R%x = 1/2 * (", b); break;
	  case 6: fprintf (file, "q = 2 * q, R%x = 2 * (", b); break;
	  case 7: fprintf (file, "R%x = 2 * (", b); break;
	  }

      dis_fcn (file, f, sh, a, b, c);

      if (sh != sl)
	{
	  fprintf (file, ", ");
	  dis_fcn (file, f, sl, a, b, c);
	}

      if (m)
	{
	  fprintf (file, " ? ");
	  dis_fcn (file, f, sh ^ 2, a, b, c);
	  if (sh != sl)
	    {
	      fprintf (file, ", ");
	      dis_fcn (file, f, sl ^ 2, a, b, c);
	    }
	}

      fprintf (file, ") ");
    }
}

void disassemble_all (FILE *f)
{
  int addr;
  int eos;

  fprintf (f, "                          jump\n"
              "entry  addr   hex    hsl  addr   function\n"
              "-----  ----  ------  ---  -----  ---------------------------------\n");

  for (addr = 0; addr < I_MAX; addr++)
    {
      if (entry [addr] >= 0)
	fprintf (f, "%03x->  ", entry [addr]);
      else
	fprintf (f, "       ");

      fprintf (f, "%03x:  %06x  ", addr, instruction [addr]);
      disassemble_inst (f, instruction [addr], & eos);
      fprintf (f, "\n");
      if (eos)
	fprintf (f, "\n");
    }
}

int main (int argc, char *argv[])
{
  FILE *infile = stdin;
  FILE *outfile = stdout;
  char *fn;
  progname = argv [0];
  switch (argc)
    {
    case 3:
      fn = argv [2];
      if (strcmp (fn, "-"))
	{
	  outfile = fopen (fn, "w");
	  if (! outfile)
	    fatal (2, "error opening output file\n");
	}
    case 2:
      fn = argv [1];
      if (strcmp (fn, "-"))
	{
	  infile = fopen (fn, "r");
	  if (! infile)
	    fatal (2, "error opening input file\n");
	}
    case 1:
      break;
    default:
      fatal (1, "");
    }
  read_inst (infile);
  disassemble_all (outfile);
  return (0);
}