/*
     This program has two separate but related uses.

     Firstly it is a simple disassembler and at some point we hope it will
     generate ASM listings that can be reassembled to the original binary,
     in such a way that changes to the asm (eg inserting a NOP anywhere in
     the code) will not break any code or data labels.

     Secondly, it is a static binary translator, capable of generating
     a C source file that will execute the same logic as an emulator would
     for the same bin file.

     The code is based on Sean Riddle's disassembler.  The biggest change to
     Sean's code is that we now attempt a tree-walk through the binary, starting
     at known executable entry points, augmented by hints from the user saved
     in a .dat file.  I should point out that because this code has taken such
     huge liberties with Sean's program, it has become quite messy and close
     to unmaintainable. (Apologies to Sean!)  Probably would be better to design
     a tree-walk program from scratch, specifically for that purpose.  However
     at the time of writing, the learning curve to get all the decoding correct
     was so steep that it was considered worth taking the shortcut of building
     on existing code.

     In SBT mode, identified code is passed to 6809.c ( http://gtoal.com/vectrex/6809sbt/6809.c.html )
     to be converted to C.  6809.c only handles one opcode at a time in order
     to keep its code simple and separate from this.

     What is *not* yet done is integration with an emulator, which would help
     significantly in determining what is code and what is data, and the addresses
     and types of data structures embedded in the binary.  These can't always 
     be determined automatically but they can be guessed at better than this
     code currently does.  Or more accurately, doesn't.

     GT.  2020/03/12
 */

/*
   TO DO: 
   Embed default DP for vectrex, set DP when OS call made to set DP
   Get document that lists what registers are preserved vs trashed
   when calling vectrex BIOS functions, and tweak JSR def/use values
   so that registers are not forced to have values if they are not
   used in a call but are trashed by that call.
   Pick up .dat file automatically from binary file name less extension.
   Detect negative hex constants and represent them better in the
   generated disassembly text.  Current output is not wrong, just
   a little verbose, eg $fffe,X should be -2,X
*/

// disasm can be called in two contexts - where it is known that the code
// is valid, and where it is examining unknown code.  We want the former
// to add symbolic labels when it sees a fixed address being used as an
// operand to particular instructions (eg JMP $1234 or LDA $1234,X etc)
// - but not if it is a tentative decode.  Not yet supported.

// dont follow addresses that are outside the cartridge

// cache DP

// print DP accesses using '>' notation

// create 'setdp' instruction for config file in case DP_to_?? auto detection fails
// highlight code with DP in operands

// fill in holes after tree-walking *as comments* if plausibly opcodes

// - do above PER BYTE to catch offset sequences

// web interface? click on commented opcode to decode from that point

// remainder is data.  determine data types if possible, use config file for rest

// add --vectrex flag, adds bios vars, handles rom header (bios config separate from rom config)

// final display pass, make sure no gaps

// warn if overlapping opcode and operands

// where code is currently printed, extract details and save
// in an array instead.  At that point set F_OPCODE and F_OPERAND

// have separate types F_TENTATIVE_OPCODE and F_TENTATIVE_OPERAND for
// use after definitive scan is complete?

/* 6809dasm.c - a 6809 opcode disassembler */
/* Version 1.6 27-DEC-95 */
/* Copyright  1995 Sean Riddle */

/* thanks to Franklin Bowen for bug fixes, ideas */

/* Freely distributable on any medium given all copyrights are retained */
/* by the author and no charge greater than $7.00 is made for obtaining */
/* this software */

/* Please send all bug reports, update ideas and data files to: */
/* seanriddle <at> airosurf <dot> com */

/* latest version at: */
/* http://www.seanriddle.com */

/* the data files must be kept compatible across systems! */

/* usage: 6809dasm <file> [<data file>] */
/* output to stdout, so use redirection */

/* The optional data file contains 7 types of lines: */
/* o Remarks - these are lines beginning with a semi-colon (;) */
/*   they are completely ignored. */
/* o 1 ORG line - gives the origin of the code; this is the starting */
/*   address to be used for the disassembly. */
/* o COMMENT lines - used to add comments to the end of lines of the */
/*   disassembly. */

// NOTE: comments from the config file are not currently making it into the listing.

/* o COMMENTLINE lines - provide full-line comments to be included before */
/*   a given address in the disassembly. */
/* o DATA lines - mark sections as data.  These sections will not be */
/*   disassembled, but dumped as hex data instead. */
/* o ASCII lines - mark sections as text.  These sections will not be */
/*   disassembled, but printed as text instead. */
/* o WTEXT lines - interprets section as text encoded as in Joust, */
/*   Bubbles, Sinistar (0x0=0,...,0xa=space,0xb=A,...,0x24=Z,...,0x32=:*/
/* See sample data files (*.dat) for examples. */

// Additions:
// * CODE lines - safe locations to start a tree walk from
// * SETDP lines - hints for expanding direct page accesses to full addresses

/* current limitations: */
/* o number of LABEL, DATA/ASCII, COMMENT and COMMENTLINE lines determined */
/*   at compile-time - see MAXLABEL, MAXDATA, MAXCOMMENT and MAXCOMMLINE */
/* o all DATA/ASCII lines in data file must be sorted in ascending */
/*   address order */
/* o ditto for COMMENT and COMMENTLINE lines */
/* o if a DATA/ASCII area is preceded by what 6809dasm thinks is code */
/*   that continues into the DATA/ASCII area, the data will not be marked */
/*   as such, and an error will be printed.  If this is the case, mark the */
/*   line before the data as data also. */

/* to do: */
/* o sort comment, ascii, data lines */
/* o look at JMP and JSR addresses- set to code unless overridden */
/*   in data file */
/* o perhaps a 'scan' that creates a first-guess .dat file? */
/*   generate dummy labels, mark code, find ASCII, etc. */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>

#include "6809.h"
#include "6809dasm.h"

//extern unsigned char *memory;
extern void flush(long regs);

#define TRUE (1==1)
#define FALSE (!TRUE)
typedef short BOOL;             /* boolean quantity */
typedef unsigned char UBYTE;    /* unsigned 8-bit quantity */

/* array sizes for labels, DATA/ASCII definitions and COMMENT/COMMENTLINE */
#define MAXLABEL 0x10000
#define MAXDATA 0x10000         /* both DATA and ASCII lines */
#define MAXCOMMENT 0x10000
#define MAXCOMMLINE 0x10000
// queue of recursive calls for branch destinations
#define MAXQUEUE 0x10000

int next_queue_item = 0;        // exclusive
int queue[MAXQUEUE];

#define MAXSEED 5000
int next_seed = 0;
int seed[MAXSEED];

unsigned int F_[0x10000];

//#define F_VALID_DECODE 1        // Valid instruction
//#define F_INVALID_DECODE 2      // shouldn't get any of these during initial scan from known starting point
//#define F_VISITED 4
//#define F_LABEL 8               // this instruction should have a label before it
//#define F_ENDSECTION 16
//#define F_NEED_DECODE 32        // print something whether code or data
//#define F_OUTSIDE_FILE 64       // exploration stopper
//#define F_DATA 128              // not code

int DP[0x10000];                // inferred value of DP at this opcode

int codesize[0x10000];          // how many bytes this opcode and operands take up

char *hex[0x10000];             // the disassembly, for putting back in order
char *decode[0x10000];          // the disassembly, for putting back in order
char *comment[0x10000];         // ditto

/* output listing spacing */
#define TABOPNAME 22
#define TABOPERAND 28
#define TABCOMM 43

#define OPNAMETAB (TABOPNAME-1)
#define OPERANDTAB (TABOPERAND-1)
#define COMMTAB (TABCOMM-1)

typedef struct {                /* opcode structure */
  UBYTE opcode;                 /* 8-bit opcode value */
  UBYTE numoperands;
  char name[6];                 /* opcode name */
  UBYTE mode;                   /* addressing mode */
  UBYTE numcycles;              /* number of cycles - not used */
} opcodeinfo;

/* 6809 ADDRESSING MODES */
#define INH 0
#define DIR 1
#define IND 2
#define REL 3
#define EXT 4
#define IMM 5
#define LREL 6
#define PG2 7                   /* PAGE SWITCHES - Page 2 */
#define PG3 8                   /* Page 3 */

/* number of opcodes in each page */
#define NUMPG1OPS 223
#define NUMPG2OPS 38
#define NUMPG3OPS 9

int numops[3] = {
  NUMPG1OPS, NUMPG2OPS, NUMPG3OPS,
};

char modenames[9][14] = {
  "inherent",  "direct",  "indexed",  "relative",  "extended",  "immediate",  "long relative",  "page 2",  "page 3",
};

opcodeinfo pg1opcodes[NUMPG1OPS] = {    /* page 1 ops */
  {0, 1, "NEG", DIR, 6},  {3, 1, "COM", DIR, 6},  {4, 1, "LSR", DIR, 6},  {6, 1, "ROR", DIR, 6},
  {7, 1, "ASR", DIR, 6},  {8, 1, "ASL", DIR, 6},  {9, 1, "ROL", DIR, 6},  {10, 1, "DEC", DIR, 6},
  {12, 1, "INC", DIR, 6},  {13, 1, "TST", DIR, 6},  {14, 1, "JMP", DIR, 3},  {15, 1, "CLR", DIR, 6},

  {16, 1, "page2", PG2, 0},  {17, 1, "page3", PG3, 0},  {18, 0, "NOP", INH, 2},  {19, 0, "SYNC", INH, 4},
  {22, 2, "LBRA", LREL, 5},  {23, 2, "LBSR", LREL, 9},  {25, 0, "DAA", INH, 2},  {26, 1, "ORCC", IMM, 3},
  {28, 1, "ANDCC", IMM, 3},  {29, 0, "SEX", INH, 2},  {30, 1, "EXG", IMM, 8},  {31, 1, "TFR", IMM, 6},

  {32, 1, "BRA", REL, 3},  {33, 1, "BRN", REL, 3},  {34, 1, "BHI", REL, 3},  {35, 1, "BLS", REL, 3},
  {36, 1, "BCC", REL, 3},  {37, 1, "BCS", REL, 3},  {38, 1, "BNE", REL, 3},  {39, 1, "BEQ", REL, 3},
  {40, 1, "BVC", REL, 3},  {41, 1, "BVS", REL, 3},  {42, 1, "BPL", REL, 3},  {43, 1, "BMI", REL, 3},
  {44, 1, "BGE", REL, 3},  {45, 1, "BLT", REL, 3},  {46, 1, "BGT", REL, 3},  {47, 1, "BLE", REL, 3},

  {48, 1, "LEAX", IND, 2},  {49, 1, "LEAY", IND, 2},  {50, 1, "LEAS", IND, 2},  {51, 1, "LEAU", IND, 2},
  {52, 1, "PSHS", INH, 5},  {53, 1, "PULS", INH, 5},  {54, 1, "PSHU", INH, 5},  {55, 1, "PULU", INH, 5},
  {57, 0, "RTS", INH, 5},  {58, 0, "ABX", INH, 3},  {59, 0, "RTI", INH, 6},  {60, 1, "CWAI", IMM, 20},
  {61, 0, "MUL", INH, 11},  {63, 0, "SWI", INH, 19},

  {64, 0, "NEGA", INH, 2},  {67, 0, "COMA", INH, 2},  {68, 0, "LSRA", INH, 2},  {70, 0, "RORA", INH, 2},
  {71, 0, "ASRA", INH, 2},  {72, 0, "ASLA", INH, 2},  {73, 0, "ROLA", INH, 2},  {74, 0, "DECA", INH, 2},
  {76, 0, "INCA", INH, 2},  {77, 0, "TSTA", INH, 2},

  {79, 0, "CLRA", INH, 2},  {80, 0, "NEGB", INH, 2},  {83, 0, "COMB", INH, 2},  {84, 0, "LSRB", INH, 2},
  {86, 0, "RORB", INH, 2},  {87, 0, "ASRB", INH, 2},  {88, 0, "ASLB", INH, 2},  {89, 0, "ROLB", INH, 2},
  {90, 0, "DECB", INH, 2},  {92, 0, "INCB", INH, 2},  {93, 0, "TSTB", INH, 2},  {95, 0, "CLRB", INH, 2},

  {96, 1, "NEG", IND, 6},  {99, 1, "COM", IND, 6},  {100, 1, "LSR", IND, 6},  {102, 1, "ROR", IND, 6},
  {103, 1, "ASR", IND, 6},  {104, 1, "ASL", IND, 6},  {105, 1, "ROL", IND, 6},  {106, 1, "DEC", IND, 6},
  {108, 1, "INC", IND, 6},  {109, 1, "TST", IND, 6},  {110, 1, "JMP", IND, 3},  {111, 1, "CLR", IND, 6},

  {112, 2, "NEG", EXT, 7},  {115, 2, "COM", EXT, 7},  {116, 2, "LSR", EXT, 7},  {118, 2, "ROR", EXT, 7},
  {119, 2, "ASR", EXT, 7},  {120, 2, "ASL", EXT, 7},  {121, 2, "ROL", EXT, 7},  {122, 2, "DEC", EXT, 7},
  {124, 2, "INC", EXT, 7},  {125, 2, "TST", EXT, 7},  {126, 2, "JMP", EXT, 4},  {127, 2, "CLR", EXT, 7},

  {128, 1, "SUBA", IMM, 2},  {129, 1, "CMPA", IMM, 2},  {130, 1, "SBCA", IMM, 2},  {131, 2, "SUBD", IMM, 4},
  {132, 1, "ANDA", IMM, 2},  {133, 1, "BITA", IMM, 2},  {134, 1, "LDA", IMM, 2},  {136, 1, "EORA", IMM, 2},
  {137, 1, "ADCA", IMM, 2},  {138, 1, "ORA", IMM, 2},  {139, 1, "ADDA", IMM, 2},  {140, 2, "CMPX", IMM, 4},
  {141, 1, "BSR", REL, 7},  {142, 2, "LDX", IMM, 3},

  {144, 1, "SUBA", DIR, 4},  {145, 1, "CMPA", DIR, 4},  {146, 1, "SBCA", DIR, 4},  {147, 1, "SUBD", DIR, 6},
  {148, 1, "ANDA", DIR, 4},  {149, 1, "BITA", DIR, 4},  {150, 1, "LDA", DIR, 4},  {151, 1, "STA", DIR, 4},
  {152, 1, "EORA", DIR, 4},  {153, 1, "ADCA", DIR, 4},  {154, 1, "ORA", DIR, 4},  {155, 1, "ADDA", DIR, 4},
  {156, 1, "CPX", DIR, 6},  {157, 1, "JSR", DIR, 7},  {158, 1, "LDX", DIR, 5},  {159, 1, "STX", DIR, 5},

  {160, 1, "SUBA", IND, 4},  {161, 1, "CMPA", IND, 4},  {162, 1, "SBCA", IND, 4},  {163, 1, "SUBD", IND, 6},
  {164, 1, "ANDA", IND, 4},  {165, 1, "BITA", IND, 4},  {166, 1, "LDA", IND, 4},  {167, 1, "STA", IND, 4},
  {168, 1, "EORA", IND, 4},  {169, 1, "ADCA", IND, 4},  {170, 1, "ORA", IND, 4},  {171, 1, "ADDA", IND, 4},
  {172, 1, "CPX", IND, 6},  {173, 1, "JSR", IND, 7},  {174, 1, "LDX", IND, 5},  {175, 1, "STX", IND, 5},

  {176, 2, "SUBA", EXT, 5},  {177, 2, "CMPA", EXT, 5},  {178, 2, "SBCA", EXT, 5},  {179, 2, "SUBD", EXT, 7},
  {180, 2, "ANDA", EXT, 5},  {181, 2, "BITA", EXT, 5},  {182, 2, "LDA", EXT, 5},  {183, 2, "STA", EXT, 5},
  {184, 2, "EORA", EXT, 5},  {185, 2, "ADCA", EXT, 5},  {186, 2, "ORA", EXT, 5},  {187, 2, "ADDA", EXT, 5},
  {188, 2, "CPX", EXT, 7},  {189, 2, "JSR", EXT, 8},  {190, 2, "LDX", EXT, 6},  {191, 2, "STX", EXT, 6},
  
  {192, 1, "SUBB", IMM, 2},  {193, 1, "CMPB", IMM, 2},  {194, 1, "SBCB", IMM, 2},  {195, 2, "ADDD", IMM, 4},
  {196, 1, "ANDB", IMM, 2},  {197, 1, "BITB", IMM, 2},  {198, 1, "LDB", IMM, 2},  {200, 1, "EORB", IMM, 2},
  {201, 1, "ADCB", IMM, 2},  {202, 1, "ORB", IMM, 2},  {203, 1, "ADDB", IMM, 2},  {204, 2, "LDD", IMM, 3},
  {206, 2, "LDU", IMM, 3},

  {208, 1, "SUBB", DIR, 4},  {209, 1, "CMPB", DIR, 4},  {210, 1, "SBCB", DIR, 4},  {211, 1, "ADDD", DIR, 6},
  {212, 1, "ANDB", DIR, 4},  {213, 1, "BITB", DIR, 4},  {214, 1, "LDB", DIR, 4},  {215, 1, "STB", DIR, 4},
  {216, 1, "EORB", DIR, 4},  {217, 1, "ADCB", DIR, 4},  {218, 1, "ORB", DIR, 4},  {219, 1, "ADDB", DIR, 4},
  {220, 1, "LDD", DIR, 5},  {221, 1, "STD", DIR, 5},  {222, 1, "LDU", DIR, 5},  {223, 1, "STU", DIR, 5},

  {224, 1, "SUBB", IND, 4},  {225, 1, "CMPB", IND, 4},  {226, 1, "SBCB", IND, 4},  {227, 1, "ADDD", IND, 6},
  {228, 1, "ANDB", IND, 4},  {229, 1, "BITB", IND, 4},  {230, 1, "LDB", IND, 4},  {231, 1, "STB", IND, 4},
  {232, 1, "EORB", IND, 4},  {233, 1, "ADCB", IND, 4},  {234, 1, "ORB", IND, 4},  {235, 1, "ADDB", IND, 4},
  {236, 1, "LDD", IND, 5},  {237, 1, "STD", IND, 5},  {238, 1, "LDU", IND, 5},  {239, 1, "STU", IND, 5},

  {240, 2, "SUBB", EXT, 5},  {241, 2, "CMPB", EXT, 5},  {242, 2, "SBCB", EXT, 5},  {243, 2, "ADDD", EXT, 7},
  {244, 2, "ANDB", EXT, 5},  {245, 2, "BITB", EXT, 5},  {246, 2, "LDB", EXT, 5},  {247, 2, "STB", EXT, 5},
  {248, 2, "EORB", EXT, 5},  {249, 2, "ADCB", EXT, 5},  {250, 2, "ORB", EXT, 5},  {251, 2, "ADDB", EXT, 5},
  {252, 2, "LDD", EXT, 6},  {253, 2, "STD", EXT, 6},  {254, 2, "LDU", EXT, 6},  {255, 2, "STU", EXT, 6}
};

opcodeinfo pg2opcodes[NUMPG2OPS] = {    /* page 2 ops 10xx */
  {33, 3, "LBRN", LREL, 5},  {34, 3, "LBHI", LREL, 5},  {35, 3, "LBLS", LREL, 5},  {36, 3, "LBCC", LREL, 5},
  {37, 3, "LBCS", LREL, 5},  {38, 3, "LBNE", LREL, 5},  {39, 3, "LBEQ", LREL, 5},  {40, 3, "LBVC", LREL, 5},
  {41, 3, "LBVS", LREL, 5},  {42, 3, "LBPL", LREL, 5},  {43, 3, "LBMI", LREL, 5},  {44, 3, "LBGE", LREL, 5},
  {45, 3, "LBLT", LREL, 5},  {46, 3, "LBGT", LREL, 5},  {47, 3, "LBLE", LREL, 5},  {63, 1, "SWI2", INH, 20},     // 2->1 fix from Malban
  {131, 3, "CMPD", IMM, 5},  {140, 3, "CMPY", IMM, 5},  {142, 3, "LDY", IMM, 4},  {147, 2, "CMPD", DIR, 7},
  {156, 2, "CMPY", DIR, 7},  {158, 2, "LDY", DIR, 6},  {159, 2, "STY", DIR, 6},  {163, 2, "CMPD", IND, 7},
  {172, 2, "CMPY", IND, 7},  {174, 2, "LDY", IND, 6},  {175, 2, "STY", IND, 6},  {179, 3, "CMPD", EXT, 8},
  {188, 3, "CMPY", EXT, 8},  {190, 3, "LDY", EXT, 7},  {191, 3, "STY", EXT, 7},  {206, 3, "LDS", IMM, 4},
  {222, 2, "LDS", DIR, 6},  {223, 2, "STS", DIR, 6},  {238, 2, "LDS", IND, 6},  {239, 2, "STS", IND, 6},
  {254, 3, "LDS", EXT, 7},  {255, 3, "STS", EXT, 7},
};

opcodeinfo pg3opcodes[NUMPG3OPS] = {    /* page 3 ops 11xx */
  {63, 1, "SWI3", INH, 20},  {131, 3, "CMPU", IMM, 5},  {140, 3, "CMPS", IMM, 5},  {147, 2, "CMPU", DIR, 7},
  {156, 2, "CMPS", DIR, 7},  {163, 2, "CMPU", IND, 7},  {172, 2, "CMPS", IND, 7},  {179, 3, "CMPU", EXT, 8},
  {188, 3, "CMPS", EXT, 8},};

opcodeinfo *pgpointers[3] = {
  pg1opcodes, pg2opcodes, pg3opcodes,
};

int count;                      /* current program counter for disasm */

/* getbyte() - get a byte from a file, and increment the byte counter */

// rom_start <= addr < rom_end is used in optimising jumps and the use of labels.
// jumps outside the current rom use PC=$FFFF; JUMP; but jumps within the same file can be
// implemented with a "goto LFFFF;"
int rom_start = 0, rom_end = 0;

unsigned char mem[0x10000];

int getbyte (int *fp) {         // file is actually in ram already
  int c;

  if ((*fp) >= rom_end)
    return -1;
  // GT: DEBUGGING: I moved count++ to after the rom_end test rather than before.
  count++;                      // watch out for 0/1 base for first byte in display code...
  c = mem[(*fp)++];
  return (c & 255);
}

int getword (int *fp) {
  int low, high;

  high = getbyte (fp);
  low = getbyte (fp);
  return (high << 8) + low;
}

void save (char *s) {
  char *commentp;
  unsigned int addr, junk, bytes;

  // xxxx: nn nn nn nn nn OPC OPD ;comment
  if (s[20] != ' ') {
    fprintf(stderr, "%s\n                    ^\n", s);
    assert (s[20] == ' ');
  }
  s[20] = '\0';
  (void) sscanf (s, "%04X: ", &addr);
  decode[addr] = strdup (s + 21);
  if ((commentp = strchr (decode[addr], ';')) != NULL) {
    if (commentp > decode[addr]) {
      if (*(commentp - 1) == ' ' && *commentp == ';') {
        commentp -= 1;
        *commentp++ = '\0';
        comment[addr] = commentp;
      }
    }
  }
  s = s + 6;
  hex[addr] = strdup (s);
  for (bytes = 0; bytes < 5; bytes++) {
    if (*s == ' ')
      break;
    (void) sscanf (s, "%02X ", &junk);;
    s += 3;
  }
  codesize[addr] = bytes;
}

const char *regs[5] = { "X", "Y", "U", "S", "PC" };

const char *teregs[16] = {
  "D", "X", "Y", "U", "S", "PC",
  "inv", "inv", "A", "B", "CC",
  "DP", "inv", "inv", "inv", "inv"
};

BOOL PC = FALSE;                /* to see if a PUL instr is pulling PC */

#define LABELSIZE 40
/* label structure */
struct lastruct {
  unsigned short lab;           /* label address */
  char label[LABELSIZE];        /* label text */
}  *labarray = NULL;
int numlab = 0;                 /* number of labels defined */

char labtemp[LABELSIZE];               /* global return for checklabs() - tsk */
//GTDEBUG: char *fulladdr = "$%04hX";
char *fulladdr = "$%04X";
char *shortaddr = "$%02hX";

/* checklabs() - check the defined labels from data file */
/* substitute label for address if found */
char *checklabs (char *opname, int address, BOOL lab2, BOOL printdollar, BOOL dosmall) {
  int i;
  char *printaddr;

  address &= 0xffff;
  //GTDEBUG  if (address >= 0x3ff) fprintf(stderr, "checklabs @ %04x  F_LABEL=%s\n", address, F_[address]&F_LABEL ? "Y" : "N");
  labtemp[0] = '\0';
  if (*opname && ((address >= 256) || dosmall)) {
    // This could be better done with a lookup table of flag bits.
    if ((!strcasecmp (opname, "BRA"))
        || (!strcasecmp (opname, "BRN"))
        || (!strcasecmp (opname, "BHI"))
        || (!strcasecmp (opname, "BLS"))
        || (!strcasecmp (opname, "BCC"))
        || (!strcasecmp (opname, "BCS"))
        || (!strcasecmp (opname, "BNE"))
        || (!strcasecmp (opname, "BEQ"))
        || (!strcasecmp (opname, "BVC"))
        || (!strcasecmp (opname, "BVS"))
        || (!strcasecmp (opname, "BPL"))
        || (!strcasecmp (opname, "BMI"))
        || (!strcasecmp (opname, "BGE"))
        || (!strcasecmp (opname, "BLT"))
        || (!strcasecmp (opname, "BGT"))
        || (!strcasecmp (opname, "BLE"))
        || (!strcasecmp (opname, "BSR"))
        || (!strcasecmp (opname, "LBRA"))
        || (!strcasecmp (opname, "LBRN"))
        || (!strcasecmp (opname, "LBHI"))
        || (!strcasecmp (opname, "LBLS"))
        || (!strcasecmp (opname, "LBCC"))
        || (!strcasecmp (opname, "LBCS"))
        || (!strcasecmp (opname, "LBNE"))
        || (!strcasecmp (opname, "LBEQ"))
        || (!strcasecmp (opname, "LBVC"))
        || (!strcasecmp (opname, "LBVS"))
        || (!strcasecmp (opname, "LBPL"))
        || (!strcasecmp (opname, "LBMI"))
        || (!strcasecmp (opname, "LBGE"))
        || (!strcasecmp (opname, "LBLT"))
        || (!strcasecmp (opname, "LBGT"))
        || (!strcasecmp (opname, "LBLE"))
        || (!strcasecmp (opname, "LBSR"))
        || (!strcasecmp (opname, "JMP"))
        || (!strcasecmp (opname, "JSR"))
     ) {
      if ((next_queue_item < MAXQUEUE) && (address < 0x8000)) queue[next_queue_item++] = address;
      F_[address] |= F_LABEL;
      // TO DO: Add DP register to direct 8bit addresses
    }
    for (i = 0; i < numlab; i++)
      if (address == labarray[i].lab) {
        sprintf (labtemp, "%s", labarray[i].label);
        if (lab2) strcat (labtemp, ":\n");
        i = numlab;
      }
    printaddr = (address < 256 ? shortaddr : fulladdr);
    if (!strlen (labtemp) && !lab2) {
      if (!printdollar) printaddr++;
      sprintf (labtemp, printaddr, address);
    }
  } else if (*opname == '\0') {
    sprintf(labtemp, "L%04X", address); if (lab2) strcat (labtemp, ":\n");
    for (i = 0; i < numlab; i++)
      if (address == labarray[i].lab) {
        sprintf (labtemp, "%s", labarray[i].label);
        if (lab2) strcat (labtemp, ":\n");
        i = numlab;
      }
  }
  //GTDEBUG:  if (address >= 0x3ff) fprintf(stderr, "checklabs @ %04x -> %s\n", address, labtemp);
  return (labtemp);
}

/* printoperands() - print operands for the given opcode */
void printoperands (int current_address, int opcode, UBYTE numoperands, UBYTE * operandarray, UBYTE mode, int *fp, char *opname, char *str) {
  int i, rel, pb, offset = 0, reg, pb2;
  BOOL comma;
  char out2[80];
  int sp;

  PC = FALSE;
  if ((opcode != 0x1f) && (opcode != 0x1e)) {
    switch (mode) {             /* print before operands */
    case IMM:
      strcat (str, "#");
      break;
    case DIR:
      break;
    case EXT:
      break;
    default:
      break;
    }
  }
  switch (mode) {
  case REL:                    /* 8-bit relative */
    rel = operandarray[0];
    sprintf (out2, "%s", checklabs (opname, (short) (count + ((rel < 128) ? rel : rel - 256)), FALSE, TRUE, TRUE));
    strcat (str, out2);
    break;
  case LREL:                   /* 16-bit long relative */
    rel = (operandarray[0] << 8) + operandarray[1];
    sprintf (out2, "%s", checklabs (opname, count + ((rel < 32768) ? rel : rel - 65536), FALSE, TRUE, TRUE));
    strcat (str, out2);
    break;
  case IND:                    /* indexed- many flavors */
    pb = operandarray[0];
    reg = (pb >> 5) & 0x3;
    // READ THIS CODE AND USE HERE!
    // http://vectrex.malban.de/preliminary/eb765dd8.html

    // filter out not allowed combinations
    // 1xxx 0111
    // 1xxx 1010
    // 1xxx 1110
    if (((pb & 0x8f) == 0x87) || ((pb & 0x8f) == 0x8a) || ((pb & 0x8f) == 0x8e)) {
      // return incorrectDisassembleFoundAt(currentPC, "Illegal postbyte value for indexed addressing, bit combination of 4 lower bits.");
      F_[current_address] |= F_INVALID_DECODE;
    }
    // filter out not allowed combinations
    // 1xx1 0010
    // 1xx1 0000
    if (((pb & 0x9f) == 0x92) || ((pb & 0x9f) == 0x90)) {
      // return incorrectDisassembleFoundAt(currentPC, "Illegal postbyte value ,-R or ,R+ not allowed for indirect indexed addressing.");
      F_[current_address] |= F_INVALID_DECODE;
    }
    // filter out not allowed combinations
    // 1xx0 1111
    if (((pb & 0x9f) == 0x8f)) {
      // return incorrectDisassembleFoundAt(currentPC, "Illegal postbyte value 16 bit extended not allowed in indexed (non indirect) addressing.");
      F_[current_address] |= F_INVALID_DECODE;
    }
    // filter out not allowed combinations
    // 1011 1111
    // 1101 1111
    // 1111 1111
    if (((pb & 0xff) == 0xbf) || ((pb & 0xff) == 0xdf) || ((pb & 0xff) == 0xff)) {
      // return incorrectDisassembleFoundAt(currentPC, "Illegal postbyte value 16 bit indirect indexed addressing expects bits 5 and 6 to be 0");
      F_[current_address] |= F_INVALID_DECODE;
    }
    // 1xxx 1100
    // 1xxx 1101
    if (((pb & 0x8f) == 0x8d) || ((pb & 0x8f) == 0x8c)) {
      // reg == PC!
      reg = 4;

      if (((pb >> 4) & 0x6) != 0) {
        /* 
           1XX? ???? X bits can be anything, asmj converts "sta <$30,pc" to "ec 8c 30" which is correct but "ec ec 30" but "ec dc 30" but "ec bc 30" are also correct, but only
           the first 100% ressembles old binary therefor the below three variants must be converted to DB, with comment not to convert to code! this is true for both 16 bit or 8
           bit variant! */
        // return incorrectDisassembleFoundAt(currentPC, "Ambiguous pc index addressing, postbytes bit 5 and 6 are non zero (assi generates 0).");
        F_[current_address] |= F_INVALID_DECODE; // ... Maybe?
      }
    }

    pb2 = pb & 0x8f;
    if ((pb2 == 0x88) || (pb2 == 0x8c)) {       /* 8-bit offset */
      offset = getbyte (fp);
      sprintf (out2, "%02hX ", offset);
      strcat (str, out2);
      if (offset > 127)         /* convert to signed */
        offset = offset - 256;
      if (pb == 0x8c)
        reg = 4;
      for (sp = strlen (str); sp < OPNAMETAB; sp++)
        strcat (str, " ");
      sprintf (out2, "%s", opname);
      strcat (str, out2);
      for (sp = strlen (str); sp < OPERANDTAB; sp++)
        strcat (str, " ");
      if ((pb & 0x90) == 0x90)
        strcat (str, "[");
      if (pb == 0x8c)
        sprintf (out2, "%s,%s", checklabs (opname, offset, FALSE, TRUE, TRUE), regs[reg]);
      else if ((char)offset >= 0)        // cast to signed short?
        sprintf (out2, "$%02X,%s", offset, regs[reg]);
      else
        sprintf (out2, "-$%02X,%s", -(char)offset, regs[reg]);
      strcat (str, out2);
      if (pb == 0x8c) {
        sprintf (out2, " ; ($%04X)", offset + count);
        strcat (str, out2);
      }
    } else if ((pb2 == 0x89) || (pb2 == 0x8d) || (pb2 == 0x8f)) {       /* IND 16-bit */
      offset = (getbyte (fp) << 8);
      sprintf (out2, "%02X ", offset >> 8);
      strcat (str, out2);
      offset += getbyte (fp);
      sprintf (out2, "%02X ", offset & 0xff);
      strcat (str, out2);
      if ((pb != 0x8f) && (offset > 32767))
        offset = offset - 65536;
      offset &= 0xffff;
      if (pb == 0x8d)
        reg = 4;
      for (sp = strlen (str); sp < OPNAMETAB; sp++)
        strcat (str, " ");
      sprintf (out2, "%s", opname);
      strcat (str, out2);
      for (sp = strlen (str); sp < OPERANDTAB; sp++)
        strcat (str, " ");
      if ((pb & 0x90) == 0x90)
        strcat (str, "[");
      if (pb == 0x9f)
        sprintf (out2, "%s", checklabs (opname, offset, FALSE, TRUE, TRUE));
      else if (pb == 0x8d)
        sprintf (out2, "%s,%s", checklabs (opname, offset, FALSE, TRUE, TRUE), regs[reg]);
      else if ((short)offset >= 0)
        sprintf (out2, "$%04X,%s", offset, regs[reg]);
      else
        sprintf (out2, "-$%04X,%s", -(short)offset, regs[reg]);   // WAIT A MINUTE!  CHECK THIS!  Maybe -offset ??? BUG FIX NEEDED - TEST FIRST...
      strcat (str, out2);
      if (pb == 0x8d) {
        sprintf (out2, " ; ($%04X)", offset + count);
        strcat (str, out2);
      }
    } else if (pb & 0x80) {
      for (sp = strlen (str); sp < OPNAMETAB; sp++)
        strcat (str, " ");
      sprintf (out2, "%s", opname);
      strcat (str, out2);
      for (sp = strlen (str); sp < OPERANDTAB; sp++)
        strcat (str, " ");
      if ((pb & 0x90) == 0x90)
        strcat (str, "[");
      if ((pb & 0x8f) == 0x80) {
        sprintf (out2, ",%s+", regs[reg]);
        strcat (str, out2);
      } else if ((pb & 0x8f) == 0x81) {
        sprintf (out2, ",%s++", regs[reg]);
        strcat (str, out2);
      } else if ((pb & 0x8f) == 0x82) {
        sprintf (out2, ",-%s", regs[reg]);
        strcat (str, out2);
      } else if ((pb & 0x8f) == 0x83) {
        sprintf (out2, ",--%s", regs[reg]);
        strcat (str, out2);
      } else if ((pb & 0x8f) == 0x84) {
        sprintf (out2, ",%s", regs[reg]);
        strcat (str, out2);
      } else if ((pb & 0x8f) == 0x85) {
        sprintf (out2, "B,%s", regs[reg]);
        strcat (str, out2);
      } else if ((pb & 0x8f) == 0x86) {
        sprintf (out2, "A,%s", regs[reg]);
        strcat (str, out2);
      } else if ((pb & 0x8f) == 0x8b) {
        sprintf (out2, "D,%s", regs[reg]);
        strcat (str, out2);
      }
    } else {                    /* IND 5-bit offset */
      offset = pb & 0x1f;
      if (offset > 15) offset = offset - 32;
      for (sp = strlen (str); sp < OPNAMETAB; sp++) strcat (str, " ");
      sprintf (out2, "%s", opname);
      strcat (str, out2);
      for (sp = strlen (str); sp < OPERANDTAB; sp++) strcat (str, " ");
      {        // LEAX $FFFF,Y GT DEBUG
        char *s = checklabs (opname, offset, FALSE, TRUE, TRUE);
        char buff1[16], buff2[16];
        sprintf(buff1, "$%02X", (offset&0xff));
        sprintf(buff2, "$%04X", (offset&0xffff));
        //fprintf(stdout, "// %s %s %s\n", s, buff1, buff2);
        if (((short)offset < 0) && (strcmp(s, buff1) == 0 || strcmp(s, buff2) == 0)) {
          sprintf (out2, "-%d,%s", -(short)offset, regs[reg]);
        } else {
          sprintf (out2, "%s,%s", s, regs[reg]);
        }
        }
      strcat (str, out2);
    }
    if ((pb & 0x90) == 0x90) strcat (str, "]");
    break;
  default:
    if ((opcode == 0x1f) || (opcode == 0x1e)) { /* TFR/EXG */
      sprintf (out2, "%s,%s", teregs[(operandarray[0] >> 4) & 0xf], teregs[operandarray[0] & 0xf]);
      strcat (str, out2);
    } else if ((opcode == 0x34) || (opcode == 0x36)) {  /* PUSH */
      comma = FALSE;
      if (operandarray[0] & 0x80) {
        strcat (str, "PC");
        comma = TRUE;
        PC = TRUE;
      }
      if (operandarray[0] & 0x40) {
        if (comma) strcat (str, ",");
        if ((opcode == 0x34) || (opcode == 0x35))
          strcat (str, "U");
        else
          strcat (str, "S");
        comma = TRUE;
      }
      if (operandarray[0] & 0x20) {
        if (comma) strcat (str, ",");
        strcat (str, "Y");
        comma = TRUE;
      }
      if (operandarray[0] & 0x10) {
        if (comma) strcat (str, ",");
        strcat (str, "X");
        comma = TRUE;
      }
      if (operandarray[0] & 0x8) {
        if (comma) strcat (str, ",");
        strcat (str, "DP");
        comma = TRUE;
      }
      if (operandarray[0] & 0x4) {
        if (comma) strcat (str, ",");
        strcat (str, "B");
        comma = TRUE;
      }
      if (operandarray[0] & 0x2) {
        if (comma) strcat (str, ",");
        strcat (str, "A");
        comma = TRUE;
      }
      if (operandarray[0] & 0x1) {
        if (comma) strcat (str, ",");
        strcat (str, "CC");
      }
    } else if ((opcode == 0x35) || (opcode == 0x37)) {  /* PULL */
      comma = FALSE;
      if (operandarray[0] & 0x1) {
        strcat (str, "CC");
        comma = TRUE;
      }
      if (operandarray[0] & 0x2) {
        if (comma) strcat (str, ",");
        strcat (str, "A");
        comma = TRUE;
      }
      if (operandarray[0] & 0x4) {
        if (comma) strcat (str, ",");
        strcat (str, "B");
        comma = TRUE;
      }
      if (operandarray[0] & 0x8) {
        if (comma) strcat (str, ",");
        strcat (str, "DP");
        comma = TRUE;
      }
      if (operandarray[0] & 0x10) {
        if (comma) strcat (str, ",");
        strcat (str, "X");
        comma = TRUE;
      }
      if (operandarray[0] & 0x20) {
        if (comma) strcat (str, ",");
        strcat (str, "Y");
        comma = TRUE;
      }
      if (operandarray[0] & 0x40) {
        if (comma) strcat (str, ",");
        if ((opcode == 0x34) || (opcode == 0x35))
          strcat (str, "U");
        else
          strcat (str, "S");
        comma = TRUE;
      }
      if (operandarray[0] & 0x80) {
        if (comma) strcat (str, ",");
        strcat (str, "PC");
        strcat (str, " ;(PUL? PC=RTS)");
        PC = TRUE;
      }
    } else {
      /* 
         _8bitPrefix="<"; _5bitPrefix="<<"; _16bitPrefix=">"; */
      if (numoperands == 0) ;
      else if (numoperands == 2) {
        /* if (mode != IMM) strcat(str, ">"); */// 16bit prefix
        strcat (str, checklabs (opname, (operandarray[0] << 8) + operandarray[1], FALSE, TRUE, TRUE));
      } else if (numoperands == 1) {    /* ((numoperands==1)&&(mode!=IMM)) */
        // give indicate 1 operand = 8 bit
        if (mode != IMM) strcat (str, "<");    // 8bit prefix
        strcat (str, checklabs (opname, operandarray[0], FALSE, TRUE, TRUE));
      } else {
        /* if (mode != IMM) strcat(str, "<<"); */// 5bit prefix. not generally supported by assemblers.
        strcat (str, "$");
        for (i = 0; i < numoperands; i++) {
          sprintf (out2, "%02X", operandarray[i]);
          strcat (str, out2);
        }
      }
    }
    break;
  }
}

#define DATA 0                  /* type of data to display */
#define ASCII 1
#define WTEXT 2

/* DATA/ASCII structure definition */
struct dastruct {
  unsigned short start;         /* beginning address of DATA/ASCII */
  unsigned short end;           /* ending address */
  unsigned short per_line;      /* values to print on a line */
  short type;                   /* DATA or ASCII ? */
}  *dataarray = NULL;

#define COMMENTSIZE 80
/* COMMENT/COMMENTLINE structure definition */
struct castruct {
  unsigned short comline;       /* comment line address */
  char comment[COMMENTSIZE];    /* comment text */
}  *commarray = NULL, *commlinearray = NULL;

char out[512], out2[80];        /* temp string buffers */

void readdatafile (char *filename, int *org, int *numlab, int *numdata, int *numcomm, int *numcommline) {
  char line2[256];
  char *line;
  FILE *fp;
  int dataline, data, data2, per_line, i, k;

  if ((fp = fopen (filename, "r"))) {   /* read data file */
    /* fprintf(stderr, "DEBUG: reading %s\n", filename); */
    while (fgets (line2, 255, fp)) {
      while (strlen (line2) && !isprint (line2[strlen (line2) - 1]))    /* strip cr */
        line2[strlen (line2) - 1] = '\0';
      for (i = 0; i < (int) strlen (line2); i++)
        if ((line2[i] == ';') || isalpha (line2[i])) {
          line = &(line2[i]);
          i = strlen (line2);
        }
      if (!strncasecmp (line, "ORG ", 4)) {
        int neworg;
        sscanf (&line[4], "%X", &neworg);
        if ((*org != -1) && (*org != 0)) {
          if (*org != neworg) {
            fprintf (stderr, "More than one ORG line - prev was %X\n", *org);
            fprintf (stderr, "ORG set to %X\n", neworg);
          }
        }
        *org = neworg;
      } else if (!strncasecmp (line, "LABEL ", 6)) {
        if (*numlab < MAXLABEL) {
          sscanf (&line[6], "%X", &dataline);
          labarray[*numlab].lab = dataline;
          k = 6;
          while (line[k] == ' ') k++;
          while (line[k] != ' ') k++;
          while (line[k] == ' ') k++;
          strncpy (labarray[*numlab].label, &line[k], LABELSIZE);
          labarray[*numlab].label[LABELSIZE - 1] = 0;   /* just in case */

          for (i = 0; i < *numlab; i++)
            if (!strcmp (labarray[i].label, labarray[*numlab].label)) {
              /* GT: (temp removed until new DP mechanism) fprintf(stderr, "duplicate label: %s\n",labarray[i].label); */
              break;
            }
          if (i >= *numlab)
            (*numlab)++;
          //fprintf(stderr, "DEBUG!!!  Added %s %04x  Set F_[%04x] |= F_LABEL\n", labarray[(*numlab)-1].label, labarray[(*numlab)-1].lab, labarray[(*numlab)-1].lab);
          // GTDEBUG:
          F_[labarray[(*numlab)-1].lab] |= F_LABEL;
          
        } else
          fprintf (stderr, "Too many labels\n");
      } else if (!strncasecmp (line, "CODE ", 5)) {
        if (next_seed < MAXSEED) {
          sscanf (&line[5], "%X", &data);
          seed[next_seed++] = data;
          ///fprintf (stderr, "DEBUG: Adding code seed $%04x\n", data);
        } else
          fprintf (stderr, "Too many CODE lines\n");
      } else if (!strncasecmp (line, "SETDP ", 6)) {
        sscanf (&line[6], "%X", &data);
        /* fprintf(stderr, "DEBUG: Adding setdp $%04x\n", data); */
      } else if (!strncasecmp (line, "DATA ", 5)) {
        if (*numdata < MAXDATA) {
          data2 = 0;
          sscanf (&line[5], "%X-%X", &data, &data2);
          k = 5;
          while (line[k] == ' ')
            k++;
          while (line[k] != ' ')
            k++;
          while (line[k] == ' ')
            k++;
          if (k < i)
            sscanf (&(line[k]), "%d", &per_line);
          else
            per_line = 0;
          if (data2 < data)
            data2 = data;
          dataarray[*numdata].type = DATA;
          dataarray[*numdata].start = data;
          dataarray[*numdata].end = data2;
          dataarray[*numdata].per_line = per_line;
          if (((*numdata) && (dataarray[*numdata - 1].start < dataarray[*numdata].start)) || !*numdata)
            (*numdata)++;
          else
            fprintf (stderr, "'%s'\nDATA out of order\n\n", line);

          {int i; for (i = data; i <= data2; i++) F_[i] |= F_DATA; } // not to be explored as code. 

        } else
          fprintf (stderr, "Too many DATA/ASCII lines\n");
      } else if (!strncasecmp (line, "ASCII ", 6)) {
        if (*numdata < MAXDATA) {
          data2 = 0;
          per_line = 0;
          sscanf (&line[6], "%X-%X %d", &data, &data2, &per_line);
          if (data2 < data)
            data2 = data;
          dataarray[*numdata].type = ASCII;
          dataarray[*numdata].start = data;
          dataarray[*numdata].end = data2;
          dataarray[*numdata].per_line = per_line;
          if (((*numdata) && (dataarray[*numdata - 1].start < dataarray[*numdata].start)) || !*numdata)
            (*numdata)++;
          else if (*numdata)
            fprintf (stderr, "'%s'\nASCII out of order\n\n", line);
        } else
          fprintf (stderr, "Too many DATA/ASCII lines\n");
      } else if (!strncasecmp (line, "WTEXT ", 6)) {
        if (*numdata < MAXDATA) {
          data2 = 0;
          per_line = 0;
          sscanf (&line[6], "%X-%X %d", &data, &data2, &per_line);
          if (data2 < data)
            data2 = data;
          dataarray[*numdata].type = WTEXT;
          dataarray[*numdata].start = data;
          dataarray[*numdata].end = data2;
          dataarray[*numdata].per_line = per_line;
          if (((*numdata) && (dataarray[*numdata - 1].start < dataarray[*numdata].start)) || !*numdata)
            (*numdata)++;
          else if (*numdata)
            fprintf (stderr, "'%s'\nWTEXT out of order\n\n", line);
        } else
          fprintf (stderr, "Too many DATA/ASCII lines\n");
      } else if (!strncasecmp (line, "COMMENT ", 8)) {
        if (*numcomm < MAXCOMMENT) {
          sscanf (&line[8], "%X", &dataline);
          commarray[*numcomm].comline = dataline;

          k = 8;
          while (line[k] == ' ')
            k++;
          while (line[k] != ' ')
            k++;
          while (line[k] == ' ')
            k++;
          strncpy (commarray[*numcomm].comment, &line[k], COMMENTSIZE);
          commarray[*numcomm].comment[COMMENTSIZE - 1] = 0;     /* in case */

          if (((*numcomm) && (commarray[(*numcomm) - 1].comline <= commarray[*numcomm].comline)) || !*numcomm)
            (*numcomm)++;
          else
            fprintf (stderr, "'%s'\nCOMMENT out of order\n\n", line);
        } else
          fprintf (stderr, "Too many COMMENT lines\n");
      } else if (!strncasecmp (line, "COMMENTLINE ", 12)) {
        if (*numcommline < MAXCOMMLINE) {
          sscanf (&line[12], "%X", &dataline);
          commlinearray[*numcommline].comline = dataline;
          k = 12;
          while (line[k] == ' ')
            k++;
          while (line[k] != ' ')
            k++;
          while (line[k] == ' ')
            k++;
          strncpy (commlinearray[*numcommline].comment, &line[k], COMMENTSIZE);
          commlinearray[*numcommline].comment[COMMENTSIZE - 1] = 0;

          if (((*numcommline) && (commlinearray[(*numcommline) - 1].comline <= commlinearray[*numcommline].comline)) || !*numcommline)
            (*numcommline)++;
          else
            fprintf (stderr, "'%s'\nCOMMENTLINE out of order\n\n", line);
        } else
          fprintf (stderr, "Too many COMMENTLINE lines\n");
      } else if (line[0] == ';')        /* remark in data file */
        ;
      else if (strlen (line))
        fprintf (stderr, "'%s'\nError in file '%s'\n\n", line, filename);
    }
    fclose (fp);
  } else
    fprintf (stderr, "Can't open file '%s'\n", filename);
}

void docomment (int line, int *curcomm, int numcomm, int numoperands) {
  int sp;
  BOOL first_comment = TRUE;

  if (!numcomm) return;
  if (*curcomm < numcomm) {     /* see if we've passed a comment */
    while (((line - 1) > commarray[*curcomm].comline + numoperands) && (*curcomm < numcomm)) {
      // these are comments attached to data statements.  they won't be output unless there's a code line at that address.
      // fprintf (stderr, "Warning: missed a comment at %X, line=%X\n", commarray[*curcomm].comline, line);
      (*curcomm)++;
    }

    while ((((line - 1) + numoperands) >= commarray[*curcomm].comline) ||
           ((line == commarray[*curcomm].comline) && (numoperands == 1)) || (((line - 1) == commarray[*curcomm].comline) && (numoperands == 0))) {
      if (*curcomm >= numcomm) break;
      if (first_comment != TRUE) { /* GT:printf("%s\n",out); out[0]='\0'; */ }
      for (sp = strlen (out); sp < COMMTAB; sp++) strcat (out, " ");
      strcat (out, ";"); strcat (out, commarray[*curcomm].comment);
      (*curcomm)++;
      first_comment = FALSE;
    }
  }
}

void docommline (int line, int *curcommline, int numcommline) {
  BOOL didone = FALSE;

  if (numcommline > 0) {
    if (*curcommline < numcommline) {   /* see if we've passed a comment line */
      while (((line - 1) > commlinearray[*curcommline].comline) && (*curcommline < numcommline)) {
        fprintf (stderr, "Error: missed a comment line at %X, line=%X\n", commlinearray[*curcommline].comline, line);
        (*curcommline)++;
      }

      while (((line - 1) == commlinearray[*curcommline].comline) && (*curcommline < numcommline)) {
        if (!didone)
          /* GT: printf("\n") */ ;
        /* GT: printf("*** %s\n",commlinearray[*curcommline].comment) */ ;
        (*curcommline)++;
        didone = TRUE;
      }
    }
  }
}

BOOL newl = FALSE;

char wchars[15] = {
  "<=-?!()',./&\":"
};

char wtext (int data) {
  if (data > 127) {
    newl = TRUE;       data -= 128;
  } else newl = FALSE;
  if (data < 10)       data += 48;
  else if (data == 10) data = 32;
  else if (data < 37)  data += 54;
  else if (data < 51)  data = (int) wchars[data - 37];
  else                 data = 39;
  return ((char) data);
}

BOOL diddata = FALSE;

int dumpdata (int opcode, int *curdata, int numdata, int *fp, int *curcomm, int numcomm, int *curcommline, int numcommline) {
  int pnum, tnum;
  int numoperands;
  int k;
  int numchars = 0;

  numoperands = 2 + dataarray[*curdata].end - count;
  pnum = dataarray[*curdata].per_line;  /* print up to pnum bytes data */
  if (dataarray[*curdata].type == DATA) {
    sprintf (out2, "%02X ", (UBYTE) opcode);
    strcat (out, out2);
    if ((pnum < 1) || (pnum > 24)) pnum = 16;                /* no more than 24 bytes hex data */
  } else {
    out2[0] = (dataarray[*curdata].type == ASCII) ? opcode : wtext (opcode);
    out2[1] = '\0';
    strcat (out, out2);
    if ((pnum < 1) || (pnum > 70)) pnum = 32;                /* no more than 70 bytes ASCII data */
  }
  newl = FALSE;
  tnum = (pnum > numoperands) ? numoperands - 2 : pnum - 1;
  for (k = 0; k < numoperands - 1; k++) {       /* print the data */
    if ((++numchars >= pnum) || newl) {
      if ((tnum) || (pnum == 1)) {
        docomment (count - tnum, curcomm, numcomm, tnum);
        docommline (count - tnum, curcommline, numcommline);
      }
      /* GT: printf("%s\n",out) */ ;
      sprintf (out, "%04X: ", count);
      numchars = 0;
      newl = FALSE;
    }
    if (dataarray[*curdata].type == DATA) sprintf (out2, "%02X ", getbyte (fp));    /* hex */
    else {
      out2[0] = (dataarray[*curdata].type == ASCII) ? getbyte (fp) : wtext (getbyte (fp)); /* ASCII */
      out2[1] = '\0';
    }
    strcat (out, out2);
  }
  if (*curdata < numdata) (*curdata)++;
  diddata = TRUE;
  return (numoperands - 2);
}

void freearrays (void) {
  if (labarray)      free (labarray);
  if (dataarray)     free (dataarray);
  if (commarray)     free (commarray);
  if (commlinearray) free (commlinearray);
}

BOOL mallocarrays (void) {
  BOOL gotit = FALSE;

  if ((labarray = (struct lastruct *) malloc (sizeof (struct lastruct) * MAXLABEL)))
    if ((dataarray = (struct dastruct *)malloc (sizeof (struct dastruct) * MAXDATA)))
      if ((commarray = (struct castruct *)malloc (sizeof (struct castruct) * MAXCOMMENT)))
        if ((commlinearray = (struct castruct *)malloc (sizeof (struct castruct) * MAXCOMMLINE)))
          gotit = TRUE;
  if (!gotit)
    freearrays ();
  return (gotit);
}

char *fullequaddr = "%s EQU $%04X\n";
char *shortequaddr = "%s EQU $%02X\n";
int VECTREX = FALSE;          // Is target the Vectrex?
int Gen_C = FALSE;            // static binary translation to C wanted?
int Gen_Switch = FALSE;       // If generating C, do we write case labels or standard labels?
int Do_Timing = FALSE;
int Single_Step = FALSE;

int Accessible = FALSE;

int main (int argc, char *argv[]) {
  int music, height, width, rel_y, rel_x, c;
  int i, j, k;
  int opcode, page;
  UBYTE operand[4];
  FILE *bin;
  int fetch_offset = 0;
  int *fp = &fetch_offset;
  int org = ~0; // GTDEBUG: aka -1. should never get to code generation with it set as this...
  opcodeinfo *op;
  int numoperands;
  int sp;
  int numcomm = 0, numdata = 0, numcommline = 0;
  int curcomm = 0, curdata = 0, curcommline = 0;
  char *Progname = argv[0];
  
  /* GT:char *printaddr; */
  BOOL dobreak;

  if (argc == 1) {
    fprintf (stderr, "syntax: 6809dasm [--vectrex] [--sbt] [--single-step] [--timing] [--org 0xnnnn] file.bin [file.dat]\n"); // does %X need xxxx or 0xnnnn ?
    exit (1);
  }

  if (strcmp (argv[1], "--list") == 0) {        /* show all instructions (debug aid.) */
    for (i = 0; i < numops[0]; i++)
      printf ("opcode %02X, operands %d, name %6s, mode %s, cycles %d\n",
              pg1opcodes[i].opcode, pg1opcodes[i].numoperands, pg1opcodes[i].name, modenames[pg1opcodes[i].mode], pg1opcodes[i].numcycles);
    for (i = 0; i < numops[1]; i++)
      printf ("opcode 10 %02X, operands %d, name %6s, mode %s, cycles %d\n",
              pg2opcodes[i].opcode, pg2opcodes[i].numoperands, pg2opcodes[i].name, modenames[pg2opcodes[i].mode], pg2opcodes[i].numcycles);
    for (i = 0; i < numops[2]; i++)
      printf ("opcode 11 %02X, operands %d, name %6s, mode %s, cycles %d\n",
              pg3opcodes[i].opcode, pg3opcodes[i].numoperands, pg3opcodes[i].name, modenames[pg3opcodes[i].mode], pg3opcodes[i].numcycles);
    exit (0);
  }

  if (strcmp (argv[1], "--vectrex") == 0) {
    VECTREX = TRUE;
    argv += 1;
    argc -= 1;
  } else if (strcmp (argv[1], "--no-vectrex") == 0) {   /* is target using Vectrex BIOS or is it stand-alone? */
    VECTREX = FALSE;
    argv += 1;
    argc -= 1;
  }

  if (strcmp (argv[1], "--sbt") == 0) {
    Gen_C = TRUE;
    argv += 1;
    argc -= 1;
  } else if (strcmp (argv[1], "--no-sbt") == 0) {       /* generate C rather than disassemble (disassembly isn't reassemblable yet - still crude) */
    Gen_C = FALSE;
    argv += 1;
    argc -= 1;
  }

  if ((strcmp (argv[1], "--single-step") == 0) || (strcmp (argv[1], "--ss") == 0)) {
    Single_Step = TRUE;
    argv += 1;
    argc -= 1;
  } else if ((strcmp (argv[1], "--no-single-step") == 0) || (strcmp (argv[1], "--no-ss") == 0)) {       /* single-step support */
    Single_Step = FALSE;
    argv += 1;
    argc -= 1;
  }

  if (strcmp (argv[1], "--timing") == 0) {
    Do_Timing = TRUE;
    argv += 1;
    argc -= 1;
  } else if (strcmp (argv[1], "--no-timing") == 0) {       /* instruction timing. May be by single-step or agrregated in larger units */
    Do_Timing = FALSE;
    argv += 1;
    argc -= 1;
  }

  if (!mallocarrays ()) {
    fprintf (stderr, "Can't get memory for arrays\n");
    exit (20);
  }
  
  if (VECTREX)
    readdatafile ("bios.dat", &org, &numlab, &numdata, &numcomm, &numcommline); // add bios vars


  // GTDEBUG moving this here in case flags were being overwritten at the point below where
  // this used to be done...
  for (i = 0; i <= 0xFFFF; i++) {
    F_[i] = F_OUTSIDE_FILE;
    DP[i] = -1;                 // inferred value of DP at this opcode
    codesize[i] = 0;            // how many bytes this opcode and operands take up
    hex[i] = "";                // the disassembly, for putting back in order
    decode[i] = "";             // the disassembly, for putting back in order
    comment[i] = "";            // ditto
  }

  if (org > -1) {               /* int PC to ORG val or 0 */
    count = org; // TO DO: start disassembling from ORG???
  } else {
    count = 0;
    if (strcmp (argv[1], "--org") == 0) {
      sscanf (argv[2], "%x", &org);
      count = org;
      argv += 2;
      argc -= 2;
    } else {
      // GTDEBUG: fix org FFFF (unset) here...
      count = org = 0;
    }
  }

  if (argc > 3) {
    fprintf (stderr, "Usage: %s <file> [<datafile>]\n", Progname);
    exit (10);
  }

  if (argc == 3) {
    readdatafile (argv[2], &org, &numlab, &numdata, &numcomm, &numcommline);    // rom-specific labels etc
  }

  dumpf (R_Always, 0, "%19s ORG   $%04X", (Gen_C ? "//" : "  "), (org == -1 ? 0 : org));

  /* GT: for(k=0;k<numlab;k++) { // print labels first if(labarray[k].lab<256) printaddr=shortequaddr; else printaddr=fullequaddr;
     printf(printaddr,labarray[k].label,labarray[k].lab); }

     if(numlab) printf("\n"); */

  if ((bin = fopen ("system.img", "rb")) != NULL) {
    rom_end = 0x8000;           // exclusive
    for (;;) {
      int c = fgetc (bin);
      if (c == EOF)
        break;
      F_[rom_end] &= ~F_OUTSIDE_FILE;
      mem[rom_end++] = c;
    }
    fclose (bin);
  }

  if ((bin = fopen (argv[1], "rb")) == NULL) {
    // open binary file
    fprintf (stderr, "Can't open file '%s'\n", argv[1]);
    exit (1);
  }

  // GT: DEBUG when would org be < 0? Is this because of a signed 16 bit org?
  // maybe need to use unsigned or mask with ffff?  Should add a check here
  // to examine, if org < 0 ...
  if (org < 0) {
    fprintf(stderr, "BUG CHECK: why is org == 0x%04x ?\n", org);
  }

  // for now, this is not behaving as I hoped. I need to study the reentrancy of
  // scanning again with these flags non-default...
  //if (load_tags(argv[1])) { // should probably store this in the .dat file rather than using a .tags suffix...
  //}
    
  rom_end = (org < 0 ? 0 : org);                  // exclusive
  rom_start = rom_end;
  for (;;) {
    int c = fgetc (bin);
    if (c == EOF)
      break;
    F_[rom_end] &= ~F_OUTSIDE_FILE;
    F_[rom_end] |= F_NEED_DECODE;
    mem[rom_end++] = c;
  }
  fclose (bin);

  if (VECTREX) {
    char *s;
    char temp[1024];

    init_vectrex_bios();
    s = temp;
    s += sprintf (s, "%19s FCC   \"", (Gen_C ? "//" : "  "));
    for (;;) {                  // getstring80 (fp) Copyright
      c = getbyte (fp);
      if (c == 0x80)
        break;
      s += sprintf (s, "%c", c);
    }
    s += sprintf (s, "%c", '"');
    dumpf (R_Always, 0, "%s", temp);
    dumpf (R_Always, 0, "%19s FCB   $80", (Gen_C ? "//" : "  "));
    music = getword (fp);
    /* 
       music1 EQU 0xFD0D ;
       music2 EQU 0xFD1D ;
       music3 EQU 0xFD81 ;
       music4 EQU 0xFDD3 ;
       music5 EQU 0xFE38 ;
       music6 EQU 0xFE76 ;
       music7 EQU 0xFEC6 ;
       music8 EQU 0xFEF8 ;
       music9 EQU 0xFF26 ;
       musica EQU 0xFF44 ;
       musicb EQU 0xFF62 ;
       musicc EQU 0xFF7A ;
       musicd EQU 0xFF8F ;
     */
    s = checklabs ("", music, FALSE, FALSE, FALSE);
    if (*s == '\0') {
      dumpf (R_Always, 0, "%19s FDB   $%04X", (Gen_C ? "//" : "  "), music);
    } else {
      dumpf (R_Always, 0, "%19s FDB   %s", (Gen_C ? "//" : "  "), s);
    }
    for (;;) {
      height = getbyte (fp);
      if (height == 0) break;
      width = getbyte (fp);
      dumpf (R_Always, 0, "%19s FCB   $%02X, $%02X                ; h,w of raster image", (Gen_C ? "//" : "  "), height, width);
      rel_y = getbyte (fp);
      rel_x = getbyte (fp);
      dumpf (R_Always, 0, "%19s FCB   $%02X, $%02X                ; y,x of raster image", (Gen_C ? "//" : "  "), rel_y, rel_x);
      sprintf (temp, "%19s FCC   \"", (Gen_C ? "//" : "  "));
      s = temp + strlen(temp);
      for (;;) {
        c = getbyte (fp);
        if (c == 0x80) break;
        *s++ = c;
        //s += sprintf (s, "%c", c);
      }                         // getstring80 (fp) Text message
      *s++ = '"'; *s = '\0';
      //s += sprintf (s, "%c", '"');
      dumpf (R_Always, 0, "%s", temp);
      dumpf (R_Always, 0, "%19s FCB   $80", (Gen_C ? "//" : "  "));
    }
  dumpf (R_Always, 0, "%19s FCB   $00", (Gen_C ? "//" : "  "));
  {int i = *fp;
    do {
      i -= 1;
      F_[i] &= ~F_NEED_DECODE;
    } while (i != 0);
  }
  queue[next_queue_item++] = (*fp);     // start of code is first seed. (on Vectrex. With arcade games, use start vector etc))
  F_[(*fp)] |= F_LABEL;
  dobreak = FALSE;              // used for end of a straight-line recursion
  } else {
    // not vectrex
    (*fp) = org;
    queue[next_queue_item++] = org;     // start of code is first seed.
    // NOTE: when translating Atari vector arcade cabinets, use the [RESET] vector contents as the first entry point.
    F_[org] |= F_LABEL;
    dobreak = FALSE;              // used for end of a straight-line recursion
  }

  while (next_seed > 0) {
    queue[next_queue_item++] = seed[--next_seed];
    //    F_[seed[next_seed]] |= F_LABEL; // WRONG!!! "code nnnn" does not imply a label!
  }

  while (next_queue_item > 0) {
    *fp = queue[--next_queue_item];
    //fprintf(stderr, "DEBUG: explore %4X\n", *fp);
    if (F_[*fp] & (F_DATA | F_OUTSIDE_FILE | F_INVALID_DECODE | F_VALID_DECODE)) { continue; }
    while ((opcode = getbyte (fp)) != EOF) {
      int current_address = (*fp) - 1;

      if (F_[current_address] & (F_DATA | F_OUTSIDE_FILE | F_INVALID_DECODE | F_VALID_DECODE)) { break; } // recursion stoppers
      count = current_address + 1;
      op = NULL;
      docommline (count, &curcommline, numcommline);

      // printf("%s", checklabs("",count-1,TRUE,FALSE,FALSE)); /* if add lab, print */
      sprintf (out, "%04X: ", count - 1);       /* print PC */

#ifdef REMOVED_WHILE_LOCATING_SPURIOUS_ERRORS
      if (numdata) {
        while (((count - 1) > dataarray[curdata].end) && (curdata < numdata)) {
          fprintf (stderr, "Error: missed a data line, start=%X, end=%X\n", dataarray[curdata].start, dataarray[curdata].end);
          curdata++;
        }
      }
#endif
      if (numdata && ((count - 1) >= dataarray[curdata].start) && ((count - 1) <= dataarray[curdata].end)) { /* data? */
        numoperands = dumpdata (opcode, &curdata, numdata, fp, &curcomm, numcomm, &curcommline, numcommline);
        i = numops[0] + 1;      /* skip decoding as an opcode */
      } else {                  /* not data - search for opcode */
        sprintf (out2, "%02X ", (UBYTE) opcode);
        strcat (out, out2);
        for (i = 0; (i < numops[0]) && (pg1opcodes[i].opcode != opcode); i++) ;

        if (i < numops[0]) {    /* opcode found */
          if (pg1opcodes[i].mode >= PG2) {      /* page switch */
            opcode = getbyte (fp);
            sprintf (out2, "%02X ", (UBYTE) opcode);
            strcat (out, out2);
            page = pg1opcodes[i].mode - PG2 + 1;        /* get page # */
            for (k = 0; (k < numops[page]) && (opcode != pgpointers[page][k].opcode); k++) ;
            if (k != numops[page]) {    /* opcode found */
              op = (opcodeinfo *) & (pgpointers[page][k]);
              numoperands = pgpointers[page][k].numoperands;
              for (j = 0; j < numoperands - 1; j++) {
                sprintf (out2, "%02X ", (operand[j] = getbyte (fp)));
                strcat (out, out2);
              }

              if (pgpointers[page][k].mode != IND) {
                for (sp = strlen (out); sp < OPNAMETAB; sp++) strcat (out, " ");
                sprintf (out2, "%s", pgpointers[page][k].name);
                strcat (out, out2);
                for (sp = strlen (out); sp < OPERANDTAB; sp++) strcat (out, " ");
              }
              printoperands (current_address, opcode, numoperands - 1, operand, pgpointers[page][k].mode, fp, pgpointers[page][k].name, out);
              F_[current_address] |= F_VALID_DECODE;
            } else {            /* not found in alternate page */
              for (sp = strlen (out); sp < OPNAMETAB; sp++) strcat (out, " ");
              strcat (out, "Illegal Opcode");
              F_[current_address] |= F_INVALID_DECODE;
              break;
            }
          } else {              /* page 1 opcode */
            op = (opcodeinfo *) & (pg1opcodes[i]);
            numoperands = pg1opcodes[i].numoperands;
            for (j = 0; j < numoperands; j++) {
              sprintf (out2, "%02X ", (operand[j] = getbyte (fp)));
              strcat (out, out2);
            }
            if (pg1opcodes[i].mode != IND) {
              for (sp = strlen (out); sp < OPNAMETAB; sp++) strcat (out, " ");
              sprintf (out2, "%s", pg1opcodes[i].name);
              strcat (out, out2);
              for (sp = strlen (out); sp < OPERANDTAB; sp++) strcat (out, " ");
            }
            printoperands (current_address, opcode, numoperands, operand, pg1opcodes[i].mode, fp, pg1opcodes[i].name, out);
            F_[current_address] |= F_VALID_DECODE;
          }
        } else if (i == numops[0]) {    /* not found in page 1 */
          for (sp = strlen (out); sp < OPNAMETAB; sp++) strcat (out, " ");
          strcat (out, "Illegal Opcode");
          F_[current_address] |= F_INVALID_DECODE;
          break;
        }
        F_[current_address] |= F_VALID_DECODE;

      }
      docomment (count - 1 - numoperands, &curcomm, numcomm, numoperands + 1);
      if (op) {
        if ((!strcasecmp (op->name, "BRA")) ||  /* extra space - branch */
            (!strcasecmp (op->name, "LBRA")) ||
            (!strcasecmp (op->name, "RTS")) ||
            (!strcasecmp (op->name, "JMP")) ||
            (!strcasecmp (op->name, "RTI")) ||
            (!strncasecmp (op->name, "PUL", 3) && PC) ||   /* PUL? PC=RTS */
            (!strcasecmp (op->name, "WAI"))) {
          if (strlen (out) && (out[strlen (out) - 1] != '\n'))
            /* strcat(out,"\n") */
            F_[current_address] |= F_ENDSECTION; // add in output code
          dobreak = TRUE;
        }
      }
      if (diddata) {
        if (strlen (out) && (out[strlen (out) - 1] != '\n')) strcat (out, "\n");
      }
      save (out);
      PC = FALSE;
      diddata = FALSE;
      if (dobreak) break;
    }
    dobreak = FALSE;
  }
  memory = mem;                 // for SBT

#ifdef NEVER
  // when the code is stabilised we might insert the actual working header here...
  if (Gen_C) {
    dumpf (R_Always, 0, "#include <stdint.h>");
    dumpf (R_Always, 0, "int main(int argc, char **argv) {");
    dumpf (R_Always, 0, "  typedef uint32_t UINT32;");
    dumpf (R_Always, 0, "  typedef int32_t  SINT32;");
    dumpf (R_Always, 0, "  typedef uint16_t UINT16;");
    dumpf (R_Always, 0, "  typedef int16_t  SINT16;");
    dumpf (R_Always, 0, "  typedef uint8_t  UINT8;");
    dumpf (R_Always, 0, "  typedef int8_t   SINT8;");
    dumpf (R_Always, 0, "");
    dumpf (R_Always, 0, "  UINT8 memory[0x10000], *memory_DP = &memory[0xD000];");
    dumpf (R_Always, 0, "");
    dumpf (R_Always, 0, "  // Modify this header to suit your target...");
    dumpf (R_Always, 0, "  SINT32 res, A, B, D, C;");
    dumpf (R_Always, 0, "  UINT16 PC, X, Y, S, U, Z, DP = 0xD0, arg, ea, msn, lsn, val;");
    dumpf (R_Always, 0, "  UINT8  N, H, V, CC;");
    dumpf (R_Always, 0, "");
    dumpf (R_Always, 0, "#define JUMP do {} while (0)");
  }
#endif
  
  // GT DEBUG: need to skip over the number of bytes used by each instruction:
  // for (i = org; i <= 0xFFFF; i++) {
  // !! This seemed to fix some of the test examples...
  if ((org&0xFFFF) == 0xFFFF) {
    fprintf(stderr, "DEBUG: Org FFFF should never happen\n");
    org = 0;
  }
  for (i = org; i <= 0xFFFF; i+=(codesize[i] <= 0 ? 1 : codesize[i])) { 
    static char line[512], *lp;
    char *s;

    line[0] = '\0';
    lp = line;
    if (codesize[i] > 0) {
      {int j; for (j = 1; j < codesize[i]; j++) F_[i+j] &= ~F_NEED_DECODE;}
      s = checklabs ("", i, FALSE/*TRUE*/, FALSE, TRUE/*FALSE*/); // third param adds ":\n" if true; last param says allow decode of 00-ff whether zp or not
      if (Single_Step) {
        if (Accessible) {
          Accessible = FALSE; lp += sprintf (lp, "PC = 0x%04X; JUMP; // sstep\n", i);
        }
      }
      if ((F_[i] & F_LABEL) || Single_Step) {
        assert(F_[i]&F_VALID_DECODE);
        // flush((unsigned long)-1L); don't need to flush for a label, only at the jump *to* a label...
        if (Gen_C) {
          //if (Gen_Switch) {
          Accessible = TRUE; lp += sprintf (lp, "case 0x%04X:\n", i); // skip this if checklabs came up with one???
            //} else {
            if (!Single_Step) lp += sprintf (lp, "L%04X:\n", i);      // skip this if checklabs came up with one???
            {char copy[32];sprintf (copy, "L%04X", i);
              if ((*s != '\0') && (strncasecmp(copy,s,5) != 0)) {
                char *t; t = strchr(s, ' '); if (t) *t = '\0'; // TEMP HACK starwars BUG
                if (!Single_Step) lp += sprintf (lp, "%s:\n", s);      // skip this if checklabs came up with one???
              }
            }
            lp += sprintf (lp, "               ");//align...
          //}
        } else {
          if (*s == '\0') {
            lp += sprintf (lp, "L%04X         ", i);      // skip this if checklabs came up with one???
          } else {
            lp += sprintf (lp, "%-12s ", s);      // skip this if checklabs came up with one???
          }
        }
      } else {
        lp += sprintf (lp, "             ");
      }
      if (Gen_C) {//gtdebug
        char *labname = checklabs ("", i, FALSE/*TRUE*/, FALSE, TRUE/*FALSE*/);
        // previously the asm was just a comment, now it is wrapped by mon() which can
        // optionally be implemented as a macro which throws its parameter away, or as
        // a procedure that prints its parameter to a log file or a cyclic buffer...
        lp += sprintf (lp, "                                      mon(\"%-8s %-30s; %04X: %s\\n\");", F_[i]&F_LABEL ? labname : "", s = decode[i], i, hex[i]);

        // GTDEBUG:
        if ((i & 0xFFFF) == 0xFFFF) {
          fprintf(stderr, "DEBUG INFO: i = 0x%08x\n", i);
          lp += sprintf (lp, " /* DBG:%08x */", i);
        }
        
      } else {
        lp += sprintf (lp, "       %-30s; %04X: %s", s = decode[i], i, hex[i]);
      }
      if ((strncmp (s, "BSR", 3) == 0)
          || (strncmp (s, "LBSR", 4) == 0)
          || (strncmp (s, "JSR", 3) == 0)
          || (strncmp (s, "SWI", 3) == 0)
          || (strncmp (s, "CWAI", 4) == 0)
          || (strncmp (s, "SYNC", 4) == 0)) {
        F_[i + codesize[i]] |= F_LABEL;  // just in time :-) For SBT
      }
      if (*comment[i] != '\0') lp += sprintf (lp, "    // %s", comment[i]);

      dumpf (R_Always, 0, "%s", line);

      if (Gen_C) translate6809 (i, i + codesize[i], 999); // codesize isn't just a simple static lookup, needs a full inst decode.
      if (F_[i] & F_ENDSECTION) {
        flush(R_FLUSH);
        dumpf (R_Always, 0, "");        // optional newline for JMP/BRA/RTS etc
      }
    } else if (F_[i]&F_NEED_DECODE) {
      extern char *disasm(unsigned char *memory, unsigned int *pc, int showhex, int showaddr);
      unsigned int pc_copy = i;
      // ignore data we know is data - print data that is probably undecoded code...
      if ((F_[i]&F_DATA) == 0) dumpf (R_Always, 0, "%19s FCB   $%02X%22s %04X: %s '%c' %s", (Gen_C ? "//" : "  "),
             memory[i], ";", i, hex[i],
             isprint(memory[i]) ? memory[i] : ' ',
             disasm(memory, &pc_copy, TRUE, FALSE));
    }
  }
  if (Gen_C && FALSE) {
    dumpf (R_Always, 0, "}");
  }
  flush (R_Always);
  
  // save for use by fallback interpreter.  currently not for use by this program.
  save_tags(argv[1]);

  freearrays ();
  return 0;
}