initial import
[picodrive.git] / cpu / musashi / m68kmake.c
diff --git a/cpu/musashi/m68kmake.c b/cpu/musashi/m68kmake.c
new file mode 100644 (file)
index 0000000..d7cbc37
--- /dev/null
@@ -0,0 +1,1484 @@
+/* ======================================================================== */\r
+/* ========================= LICENSING & COPYRIGHT ======================== */\r
+/* ======================================================================== */\r
+/*\r
+ *                                  MUSASHI\r
+ *                                Version 3.3\r
+ *\r
+ * A portable Motorola M680x0 processor emulation engine.\r
+ * Copyright 1998-2001 Karl Stenerud.  All rights reserved.\r
+ *\r
+ * This code may be freely used for non-commercial purposes as long as this\r
+ * copyright notice remains unaltered in the source code and any binary files\r
+ * containing this code in compiled form.\r
+ *\r
+ * All other lisencing terms must be negotiated with the author\r
+ * (Karl Stenerud).\r
+ *\r
+ * The latest version of this code can be obtained at:\r
+ * http://kstenerud.cjb.net\r
+ */\r
+\r
+/*\r
+ * Modified For OpenVMS By:  Robert Alan Byer\r
+ *                           byer@mail.ourservers.net\r
+ */\r
+\r
+\r
+/* ======================================================================== */\r
+/* ============================ CODE GENERATOR ============================ */\r
+/* ======================================================================== */\r
+/*\r
+ * This is the code generator program which will generate the opcode table\r
+ * and the final opcode handlers.\r
+ *\r
+ * It requires an input file to function (default m68k_in.c), but you can\r
+ * specify your own like so:\r
+ *\r
+ * m68kmake <output path> <input file>\r
+ *\r
+ * where output path is the path where the output files should be placed, and\r
+ * input file is the file to use for input.\r
+ *\r
+ * If you modify the input file greatly from its released form, you may have\r
+ * to tweak the configuration section a bit since I'm using static allocation\r
+ * to keep things simple.\r
+ *\r
+ *\r
+ * TODO: - build a better code generator for the move instruction.\r
+ *       - Add callm and rtm instructions\r
+ *       - Fix RTE to handle other format words\r
+ *       - Add address error (and bus error?) handling\r
+ */\r
+\r
+\r
+const char* g_version = "3.3";\r
+\r
+/* ======================================================================== */\r
+/* =============================== INCLUDES =============================== */\r
+/* ======================================================================== */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+#include <stdarg.h>\r
+\r
+\r
+\r
+/* ======================================================================== */\r
+/* ============================= CONFIGURATION ============================ */\r
+/* ======================================================================== */\r
+\r
+#define M68K_MAX_PATH 1024\r
+#define M68K_MAX_DIR  1024\r
+\r
+#define MAX_LINE_LENGTH                 200    /* length of 1 line */\r
+#define MAX_BODY_LENGTH                 300    /* Number of lines in 1 function */\r
+#define MAX_REPLACE_LENGTH               30    /* Max number of replace strings */\r
+#define MAX_INSERT_LENGTH              5000    /* Max size of insert piece */\r
+#define MAX_NAME_LENGTH                  30    /* Max length of ophandler name */\r
+#define MAX_SPEC_PROC_LENGTH              4    /* Max length of special processing str */\r
+#define MAX_SPEC_EA_LENGTH                5    /* Max length of specified EA str */\r
+#define EA_ALLOWED_LENGTH                11    /* Max length of ea allowed str */\r
+#define MAX_OPCODE_INPUT_TABLE_LENGTH  1000    /* Max length of opcode handler tbl */\r
+#define MAX_OPCODE_OUTPUT_TABLE_LENGTH 3000    /* Max length of opcode handler tbl */\r
+\r
+/* Default filenames */\r
+#define FILENAME_INPUT      "m68k_in.c"\r
+#define FILENAME_PROTOTYPE  "m68kops.h"\r
+#define FILENAME_TABLE      "m68kops.c"\r
+#define FILENAME_OPS_AC     "m68kopac.c"\r
+#define FILENAME_OPS_DM     "m68kopdm.c"\r
+#define FILENAME_OPS_NZ     "m68kopnz.c"\r
+\r
+\r
+/* Identifier sequences recognized by this program */\r
+\r
+#define ID_INPUT_SEPARATOR "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\r
+\r
+#define ID_BASE                 "M68KMAKE"\r
+#define ID_PROTOTYPE_HEADER     ID_BASE "_PROTOTYPE_HEADER"\r
+#define ID_PROTOTYPE_FOOTER     ID_BASE "_PROTOTYPE_FOOTER"\r
+#define ID_TABLE_HEADER         ID_BASE "_TABLE_HEADER"\r
+#define ID_TABLE_FOOTER         ID_BASE "_TABLE_FOOTER"\r
+#define ID_TABLE_BODY           ID_BASE "_TABLE_BODY"\r
+#define ID_TABLE_START          ID_BASE "_TABLE_START"\r
+#define ID_OPHANDLER_HEADER     ID_BASE "_OPCODE_HANDLER_HEADER"\r
+#define ID_OPHANDLER_FOOTER     ID_BASE "_OPCODE_HANDLER_FOOTER"\r
+#define ID_OPHANDLER_BODY       ID_BASE "_OPCODE_HANDLER_BODY"\r
+#define ID_END                  ID_BASE "_END"\r
+\r
+#define ID_OPHANDLER_NAME       ID_BASE "_OP"\r
+#define ID_OPHANDLER_EA_AY_8    ID_BASE "_GET_EA_AY_8"\r
+#define ID_OPHANDLER_EA_AY_16   ID_BASE "_GET_EA_AY_16"\r
+#define ID_OPHANDLER_EA_AY_32   ID_BASE "_GET_EA_AY_32"\r
+#define ID_OPHANDLER_OPER_AY_8  ID_BASE "_GET_OPER_AY_8"\r
+#define ID_OPHANDLER_OPER_AY_16 ID_BASE "_GET_OPER_AY_16"\r
+#define ID_OPHANDLER_OPER_AY_32 ID_BASE "_GET_OPER_AY_32"\r
+#define ID_OPHANDLER_CC         ID_BASE "_CC"\r
+#define ID_OPHANDLER_NOT_CC     ID_BASE "_NOT_CC"\r
+\r
+\r
+#ifndef DECL_SPEC\r
+#define DECL_SPEC\r
+#endif /* DECL_SPEC */\r
+\r
+\r
+\r
+/* ======================================================================== */\r
+/* ============================== PROTOTYPES ============================== */\r
+/* ======================================================================== */\r
+\r
+enum {\r
+       CPU_TYPE_000 = 0,\r
+       CPU_TYPE_010,\r
+       CPU_TYPE_020,\r
+       CPU_TYPE_040,\r
+       NUM_CPUS\r
+};\r
+\r
+#define UNSPECIFIED "."\r
+#define UNSPECIFIED_CH '.'\r
+\r
+#define HAS_NO_EA_MODE(A) (strcmp(A, "..........") == 0)\r
+#define HAS_EA_AI(A)   ((A)[0] == 'A')\r
+#define HAS_EA_PI(A)   ((A)[1] == '+')\r
+#define HAS_EA_PD(A)   ((A)[2] == '-')\r
+#define HAS_EA_DI(A)   ((A)[3] == 'D')\r
+#define HAS_EA_IX(A)   ((A)[4] == 'X')\r
+#define HAS_EA_AW(A)   ((A)[5] == 'W')\r
+#define HAS_EA_AL(A)   ((A)[6] == 'L')\r
+#define HAS_EA_PCDI(A) ((A)[7] == 'd')\r
+#define HAS_EA_PCIX(A) ((A)[8] == 'x')\r
+#define HAS_EA_I(A)    ((A)[9] == 'I')\r
+\r
+enum\r
+{\r
+       EA_MODE_NONE,   /* No special addressing mode */\r
+       EA_MODE_AI,             /* Address register indirect */\r
+       EA_MODE_PI,             /* Address register indirect with postincrement */\r
+       EA_MODE_PI7,    /* Address register 7 indirect with postincrement */\r
+       EA_MODE_PD,             /* Address register indirect with predecrement */\r
+       EA_MODE_PD7,    /* Address register 7 indirect with predecrement */\r
+       EA_MODE_DI,             /* Address register indirect with displacement */\r
+       EA_MODE_IX,             /* Address register indirect with index */\r
+       EA_MODE_AW,             /* Absolute word */\r
+       EA_MODE_AL,             /* Absolute long */\r
+       EA_MODE_PCDI,   /* Program counter indirect with displacement */\r
+       EA_MODE_PCIX,   /* Program counter indirect with index */\r
+       EA_MODE_I               /* Immediate */\r
+};\r
+\r
+\r
+/* Everything we need to know about an opcode */\r
+typedef struct\r
+{\r
+       char name[MAX_NAME_LENGTH];           /* opcode handler name */\r
+       unsigned char size;                   /* Size of operation */\r
+       char spec_proc[MAX_SPEC_PROC_LENGTH]; /* Special processing mode */\r
+       char spec_ea[MAX_SPEC_EA_LENGTH];     /* Specified effective addressing mode */\r
+       unsigned char bits;                   /* Number of significant bits (used for sorting the table) */\r
+       unsigned short op_mask;               /* Mask to apply for matching an opcode to a handler */\r
+       unsigned short op_match;              /* Value to match after masking */\r
+       char ea_allowed[EA_ALLOWED_LENGTH];   /* Effective addressing modes allowed */\r
+       char cpu_mode[NUM_CPUS];              /* User or supervisor mode */\r
+       char cpus[NUM_CPUS+1];                /* Allowed CPUs */\r
+       unsigned char cycles[NUM_CPUS];       /* cycles for 000, 010, 020 */\r
+} opcode_struct;\r
+\r
+\r
+/* All modifications necessary for a specific EA mode of an instruction */\r
+typedef struct\r
+{\r
+       const char* fname_add;\r
+       const char* ea_add;\r
+       unsigned int mask_add;\r
+       unsigned int match_add;\r
+} ea_info_struct;\r
+\r
+\r
+/* Holds the body of a function */\r
+typedef struct\r
+{\r
+       char body[MAX_BODY_LENGTH][MAX_LINE_LENGTH+1];\r
+       int length;\r
+} body_struct;\r
+\r
+\r
+/* Holds a sequence of search / replace strings */\r
+typedef struct\r
+{\r
+       char replace[MAX_REPLACE_LENGTH][2][MAX_LINE_LENGTH+1];\r
+       int length;\r
+} replace_struct;\r
+\r
+\r
+/* Function Prototypes */\r
+void error_exit(const char* fmt, ...);\r
+void perror_exit(const char* fmt, ...);\r
+int check_strsncpy(char* dst, char* src, int maxlength);\r
+int check_atoi(char* str, int *result);\r
+int skip_spaces(char* str);\r
+int num_bits(int value);\r
+int atoh(char* buff);\r
+int fgetline(char* buff, int nchars, FILE* file);\r
+int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type);\r
+opcode_struct* find_opcode(char* name, int size, char* spec_proc, char* spec_ea);\r
+opcode_struct* find_illegal_opcode(void);\r
+int extract_opcode_info(char* src, char* name, int* size, char* spec_proc, char* spec_ea);\r
+void add_replace_string(replace_struct* replace, const char* search_str, const char* replace_str);\r
+void write_body(FILE* filep, body_struct* body, replace_struct* replace);\r
+void get_base_name(char* base_name, opcode_struct* op);\r
+void write_prototype(FILE* filep, char* base_name);\r
+void write_function_name(FILE* filep, char* base_name);\r
+void add_opcode_output_table_entry(opcode_struct* op, char* name);\r
+static int DECL_SPEC compare_nof_true_bits(const void* aptr, const void* bptr);\r
+void print_opcode_output_table(FILE* filep);\r
+void write_table_entry(FILE* filep, opcode_struct* op);\r
+void set_opcode_struct(opcode_struct* src, opcode_struct* dst, int ea_mode);\r
+void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* opinfo, int ea_mode);\r
+void generate_opcode_ea_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op);\r
+void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op_in, int offset);\r
+void process_opcode_handlers(void);\r
+void populate_table(void);\r
+void read_insert(char* insert);\r
+\r
+\r
+\r
+/* ======================================================================== */\r
+/* ================================= DATA ================================= */\r
+/* ======================================================================== */\r
+\r
+/* Name of the input file */\r
+char g_input_filename[M68K_MAX_PATH] = FILENAME_INPUT;\r
+\r
+/* File handles */\r
+FILE* g_input_file = NULL;\r
+FILE* g_prototype_file = NULL;\r
+FILE* g_table_file = NULL;\r
+FILE* g_ops_ac_file = NULL;\r
+FILE* g_ops_dm_file = NULL;\r
+FILE* g_ops_nz_file = NULL;\r
+\r
+int g_num_functions = 0;  /* Number of functions processed */\r
+int g_num_primitives = 0; /* Number of function primitives read */\r
+int g_line_number = 1;    /* Current line number */\r
+\r
+/* Opcode handler table */\r
+opcode_struct g_opcode_input_table[MAX_OPCODE_INPUT_TABLE_LENGTH];\r
+\r
+opcode_struct g_opcode_output_table[MAX_OPCODE_OUTPUT_TABLE_LENGTH];\r
+int g_opcode_output_table_length = 0;\r
+\r
+ea_info_struct g_ea_info_table[13] =\r
+{/* fname    ea        mask  match */\r
+       {"",     "",       0x00, 0x00}, /* EA_MODE_NONE */\r
+       {"ai",   "AY_AI",  0x38, 0x10}, /* EA_MODE_AI   */\r
+       {"pi",   "AY_PI",  0x38, 0x18}, /* EA_MODE_PI   */\r
+       {"pi7",  "A7_PI",  0x3f, 0x1f}, /* EA_MODE_PI7  */\r
+       {"pd",   "AY_PD",  0x38, 0x20}, /* EA_MODE_PD   */\r
+       {"pd7",  "A7_PD",  0x3f, 0x27}, /* EA_MODE_PD7  */\r
+       {"di",   "AY_DI",  0x38, 0x28}, /* EA_MODE_DI   */\r
+       {"ix",   "AY_IX",  0x38, 0x30}, /* EA_MODE_IX   */\r
+       {"aw",   "AW",     0x3f, 0x38}, /* EA_MODE_AW   */\r
+       {"al",   "AL",     0x3f, 0x39}, /* EA_MODE_AL   */\r
+       {"pcdi", "PCDI",   0x3f, 0x3a}, /* EA_MODE_PCDI */\r
+       {"pcix", "PCIX",   0x3f, 0x3b}, /* EA_MODE_PCIX */\r
+       {"i",    "I",      0x3f, 0x3c}, /* EA_MODE_I    */\r
+};\r
+\r
+\r
+const char* g_cc_table[16][2] =\r
+{\r
+       { "t",  "T"}, /* 0000 */\r
+       { "f",  "F"}, /* 0001 */\r
+       {"hi", "HI"}, /* 0010 */\r
+       {"ls", "LS"}, /* 0011 */\r
+       {"cc", "CC"}, /* 0100 */\r
+       {"cs", "CS"}, /* 0101 */\r
+       {"ne", "NE"}, /* 0110 */\r
+       {"eq", "EQ"}, /* 0111 */\r
+       {"vc", "VC"}, /* 1000 */\r
+       {"vs", "VS"}, /* 1001 */\r
+       {"pl", "PL"}, /* 1010 */\r
+       {"mi", "MI"}, /* 1011 */\r
+       {"ge", "GE"}, /* 1100 */\r
+       {"lt", "LT"}, /* 1101 */\r
+       {"gt", "GT"}, /* 1110 */\r
+       {"le", "LE"}, /* 1111 */\r
+};\r
+\r
+/* size to index translator (0 -> 0, 8 and 16 -> 1, 32 -> 2) */\r
+int g_size_select_table[33] =\r
+{\r
+       0,                                                                                              /* unsized */\r
+       0, 0, 0, 0, 0, 0, 0, 1,                                                 /*    8    */\r
+       0, 0, 0, 0, 0, 0, 0, 1,                                                 /*   16    */\r
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2  /*   32    */\r
+};\r
+\r
+/* Extra cycles required for certain EA modes */\r
+/* TODO: correct timings for 040 */\r
+int g_ea_cycle_table[13][NUM_CPUS][3] =\r
+{/*       000           010           020           040  */\r
+       {{ 0,  0,  0}, { 0,  0,  0}, { 0,  0,  0}, { 0,  0,  0}}, /* EA_MODE_NONE */\r
+       {{ 0,  4,  8}, { 0,  4,  8}, { 0,  4,  4}, { 0,  4,  4}}, /* EA_MODE_AI   */\r
+       {{ 0,  4,  8}, { 0,  4,  8}, { 0,  4,  4}, { 0,  4,  4}}, /* EA_MODE_PI   */\r
+       {{ 0,  4,  8}, { 0,  4,  8}, { 0,  4,  4}, { 0,  4,  4}}, /* EA_MODE_PI7  */\r
+       {{ 0,  6, 10}, { 0,  6, 10}, { 0,  5,  5}, { 0,  5,  5}}, /* EA_MODE_PD   */\r
+       {{ 0,  6, 10}, { 0,  6, 10}, { 0,  5,  5}, { 0,  5,  5}}, /* EA_MODE_PD7  */\r
+       {{ 0,  8, 12}, { 0,  8, 12}, { 0,  5,  5}, { 0,  5,  5}}, /* EA_MODE_DI   */\r
+       {{ 0, 10, 14}, { 0, 10, 14}, { 0,  7,  7}, { 0,  7,  7}}, /* EA_MODE_IX   */\r
+       {{ 0,  8, 12}, { 0,  8, 12}, { 0,  4,  4}, { 0,  4,  4}}, /* EA_MODE_AW   */\r
+       {{ 0, 12, 16}, { 0, 12, 16}, { 0,  4,  4}, { 0,  4,  4}}, /* EA_MODE_AL   */\r
+       {{ 0,  8, 12}, { 0,  8, 12}, { 0,  5,  5}, { 0,  5,  5}}, /* EA_MODE_PCDI */\r
+       {{ 0, 10, 14}, { 0, 10, 14}, { 0,  7,  7}, { 0,  7,  7}}, /* EA_MODE_PCIX */\r
+       {{ 0,  4,  8}, { 0,  4,  8}, { 0,  2,  4}, { 0,  2,  4}}, /* EA_MODE_I    */\r
+};\r
+\r
+/* Extra cycles for JMP instruction (000, 010) */\r
+int g_jmp_cycle_table[13] =\r
+{\r
+        0, /* EA_MODE_NONE */\r
+        4, /* EA_MODE_AI   */\r
+        0, /* EA_MODE_PI   */\r
+        0, /* EA_MODE_PI7  */\r
+        0, /* EA_MODE_PD   */\r
+        0, /* EA_MODE_PD7  */\r
+        6, /* EA_MODE_DI   */\r
+       10, /* EA_MODE_IX   */\r
+        6, /* EA_MODE_AW   */\r
+        8, /* EA_MODE_AL   */\r
+        6, /* EA_MODE_PCDI */\r
+       10, /* EA_MODE_PCIX */\r
+        0, /* EA_MODE_I    */\r
+};\r
+\r
+/* Extra cycles for JSR instruction (000, 010) */\r
+int g_jsr_cycle_table[13] =\r
+{\r
+        0, /* EA_MODE_NONE */\r
+        4, /* EA_MODE_AI   */\r
+        0, /* EA_MODE_PI   */\r
+        0, /* EA_MODE_PI7  */\r
+        0, /* EA_MODE_PD   */\r
+        0, /* EA_MODE_PD7  */\r
+        6, /* EA_MODE_DI   */\r
+       10, /* EA_MODE_IX   */\r
+        6, /* EA_MODE_AW   */\r
+        8, /* EA_MODE_AL   */\r
+        6, /* EA_MODE_PCDI */\r
+       10, /* EA_MODE_PCIX */\r
+        0, /* EA_MODE_I    */\r
+};\r
+\r
+/* Extra cycles for LEA instruction (000, 010) */\r
+int g_lea_cycle_table[13] =\r
+{\r
+        0, /* EA_MODE_NONE */\r
+        4, /* EA_MODE_AI   */\r
+        0, /* EA_MODE_PI   */\r
+        0, /* EA_MODE_PI7  */\r
+        0, /* EA_MODE_PD   */\r
+        0, /* EA_MODE_PD7  */\r
+        8, /* EA_MODE_DI   */\r
+       12, /* EA_MODE_IX   */\r
+        8, /* EA_MODE_AW   */\r
+       12, /* EA_MODE_AL   */\r
+        8, /* EA_MODE_PCDI */\r
+       12, /* EA_MODE_PCIX */\r
+        0, /* EA_MODE_I    */\r
+};\r
+\r
+/* Extra cycles for PEA instruction (000, 010) */\r
+int g_pea_cycle_table[13] =\r
+{\r
+        0, /* EA_MODE_NONE */\r
+        6, /* EA_MODE_AI   */\r
+        0, /* EA_MODE_PI   */\r
+        0, /* EA_MODE_PI7  */\r
+        0, /* EA_MODE_PD   */\r
+        0, /* EA_MODE_PD7  */\r
+       10, /* EA_MODE_DI   */\r
+       14, /* EA_MODE_IX   */\r
+       10, /* EA_MODE_AW   */\r
+       14, /* EA_MODE_AL   */\r
+       10, /* EA_MODE_PCDI */\r
+       14, /* EA_MODE_PCIX */\r
+        0, /* EA_MODE_I    */\r
+};\r
+\r
+/* Extra cycles for MOVEM instruction (000, 010) */\r
+int g_movem_cycle_table[13] =\r
+{\r
+        0, /* EA_MODE_NONE */\r
+        0, /* EA_MODE_AI   */\r
+        0, /* EA_MODE_PI   */\r
+        0, /* EA_MODE_PI7  */\r
+        0, /* EA_MODE_PD   */\r
+        0, /* EA_MODE_PD7  */\r
+        4, /* EA_MODE_DI   */\r
+        6, /* EA_MODE_IX   */\r
+        4, /* EA_MODE_AW   */\r
+        8, /* EA_MODE_AL   */\r
+        0, /* EA_MODE_PCDI */\r
+        0, /* EA_MODE_PCIX */\r
+        0, /* EA_MODE_I    */\r
+};\r
+\r
+/* Extra cycles for MOVES instruction (010) */\r
+int g_moves_cycle_table[13][3] =\r
+{\r
+       { 0,  0,  0}, /* EA_MODE_NONE */\r
+       { 0,  4,  6}, /* EA_MODE_AI   */\r
+       { 0,  4,  6}, /* EA_MODE_PI   */\r
+       { 0,  4,  6}, /* EA_MODE_PI7  */\r
+       { 0,  6, 12}, /* EA_MODE_PD   */\r
+       { 0,  6, 12}, /* EA_MODE_PD7  */\r
+       { 0, 12, 16}, /* EA_MODE_DI   */\r
+       { 0, 16, 20}, /* EA_MODE_IX   */\r
+       { 0, 12, 16}, /* EA_MODE_AW   */\r
+       { 0, 16, 20}, /* EA_MODE_AL   */\r
+       { 0,  0,  0}, /* EA_MODE_PCDI */\r
+       { 0,  0,  0}, /* EA_MODE_PCIX */\r
+       { 0,  0,  0}, /* EA_MODE_I    */\r
+};\r
+\r
+/* Extra cycles for CLR instruction (010) */\r
+int g_clr_cycle_table[13][3] =\r
+{\r
+       { 0,  0,  0}, /* EA_MODE_NONE */\r
+       { 0,  4,  6}, /* EA_MODE_AI   */\r
+       { 0,  4,  6}, /* EA_MODE_PI   */\r
+       { 0,  4,  6}, /* EA_MODE_PI7  */\r
+       { 0,  6,  8}, /* EA_MODE_PD   */\r
+       { 0,  6,  8}, /* EA_MODE_PD7  */\r
+       { 0,  8, 10}, /* EA_MODE_DI   */\r
+       { 0, 10, 14}, /* EA_MODE_IX   */\r
+       { 0,  8, 10}, /* EA_MODE_AW   */\r
+       { 0, 10, 14}, /* EA_MODE_AL   */\r
+       { 0,  0,  0}, /* EA_MODE_PCDI */\r
+       { 0,  0,  0}, /* EA_MODE_PCIX */\r
+       { 0,  0,  0}, /* EA_MODE_I    */\r
+};\r
+\r
+\r
+\r
+/* ======================================================================== */\r
+/* =========================== UTILITY FUNCTIONS ========================== */\r
+/* ======================================================================== */\r
+\r
+/* Print an error message and exit with status error */\r
+void error_exit(const char* fmt, ...)\r
+{\r
+       va_list args;\r
+       fprintf(stderr, "In %s, near or on line %d:\n\t", g_input_filename, g_line_number);\r
+       va_start(args, fmt);\r
+       vfprintf(stderr, fmt, args);\r
+       va_end(args);\r
+       fprintf(stderr, "\n");\r
+\r
+       if(g_prototype_file) fclose(g_prototype_file);\r
+       if(g_table_file) fclose(g_table_file);\r
+       if(g_ops_ac_file) fclose(g_ops_ac_file);\r
+       if(g_ops_dm_file) fclose(g_ops_dm_file);\r
+       if(g_ops_nz_file) fclose(g_ops_nz_file);\r
+       if(g_input_file) fclose(g_input_file);\r
+\r
+       exit(EXIT_FAILURE);\r
+}\r
+\r
+/* Print an error message, call perror(), and exit with status error */\r
+void perror_exit(const char* fmt, ...)\r
+{\r
+       va_list args;\r
+       va_start(args, fmt);\r
+       vfprintf(stderr, fmt, args);\r
+       va_end(args);\r
+       perror("");\r
+\r
+       if(g_prototype_file) fclose(g_prototype_file);\r
+       if(g_table_file) fclose(g_table_file);\r
+       if(g_ops_ac_file) fclose(g_ops_ac_file);\r
+       if(g_ops_dm_file) fclose(g_ops_dm_file);\r
+       if(g_ops_nz_file) fclose(g_ops_nz_file);\r
+       if(g_input_file) fclose(g_input_file);\r
+\r
+       exit(EXIT_FAILURE);\r
+}\r
+\r
+\r
+/* copy until 0 or space and exit with error if we read too far */\r
+int check_strsncpy(char* dst, char* src, int maxlength)\r
+{\r
+       char* p = dst;\r
+       while(*src && *src != ' ')\r
+       {\r
+               *p++ = *src++;\r
+               if(p - dst > maxlength)\r
+                       error_exit("Field too long");\r
+       }\r
+       *p = 0;\r
+       return p - dst;\r
+}\r
+\r
+/* copy until 0 or specified character and exit with error if we read too far */\r
+int check_strcncpy(char* dst, char* src, char delim, int maxlength)\r
+{\r
+       char* p = dst;\r
+       while(*src && *src != delim)\r
+       {\r
+               *p++ = *src++;\r
+               if(p - dst > maxlength)\r
+                       error_exit("Field too long");\r
+       }\r
+       *p = 0;\r
+       return p - dst;\r
+}\r
+\r
+/* convert ascii to integer and exit with error if we find invalid data */\r
+int check_atoi(char* str, int *result)\r
+{\r
+       int accum = 0;\r
+       char* p = str;\r
+       while(*p >= '0' && *p <= '9')\r
+       {\r
+               accum *= 10;\r
+               accum += *p++ - '0';\r
+       }\r
+       if(*p != ' ' && *p != 0)\r
+               error_exit("Malformed integer value (%c)", *p);\r
+       *result = accum;\r
+       return p - str;\r
+}\r
+\r
+/* Skip past spaces in a string */\r
+int skip_spaces(char* str)\r
+{\r
+       char* p = str;\r
+\r
+       while(*p == ' ')\r
+               p++;\r
+\r
+       return p - str;\r
+}\r
+\r
+/* Count the number of set bits in a value */\r
+int num_bits(int value)\r
+{\r
+    value = ((value & 0xaaaa) >> 1) + (value & 0x5555);\r
+    value = ((value & 0xcccc) >> 2) + (value & 0x3333);\r
+    value = ((value & 0xf0f0) >> 4) + (value & 0x0f0f);\r
+    value = ((value & 0xff00) >> 8) + (value & 0x00ff);\r
+       return value;\r
+}\r
+\r
+/* Convert a hex value written in ASCII */\r
+int atoh(char* buff)\r
+{\r
+       int accum = 0;\r
+\r
+       for(;;buff++)\r
+       {\r
+               if(*buff >= '0' && *buff <= '9')\r
+               {\r
+                       accum <<= 4;\r
+                       accum += *buff - '0';\r
+               }\r
+               else if(*buff >= 'a' && *buff <= 'f')\r
+               {\r
+                       accum <<= 4;\r
+                       accum += *buff - 'a' + 10;\r
+               }\r
+               else break;\r
+       }\r
+       return accum;\r
+}\r
+\r
+/* Get a line of text from a file, discarding any end-of-line characters */\r
+int fgetline(char* buff, int nchars, FILE* file)\r
+{\r
+       int length;\r
+\r
+       if(fgets(buff, nchars, file) == NULL)\r
+               return -1;\r
+       if(buff[0] == '\r')\r
+               memcpy(buff, buff + 1, nchars - 1);\r
+\r
+       length = strlen(buff);\r
+       while(length && (buff[length-1] == '\r' || buff[length-1] == '\n'))\r
+               length--;\r
+       buff[length] = 0;\r
+       g_line_number++;\r
+\r
+       return length;\r
+}\r
+\r
+\r
+\r
+/* ======================================================================== */\r
+/* =========================== HELPER FUNCTIONS =========================== */\r
+/* ======================================================================== */\r
+\r
+/* Calculate the number of cycles an opcode requires */\r
+int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type)\r
+{\r
+       int size = g_size_select_table[op->size];\r
+\r
+       if(op->cpus[cpu_type] == '.')\r
+               return 0;\r
+\r
+       if(cpu_type < CPU_TYPE_020)\r
+       {\r
+               if(cpu_type == CPU_TYPE_010)\r
+               {\r
+                       if(strcmp(op->name, "moves") == 0)\r
+                               return op->cycles[cpu_type] + g_moves_cycle_table[ea_mode][size];\r
+                       if(strcmp(op->name, "clr") == 0)\r
+                               return op->cycles[cpu_type] + g_clr_cycle_table[ea_mode][size];\r
+               }\r
+\r
+               /* ASG: added these cases -- immediate modes take 2 extra cycles here */\r
+               /* SV: but only when operating on long, and also on register direct mode */\r
+               if(cpu_type == CPU_TYPE_000 && (ea_mode == EA_MODE_I || ea_mode == EA_MODE_NONE) && op->size == 32 &&\r
+                  ((strcmp(op->name, "add") == 0 && strcmp(op->spec_proc, "er") == 0) ||\r
+                       strcmp(op->name, "adda")   == 0                                    ||\r
+                       (strcmp(op->name, "and") == 0 && strcmp(op->spec_proc, "er") == 0) ||\r
+                       (strcmp(op->name, "or") == 0 && strcmp(op->spec_proc, "er") == 0)  ||\r
+                       (strcmp(op->name, "sub") == 0 && strcmp(op->spec_proc, "er") == 0) ||\r
+                       strcmp(op->name, "suba")   == 0))\r
+                       return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size] + 2;\r
+\r
+               if(strcmp(op->name, "jmp") == 0)\r
+                       return op->cycles[cpu_type] + g_jmp_cycle_table[ea_mode];\r
+               if(strcmp(op->name, "jsr") == 0)\r
+                       return op->cycles[cpu_type] + g_jsr_cycle_table[ea_mode];\r
+               if(strcmp(op->name, "lea") == 0)\r
+                       return op->cycles[cpu_type] + g_lea_cycle_table[ea_mode];\r
+               if(strcmp(op->name, "pea") == 0)\r
+                       return op->cycles[cpu_type] + g_pea_cycle_table[ea_mode];\r
+               if(strcmp(op->name, "movem") == 0)\r
+                       return op->cycles[cpu_type] + g_movem_cycle_table[ea_mode];\r
+       }\r
+       return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size];\r
+}\r
+\r
+/* Find an opcode in the opcode handler list */\r
+opcode_struct* find_opcode(char* name, int size, char* spec_proc, char* spec_ea)\r
+{\r
+       opcode_struct* op;\r
+\r
+\r
+       for(op = g_opcode_input_table;op->name != NULL;op++)\r
+       {\r
+               if(     strcmp(name, op->name) == 0 &&\r
+                       (size == op->size) &&\r
+                       strcmp(spec_proc, op->spec_proc) == 0 &&\r
+                       strcmp(spec_ea, op->spec_ea) == 0)\r
+                               return op;\r
+       }\r
+       return NULL;\r
+}\r
+\r
+/* Specifically find the illegal opcode in the list */\r
+opcode_struct* find_illegal_opcode(void)\r
+{\r
+       opcode_struct* op;\r
+\r
+       for(op = g_opcode_input_table;op->name != NULL;op++)\r
+       {\r
+               if(strcmp(op->name, "illegal") == 0)\r
+                       return op;\r
+       }\r
+       return NULL;\r
+}\r
+\r
+/* Parse an opcode handler name */\r
+int extract_opcode_info(char* src, char* name, int* size, char* spec_proc, char* spec_ea)\r
+{\r
+       char* ptr = strstr(src, ID_OPHANDLER_NAME);\r
+\r
+       if(ptr == NULL)\r
+               return 0;\r
+\r
+       ptr += strlen(ID_OPHANDLER_NAME) + 1;\r
+\r
+       ptr += check_strcncpy(name, ptr, ',', MAX_NAME_LENGTH);\r
+       if(*ptr != ',') return 0;\r
+       ptr++;\r
+       ptr += skip_spaces(ptr);\r
+\r
+       *size = atoi(ptr);\r
+       ptr = strstr(ptr, ",");\r
+       if(ptr == NULL) return 0;\r
+    ptr++;\r
+       ptr += skip_spaces(ptr);\r
+\r
+       ptr += check_strcncpy(spec_proc, ptr, ',', MAX_SPEC_PROC_LENGTH);\r
+       if(*ptr != ',') return 0;\r
+       ptr++;\r
+       ptr += skip_spaces(ptr);\r
+\r
+       ptr += check_strcncpy(spec_ea, ptr, ')', MAX_SPEC_EA_LENGTH);\r
+       if(*ptr != ')') return 0;\r
+       ptr++;\r
+       ptr += skip_spaces(ptr);\r
+\r
+       return 1;\r
+}\r
+\r
+\r
+/* Add a search/replace pair to a replace structure */\r
+void add_replace_string(replace_struct* replace, const char* search_str, const char* replace_str)\r
+{\r
+       if(replace->length >= MAX_REPLACE_LENGTH)\r
+               error_exit("overflow in replace structure");\r
+\r
+       strcpy(replace->replace[replace->length][0], search_str);\r
+       strcpy(replace->replace[replace->length++][1], replace_str);\r
+}\r
+\r
+/* Write a function body while replacing any selected strings */\r
+void write_body(FILE* filep, body_struct* body, replace_struct* replace)\r
+{\r
+       int i;\r
+       int j;\r
+       char* ptr;\r
+       char output[MAX_LINE_LENGTH+1];\r
+       char temp_buff[MAX_LINE_LENGTH+1];\r
+       int found;\r
+\r
+       for(i=0;i<body->length;i++)\r
+       {\r
+               strcpy(output, body->body[i]);\r
+               /* Check for the base directive header */\r
+               if(strstr(output, ID_BASE) != NULL)\r
+               {\r
+                       /* Search for any text we need to replace */\r
+                       found = 0;\r
+                       for(j=0;j<replace->length;j++)\r
+                       {\r
+                               ptr = strstr(output, replace->replace[j][0]);\r
+                               if(ptr)\r
+                               {\r
+                                       /* We found something to replace */\r
+                                       found = 1;\r
+                                       strcpy(temp_buff, ptr+strlen(replace->replace[j][0]));\r
+                                       strcpy(ptr, replace->replace[j][1]);\r
+                                       strcat(ptr, temp_buff);\r
+                               }\r
+                       }\r
+                       /* Found a directive with no matching replace string */\r
+                       if(!found)\r
+                               error_exit("Unknown " ID_BASE " directive");\r
+               }\r
+               fprintf(filep, "%s\n", output);\r
+       }\r
+       fprintf(filep, "\n\n");\r
+}\r
+\r
+/* Generate a base function name from an opcode struct */\r
+void get_base_name(char* base_name, opcode_struct* op)\r
+{\r
+       sprintf(base_name, "m68k_op_%s", op->name);\r
+       if(op->size > 0)\r
+               sprintf(base_name+strlen(base_name), "_%d", op->size);\r
+       if(strcmp(op->spec_proc, UNSPECIFIED) != 0)\r
+               sprintf(base_name+strlen(base_name), "_%s", op->spec_proc);\r
+       if(strcmp(op->spec_ea, UNSPECIFIED) != 0)\r
+               sprintf(base_name+strlen(base_name), "_%s", op->spec_ea);\r
+}\r
+\r
+/* Write the prototype of an opcode handler function */\r
+void write_prototype(FILE* filep, char* base_name)\r
+{\r
+       fprintf(filep, "void %s(void);\n", base_name);\r
+}\r
+\r
+/* Write the name of an opcode handler function */\r
+void write_function_name(FILE* filep, char* base_name)\r
+{\r
+       fprintf(filep, "void %s(void)\n", base_name);\r
+}\r
+\r
+void add_opcode_output_table_entry(opcode_struct* op, char* name)\r
+{\r
+       opcode_struct* ptr;\r
+       if(g_opcode_output_table_length > MAX_OPCODE_OUTPUT_TABLE_LENGTH)\r
+               error_exit("Opcode output table overflow");\r
+\r
+       ptr = g_opcode_output_table + g_opcode_output_table_length++;\r
+\r
+       *ptr = *op;\r
+       strcpy(ptr->name, name);\r
+       ptr->bits = num_bits(ptr->op_mask);\r
+}\r
+\r
+/*\r
+ * Comparison function for qsort()\r
+ * For entries with an equal number of set bits in\r
+ * the mask compare the match values\r
+ */\r
+static int DECL_SPEC compare_nof_true_bits(const void* aptr, const void* bptr)\r
+{\r
+       const opcode_struct *a = aptr, *b = bptr;\r
+       if(a->bits != b->bits)\r
+               return a->bits - b->bits;\r
+       if(a->op_mask != b->op_mask)\r
+               return a->op_mask - b->op_mask;\r
+       return a->op_match - b->op_match;\r
+}\r
+\r
+void print_opcode_output_table(FILE* filep)\r
+{\r
+       int i;\r
+       qsort((void *)g_opcode_output_table, g_opcode_output_table_length, sizeof(g_opcode_output_table[0]), compare_nof_true_bits);\r
+\r
+       for(i=0;i<g_opcode_output_table_length;i++)\r
+               write_table_entry(filep, g_opcode_output_table+i);\r
+}\r
+\r
+/* Write an entry in the opcode handler table */\r
+void write_table_entry(FILE* filep, opcode_struct* op)\r
+{\r
+       int i;\r
+\r
+       fprintf(filep, "\t{%-28s, 0x%04x, 0x%04x, {",\r
+               op->name, op->op_mask, op->op_match);\r
+\r
+       for(i=0;i<NUM_CPUS;i++)\r
+       {\r
+               fprintf(filep, "%3d", op->cycles[i]);\r
+               if(i < NUM_CPUS-1)\r
+                       fprintf(filep, ", ");\r
+       }\r
+\r
+       fprintf(filep, "}},\n");\r
+}\r
+\r
+/* Fill out an opcode struct with a specific addressing mode of the source opcode struct */\r
+void set_opcode_struct(opcode_struct* src, opcode_struct* dst, int ea_mode)\r
+{\r
+       int i;\r
+\r
+       *dst = *src;\r
+\r
+       for(i=0;i<NUM_CPUS;i++)\r
+               dst->cycles[i] = get_oper_cycles(dst, ea_mode, i);\r
+       if(strcmp(dst->spec_ea, UNSPECIFIED) == 0 && ea_mode != EA_MODE_NONE)\r
+               sprintf(dst->spec_ea, "%s", g_ea_info_table[ea_mode].fname_add);\r
+       dst->op_mask |= g_ea_info_table[ea_mode].mask_add;\r
+       dst->op_match |= g_ea_info_table[ea_mode].match_add;\r
+}\r
+\r
+\r
+/* Generate a final opcode handler from the provided data */\r
+void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* opinfo, int ea_mode)\r
+{\r
+       char str[MAX_LINE_LENGTH+1];\r
+       opcode_struct* op = malloc(sizeof(opcode_struct));\r
+\r
+       /* Set the opcode structure and write the tables, prototypes, etc */\r
+       set_opcode_struct(opinfo, op, ea_mode);\r
+       get_base_name(str, op);\r
+       write_prototype(g_prototype_file, str);\r
+       add_opcode_output_table_entry(op, str);\r
+       write_function_name(filep, str);\r
+\r
+       /* Add any replace strings needed */\r
+       if(ea_mode != EA_MODE_NONE)\r
+       {\r
+               sprintf(str, "EA_%s_8()", g_ea_info_table[ea_mode].ea_add);\r
+               add_replace_string(replace, ID_OPHANDLER_EA_AY_8, str);\r
+               sprintf(str, "EA_%s_16()", g_ea_info_table[ea_mode].ea_add);\r
+               add_replace_string(replace, ID_OPHANDLER_EA_AY_16, str);\r
+               sprintf(str, "EA_%s_32()", g_ea_info_table[ea_mode].ea_add);\r
+               add_replace_string(replace, ID_OPHANDLER_EA_AY_32, str);\r
+               sprintf(str, "OPER_%s_8()", g_ea_info_table[ea_mode].ea_add);\r
+               add_replace_string(replace, ID_OPHANDLER_OPER_AY_8, str);\r
+               sprintf(str, "OPER_%s_16()", g_ea_info_table[ea_mode].ea_add);\r
+               add_replace_string(replace, ID_OPHANDLER_OPER_AY_16, str);\r
+               sprintf(str, "OPER_%s_32()", g_ea_info_table[ea_mode].ea_add);\r
+               add_replace_string(replace, ID_OPHANDLER_OPER_AY_32, str);\r
+       }\r
+\r
+       /* Now write the function body with the selected replace strings */\r
+       write_body(filep, body, replace);\r
+       g_num_functions++;\r
+       free(op);\r
+}\r
+\r
+/* Generate opcode variants based on available addressing modes */\r
+void generate_opcode_ea_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op)\r
+{\r
+       int old_length = replace->length;\r
+\r
+       /* No ea modes available for this opcode */\r
+       if(HAS_NO_EA_MODE(op->ea_allowed))\r
+       {\r
+               generate_opcode_handler(filep, body, replace, op, EA_MODE_NONE);\r
+               return;\r
+       }\r
+\r
+       /* Check for and create specific opcodes for each available addressing mode */\r
+       if(HAS_EA_AI(op->ea_allowed))\r
+               generate_opcode_handler(filep, body, replace, op, EA_MODE_AI);\r
+       replace->length = old_length;\r
+       if(HAS_EA_PI(op->ea_allowed))\r
+       {\r
+               generate_opcode_handler(filep, body, replace, op, EA_MODE_PI);\r
+               replace->length = old_length;\r
+               if(op->size == 8)\r
+                       generate_opcode_handler(filep, body, replace, op, EA_MODE_PI7);\r
+       }\r
+       replace->length = old_length;\r
+       if(HAS_EA_PD(op->ea_allowed))\r
+       {\r
+               generate_opcode_handler(filep, body, replace, op, EA_MODE_PD);\r
+               replace->length = old_length;\r
+               if(op->size == 8)\r
+                       generate_opcode_handler(filep, body, replace, op, EA_MODE_PD7);\r
+       }\r
+       replace->length = old_length;\r
+       if(HAS_EA_DI(op->ea_allowed))\r
+               generate_opcode_handler(filep, body, replace, op, EA_MODE_DI);\r
+       replace->length = old_length;\r
+       if(HAS_EA_IX(op->ea_allowed))\r
+               generate_opcode_handler(filep, body, replace, op, EA_MODE_IX);\r
+       replace->length = old_length;\r
+       if(HAS_EA_AW(op->ea_allowed))\r
+               generate_opcode_handler(filep, body, replace, op, EA_MODE_AW);\r
+       replace->length = old_length;\r
+       if(HAS_EA_AL(op->ea_allowed))\r
+               generate_opcode_handler(filep, body, replace, op, EA_MODE_AL);\r
+       replace->length = old_length;\r
+       if(HAS_EA_PCDI(op->ea_allowed))\r
+               generate_opcode_handler(filep, body, replace, op, EA_MODE_PCDI);\r
+       replace->length = old_length;\r
+       if(HAS_EA_PCIX(op->ea_allowed))\r
+               generate_opcode_handler(filep, body, replace, op, EA_MODE_PCIX);\r
+       replace->length = old_length;\r
+       if(HAS_EA_I(op->ea_allowed))\r
+               generate_opcode_handler(filep, body, replace, op, EA_MODE_I);\r
+       replace->length = old_length;\r
+}\r
+\r
+/* Generate variants of condition code opcodes */\r
+void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op_in, int offset)\r
+{\r
+       char repl[20];\r
+       char replnot[20];\r
+       int i;\r
+       int old_length = replace->length;\r
+       opcode_struct* op = malloc(sizeof(opcode_struct));\r
+\r
+       *op = *op_in;\r
+\r
+       op->op_mask |= 0x0f00;\r
+\r
+       /* Do all condition codes except t and f */\r
+       for(i=2;i<16;i++)\r
+       {\r
+               /* Add replace strings for this condition code */\r
+               sprintf(repl, "COND_%s()", g_cc_table[i][1]);\r
+               sprintf(replnot, "COND_NOT_%s()", g_cc_table[i][1]);\r
+\r
+               add_replace_string(replace, ID_OPHANDLER_CC, repl);\r
+               add_replace_string(replace, ID_OPHANDLER_NOT_CC, replnot);\r
+\r
+               /* Set the new opcode info */\r
+               strcpy(op->name+offset, g_cc_table[i][0]);\r
+\r
+               op->op_match = (op->op_match & 0xf0ff) | (i<<8);\r
+\r
+               /* Generate all opcode variants for this modified opcode */\r
+               generate_opcode_ea_variants(filep, body, replace, op);\r
+               /* Remove the above replace strings */\r
+               replace->length = old_length;\r
+       }\r
+       free(op);\r
+}\r
+\r
+/* Process the opcode handlers section of the input file */\r
+void process_opcode_handlers(void)\r
+{\r
+       FILE* input_file = g_input_file;\r
+       FILE* output_file;\r
+       char func_name[MAX_LINE_LENGTH+1];\r
+       char oper_name[MAX_LINE_LENGTH+1];\r
+       int  oper_size;\r
+       char oper_spec_proc[MAX_LINE_LENGTH+1];\r
+       char oper_spec_ea[MAX_LINE_LENGTH+1];\r
+       opcode_struct* opinfo;\r
+       replace_struct* replace = malloc(sizeof(replace_struct));\r
+       body_struct* body = malloc(sizeof(body_struct));\r
+\r
+\r
+       output_file = g_ops_ac_file;\r
+\r
+       for(;;)\r
+       {\r
+               /* Find the first line of the function */\r
+               func_name[0] = 0;\r
+               while(strstr(func_name, ID_OPHANDLER_NAME) == NULL)\r
+               {\r
+                       if(strcmp(func_name, ID_INPUT_SEPARATOR) == 0)\r
+                       {\r
+                               free(replace);\r
+                               free(body);\r
+                               return; /* all done */\r
+                       }\r
+                       if(fgetline(func_name, MAX_LINE_LENGTH, input_file) < 0)\r
+                               error_exit("Premature end of file when getting function name");\r
+               }\r
+               /* Get the rest of the function */\r
+               for(body->length=0;;body->length++)\r
+               {\r
+                       if(body->length > MAX_BODY_LENGTH)\r
+                               error_exit("Function too long");\r
+\r
+                       if(fgetline(body->body[body->length], MAX_LINE_LENGTH, input_file) < 0)\r
+                               error_exit("Premature end of file when getting function body");\r
+\r
+                       if(body->body[body->length][0] == '}')\r
+                       {\r
+                               body->length++;\r
+                               break;\r
+                       }\r
+               }\r
+\r
+               g_num_primitives++;\r
+\r
+               /* Extract the function name information */\r
+               if(!extract_opcode_info(func_name, oper_name, &oper_size, oper_spec_proc, oper_spec_ea))\r
+                       error_exit("Invalid " ID_OPHANDLER_NAME " format");\r
+\r
+               /* Find the corresponding table entry */\r
+               opinfo = find_opcode(oper_name, oper_size, oper_spec_proc, oper_spec_ea);\r
+               if(opinfo == NULL)\r
+                       error_exit("Unable to find matching table entry for %s", func_name);\r
+\r
+        /* Change output files if we pass 'c' or 'n' */\r
+               if(output_file == g_ops_ac_file && oper_name[0] > 'c')\r
+                       output_file = g_ops_dm_file;\r
+               else if(output_file == g_ops_dm_file && oper_name[0] > 'm')\r
+                       output_file = g_ops_nz_file;\r
+\r
+               replace->length = 0;\r
+\r
+               /* Generate opcode variants */\r
+               if(strcmp(opinfo->name, "bcc") == 0 || strcmp(opinfo->name, "scc") == 0)\r
+                       generate_opcode_cc_variants(output_file, body, replace, opinfo, 1);\r
+               else if(strcmp(opinfo->name, "dbcc") == 0)\r
+                       generate_opcode_cc_variants(output_file, body, replace, opinfo, 2);\r
+               else if(strcmp(opinfo->name, "trapcc") == 0)\r
+                       generate_opcode_cc_variants(output_file, body, replace, opinfo, 4);\r
+               else\r
+                       generate_opcode_ea_variants(output_file, body, replace, opinfo);\r
+       }\r
+\r
+       free(replace);\r
+       free(body);\r
+}\r
+\r
+\r
+/* Populate the opcode handler table from the input file */\r
+void populate_table(void)\r
+{\r
+       char* ptr;\r
+       char bitpattern[17];\r
+       opcode_struct* op;\r
+       char buff[MAX_LINE_LENGTH];\r
+       int i;\r
+       int temp;\r
+\r
+       buff[0] = 0;\r
+\r
+       /* Find the start of the table */\r
+       while(strcmp(buff, ID_TABLE_START) != 0)\r
+               if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0)\r
+                       error_exit("Premature EOF while reading table");\r
+\r
+       /* Process the entire table */\r
+       for(op = g_opcode_input_table;;op++)\r
+       {\r
+               if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0)\r
+                       error_exit("Premature EOF while reading table");\r
+               if(strlen(buff) == 0)\r
+                       continue;\r
+               /* We finish when we find an input separator */\r
+               if(strcmp(buff, ID_INPUT_SEPARATOR) == 0)\r
+                       break;\r
+\r
+               /* Extract the info from the table */\r
+               ptr = buff;\r
+\r
+               /* Name */\r
+               ptr += skip_spaces(ptr);\r
+               ptr += check_strsncpy(op->name, ptr, MAX_NAME_LENGTH);\r
+\r
+               /* Size */\r
+               ptr += skip_spaces(ptr);\r
+               ptr += check_atoi(ptr, &temp);\r
+               op->size = (unsigned char)temp;\r
+\r
+               /* Special processing */\r
+               ptr += skip_spaces(ptr);\r
+               ptr += check_strsncpy(op->spec_proc, ptr, MAX_SPEC_PROC_LENGTH);\r
+\r
+               /* Specified EA Mode */\r
+               ptr += skip_spaces(ptr);\r
+               ptr += check_strsncpy(op->spec_ea, ptr, MAX_SPEC_EA_LENGTH);\r
+\r
+               /* Bit Pattern (more processing later) */\r
+               ptr += skip_spaces(ptr);\r
+               ptr += check_strsncpy(bitpattern, ptr, 17);\r
+\r
+               /* Allowed Addressing Mode List */\r
+               ptr += skip_spaces(ptr);\r
+               ptr += check_strsncpy(op->ea_allowed, ptr, EA_ALLOWED_LENGTH);\r
+\r
+               /* CPU operating mode (U = user or supervisor, S = supervisor only */\r
+               ptr += skip_spaces(ptr);\r
+               for(i=0;i<NUM_CPUS;i++)\r
+               {\r
+                       op->cpu_mode[i] = *ptr++;\r
+                       ptr += skip_spaces(ptr);\r
+               }\r
+\r
+               /* Allowed CPUs for this instruction */\r
+               for(i=0;i<NUM_CPUS;i++)\r
+               {\r
+                       ptr += skip_spaces(ptr);\r
+                       if(*ptr == UNSPECIFIED_CH)\r
+                       {\r
+                               op->cpus[i] = UNSPECIFIED_CH;\r
+                               op->cycles[i] = 0;\r
+                               ptr++;\r
+                       }\r
+                       else\r
+                       {\r
+                               op->cpus[i] = '0' + i;\r
+                               ptr += check_atoi(ptr, &temp);\r
+                               op->cycles[i] = (unsigned char)temp;\r
+                       }\r
+               }\r
+\r
+               /* generate mask and match from bitpattern */\r
+               op->op_mask = 0;\r
+               op->op_match = 0;\r
+               for(i=0;i<16;i++)\r
+               {\r
+                       op->op_mask |= (bitpattern[i] != '.') << (15-i);\r
+                       op->op_match |= (bitpattern[i] == '1') << (15-i);\r
+               }\r
+       }\r
+       /* Terminate the list */\r
+       op->name[0] = 0;\r
+}\r
+\r
+/* Read a header or footer insert from the input file */\r
+void read_insert(char* insert)\r
+{\r
+       char* ptr = insert;\r
+       char* overflow = insert + MAX_INSERT_LENGTH - MAX_LINE_LENGTH;\r
+       int length;\r
+       char* first_blank = NULL;\r
+\r
+       first_blank = NULL;\r
+\r
+       /* Skip any leading blank lines */\r
+       for(length = 0;length == 0;length = fgetline(ptr, MAX_LINE_LENGTH, g_input_file))\r
+               if(ptr >= overflow)\r
+                       error_exit("Buffer overflow reading inserts");\r
+       if(length < 0)\r
+               error_exit("Premature EOF while reading inserts");\r
+\r
+       /* Advance and append newline */\r
+       ptr += length;\r
+       strcpy(ptr++, "\n");\r
+\r
+       /* Read until next separator */\r
+       for(;;)\r
+       {\r
+               /* Read a new line */\r
+               if(ptr >= overflow)\r
+                       error_exit("Buffer overflow reading inserts");\r
+               if((length = fgetline(ptr, MAX_LINE_LENGTH, g_input_file)) < 0)\r
+                       error_exit("Premature EOF while reading inserts");\r
+\r
+               /* Stop if we read a separator */\r
+               if(strcmp(ptr, ID_INPUT_SEPARATOR) == 0)\r
+                       break;\r
+\r
+               /* keep track in case there are trailing blanks */\r
+               if(length == 0)\r
+               {\r
+                       if(first_blank == NULL)\r
+                               first_blank = ptr;\r
+               }\r
+               else\r
+                       first_blank = NULL;\r
+\r
+               /* Advance and append newline */\r
+               ptr += length;\r
+               strcpy(ptr++, "\n");\r
+       }\r
+\r
+       /* kill any trailing blank lines */\r
+       if(first_blank)\r
+               ptr = first_blank;\r
+       *ptr++ = 0;\r
+}\r
+\r
+\r
+\r
+/* ======================================================================== */\r
+/* ============================= MAIN FUNCTION ============================ */\r
+/* ======================================================================== */\r
+\r
+int main(int argc, char **argv)\r
+{\r
+       /* File stuff */\r
+       char output_path[M68K_MAX_DIR] = "";\r
+       char filename[M68K_MAX_PATH];\r
+       /* Section identifier */\r
+       char section_id[MAX_LINE_LENGTH+1];\r
+       /* Inserts */\r
+       char temp_insert[MAX_INSERT_LENGTH+1];\r
+       char prototype_footer_insert[MAX_INSERT_LENGTH+1];\r
+       char table_footer_insert[MAX_INSERT_LENGTH+1];\r
+       char ophandler_footer_insert[MAX_INSERT_LENGTH+1];\r
+       /* Flags if we've processed certain parts already */\r
+       int prototype_header_read = 0;\r
+       int prototype_footer_read = 0;\r
+       int table_header_read = 0;\r
+       int table_footer_read = 0;\r
+       int ophandler_header_read = 0;\r
+       int ophandler_footer_read = 0;\r
+       int table_body_read = 0;\r
+       int ophandler_body_read = 0;\r
+\r
+       printf("\n\t\tMusashi v%s 68000, 68008, 68010, 68EC020, 68020 emulator\n", g_version);\r
+       printf("\t\tCopyright 1998-2000 Karl Stenerud (karl@mame.net)\n\n");\r
+\r
+       /* Check if output path and source for the input file are given */\r
+    if(argc > 1)\r
+       {\r
+               char *ptr;\r
+               strcpy(output_path, argv[1]);\r
+\r
+               for(ptr = strchr(output_path, '\\'); ptr; ptr = strchr(ptr, '\\'))\r
+                       *ptr = '/';\r
+\r
+#if !(defined(__DECC) && defined(VMS))\r
+        if(output_path[strlen(output_path)-1] != '/')\r
+                       strcat(output_path, "/");\r
+#endif\r
+\r
+               if(argc > 2)\r
+                       strcpy(g_input_filename, argv[2]);\r
+       }\r
+\r
+\r
+#if defined(__DECC) && defined(VMS)\r
+\r
+       /* Open the files we need */\r
+       sprintf(filename, "%s%s", output_path, FILENAME_PROTOTYPE);\r
+       if((g_prototype_file = fopen(filename, "w")) == NULL)\r
+               perror_exit("Unable to create prototype file (%s)\n", filename);\r
+\r
+       sprintf(filename, "%s%s", output_path, FILENAME_TABLE);\r
+       if((g_table_file = fopen(filename, "w")) == NULL)\r
+               perror_exit("Unable to create table file (%s)\n", filename);\r
+\r
+       sprintf(filename, "%s%s", output_path, FILENAME_OPS_AC);\r
+       if((g_ops_ac_file = fopen(filename, "w")) == NULL)\r
+               perror_exit("Unable to create ops ac file (%s)\n", filename);\r
+\r
+       sprintf(filename, "%s%s", output_path, FILENAME_OPS_DM);\r
+       if((g_ops_dm_file = fopen(filename, "w")) == NULL)\r
+               perror_exit("Unable to create ops dm file (%s)\n", filename);\r
+\r
+       sprintf(filename, "%s%s", output_path, FILENAME_OPS_NZ);\r
+       if((g_ops_nz_file = fopen(filename, "w")) == NULL)\r
+               perror_exit("Unable to create ops nz file (%s)\n", filename);\r
+\r
+       if((g_input_file=fopen(g_input_filename, "r")) == NULL)\r
+               perror_exit("can't open %s for input", g_input_filename);\r
+\r
+#else\r
+\r
+\r
+       /* Open the files we need */\r
+       sprintf(filename, "%s%s", output_path, FILENAME_PROTOTYPE);\r
+       if((g_prototype_file = fopen(filename, "wt")) == NULL)\r
+               perror_exit("Unable to create prototype file (%s)\n", filename);\r
+\r
+       sprintf(filename, "%s%s", output_path, FILENAME_TABLE);\r
+       if((g_table_file = fopen(filename, "wt")) == NULL)\r
+               perror_exit("Unable to create table file (%s)\n", filename);\r
+\r
+       sprintf(filename, "%s%s", output_path, FILENAME_OPS_AC);\r
+       if((g_ops_ac_file = fopen(filename, "wt")) == NULL)\r
+               perror_exit("Unable to create ops ac file (%s)\n", filename);\r
+\r
+       sprintf(filename, "%s%s", output_path, FILENAME_OPS_DM);\r
+       if((g_ops_dm_file = fopen(filename, "wt")) == NULL)\r
+               perror_exit("Unable to create ops dm file (%s)\n", filename);\r
+\r
+       sprintf(filename, "%s%s", output_path, FILENAME_OPS_NZ);\r
+       if((g_ops_nz_file = fopen(filename, "wt")) == NULL)\r
+               perror_exit("Unable to create ops nz file (%s)\n", filename);\r
+\r
+       if((g_input_file=fopen(g_input_filename, "rt")) == NULL)\r
+               perror_exit("can't open %s for input", g_input_filename);\r
+\r
+#endif\r
+\r
+       /* Get to the first section of the input file */\r
+       section_id[0] = 0;\r
+       while(strcmp(section_id, ID_INPUT_SEPARATOR) != 0)\r
+               if(fgetline(section_id, MAX_LINE_LENGTH, g_input_file) < 0)\r
+                       error_exit("Premature EOF while reading input file");\r
+\r
+       /* Now process all sections */\r
+       for(;;)\r
+       {\r
+               if(fgetline(section_id, MAX_LINE_LENGTH, g_input_file) < 0)\r
+                       error_exit("Premature EOF while reading input file");\r
+               if(strcmp(section_id, ID_PROTOTYPE_HEADER) == 0)\r
+               {\r
+                       if(prototype_header_read)\r
+                               error_exit("Duplicate prototype header");\r
+                       read_insert(temp_insert);\r
+                       fprintf(g_prototype_file, "%s\n\n", temp_insert);\r
+                       prototype_header_read = 1;\r
+               }\r
+               else if(strcmp(section_id, ID_TABLE_HEADER) == 0)\r
+               {\r
+                       if(table_header_read)\r
+                               error_exit("Duplicate table header");\r
+                       read_insert(temp_insert);\r
+                       fprintf(g_table_file, "%s", temp_insert);\r
+                       table_header_read = 1;\r
+               }\r
+               else if(strcmp(section_id, ID_OPHANDLER_HEADER) == 0)\r
+               {\r
+                       if(ophandler_header_read)\r
+                               error_exit("Duplicate opcode handler header");\r
+                       read_insert(temp_insert);\r
+                       fprintf(g_ops_ac_file, "%s\n\n", temp_insert);\r
+                       fprintf(g_ops_dm_file, "%s\n\n", temp_insert);\r
+                       fprintf(g_ops_nz_file, "%s\n\n", temp_insert);\r
+                       ophandler_header_read = 1;\r
+               }\r
+               else if(strcmp(section_id, ID_PROTOTYPE_FOOTER) == 0)\r
+               {\r
+                       if(prototype_footer_read)\r
+                               error_exit("Duplicate prototype footer");\r
+                       read_insert(prototype_footer_insert);\r
+                       prototype_footer_read = 1;\r
+               }\r
+               else if(strcmp(section_id, ID_TABLE_FOOTER) == 0)\r
+               {\r
+                       if(table_footer_read)\r
+                               error_exit("Duplicate table footer");\r
+                       read_insert(table_footer_insert);\r
+                       table_footer_read = 1;\r
+               }\r
+               else if(strcmp(section_id, ID_OPHANDLER_FOOTER) == 0)\r
+               {\r
+                       if(ophandler_footer_read)\r
+                               error_exit("Duplicate opcode handler footer");\r
+                       read_insert(ophandler_footer_insert);\r
+                       ophandler_footer_read = 1;\r
+               }\r
+               else if(strcmp(section_id, ID_TABLE_BODY) == 0)\r
+               {\r
+                       if(!prototype_header_read)\r
+                               error_exit("Table body encountered before prototype header");\r
+                       if(!table_header_read)\r
+                               error_exit("Table body encountered before table header");\r
+                       if(!ophandler_header_read)\r
+                               error_exit("Table body encountered before opcode handler header");\r
+\r
+                       if(table_body_read)\r
+                               error_exit("Duplicate table body");\r
+\r
+                       populate_table();\r
+                       table_body_read = 1;\r
+               }\r
+               else if(strcmp(section_id, ID_OPHANDLER_BODY) == 0)\r
+               {\r
+                       if(!prototype_header_read)\r
+                               error_exit("Opcode handlers encountered before prototype header");\r
+                       if(!table_header_read)\r
+                               error_exit("Opcode handlers encountered before table header");\r
+                       if(!ophandler_header_read)\r
+                               error_exit("Opcode handlers encountered before opcode handler header");\r
+                       if(!table_body_read)\r
+                               error_exit("Opcode handlers encountered before table body");\r
+\r
+                       if(ophandler_body_read)\r
+                               error_exit("Duplicate opcode handler section");\r
+\r
+                       process_opcode_handlers();\r
+\r
+                       ophandler_body_read = 1;\r
+               }\r
+               else if(strcmp(section_id, ID_END) == 0)\r
+               {\r
+                       /* End of input file.  Do a sanity check and then write footers */\r
+                       if(!prototype_header_read)\r
+                               error_exit("Missing prototype header");\r
+                       if(!prototype_footer_read)\r
+                               error_exit("Missing prototype footer");\r
+                       if(!table_header_read)\r
+                               error_exit("Missing table header");\r
+                       if(!table_footer_read)\r
+                               error_exit("Missing table footer");\r
+                       if(!table_body_read)\r
+                               error_exit("Missing table body");\r
+                       if(!ophandler_header_read)\r
+                               error_exit("Missing opcode handler header");\r
+                       if(!ophandler_footer_read)\r
+                               error_exit("Missing opcode handler footer");\r
+                       if(!ophandler_body_read)\r
+                               error_exit("Missing opcode handler body");\r
+\r
+                       print_opcode_output_table(g_table_file);\r
+\r
+                       fprintf(g_prototype_file, "%s\n\n", prototype_footer_insert);\r
+                       fprintf(g_table_file, "%s\n\n", table_footer_insert);\r
+                       fprintf(g_ops_ac_file, "%s\n\n", ophandler_footer_insert);\r
+                       fprintf(g_ops_dm_file, "%s\n\n", ophandler_footer_insert);\r
+                       fprintf(g_ops_nz_file, "%s\n\n", ophandler_footer_insert);\r
+\r
+                       break;\r
+               }\r
+               else\r
+               {\r
+                       error_exit("Unknown section identifier: %s", section_id);\r
+               }\r
+       }\r
+\r
+       /* Close all files and exit */\r
+       fclose(g_prototype_file);\r
+       fclose(g_table_file);\r
+       fclose(g_ops_ac_file);\r
+       fclose(g_ops_dm_file);\r
+       fclose(g_ops_nz_file);\r
+       fclose(g_input_file);\r
+\r
+       printf("Generated %d opcode handlers from %d primitives\n", g_num_functions, g_num_primitives);\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+\r
+/* ======================================================================== */\r
+/* ============================== END OF FILE ============================= */\r
+/* ======================================================================== */\r