src/musashi/m68kmake.c

Tue, 15 Nov 2011 10:12:37 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Tue, 15 Nov 2011 10:12:37 +0000
changeset 109
2f8afb9e5baa
parent 0
8bf1bf91a36d
permissions
-rw-r--r--

[musashi] Fix handling of bus errors

Patch-Author: Andrew Warkentin <andreww591!gmail>
Patch-MessageID: <4EC200CE.2020304@gmail.com>

I have fixed the first page fault test failure in FreeBee (the page fault test now hangs rather than errors out, because it is trying to read from the hard drive to test DMA page faults).

There were actually two bugs (the first bug was masking the second one).

First, the ancient version of Musashi that you used is unable to properly resume from bus errors that happen in the middle of certain instructions (some instructions are fetched in stages, with the PC being advanced to each part of the instruction, so basically what happens is the CPU core attempts to read the memory location referenced by the first operand, the bus error occurs, causing the PC to jump to the exception vector, but the faulting instruction is still in the middle of being fetched, so the PC is then advanced past the beginning of the exception handler). I fixed this by delaying the jump to the bus error vector until after the faulting instruction finishes.

The second bug is simpler - you had the UDS and LDS bits in BSR0 inverted (they are supposed to be active low).

     1 /* ======================================================================== */
     2 /* ========================= LICENSING & COPYRIGHT ======================== */
     3 /* ======================================================================== */
     4 /*
     5  *                                  MUSASHI
     6  *                                Version 3.3
     7  *
     8  * A portable Motorola M680x0 processor emulation engine.
     9  * Copyright 1998-2001 Karl Stenerud.  All rights reserved.
    10  *
    11  * This code may be freely used for non-commercial purposes as long as this
    12  * copyright notice remains unaltered in the source code and any binary files
    13  * containing this code in compiled form.
    14  *
    15  * All other lisencing terms must be negotiated with the author
    16  * (Karl Stenerud).
    17  *
    18  * The latest version of this code can be obtained at:
    19  * http://kstenerud.cjb.net
    20  */
    24 /* ======================================================================== */
    25 /* ============================ CODE GENERATOR ============================ */
    26 /* ======================================================================== */
    27 /*
    28  * This is the code generator program which will generate the opcode table
    29  * and the final opcode handlers.
    30  *
    31  * It requires an input file to function (default m68k_in.c), but you can
    32  * specify your own like so:
    33  *
    34  * m68kmake <output path> <input file>
    35  *
    36  * where output path is the path where the output files should be placed, and
    37  * input file is the file to use for input.
    38  *
    39  * If you modify the input file greatly from its released form, you may have
    40  * to tweak the configuration section a bit since I'm using static allocation
    41  * to keep things simple.
    42  *
    43  *
    44  * TODO: - build a better code generator for the move instruction.
    45  *       - Add callm and rtm instructions
    46  *       - Fix RTE to handle other format words
    47  *       - Add address error (and bus error?) handling
    48  */
    51 char* g_version = "3.3";
    53 /* ======================================================================== */
    54 /* =============================== INCLUDES =============================== */
    55 /* ======================================================================== */
    57 #include <stdio.h>
    58 #include <stdlib.h>
    59 #include <string.h>
    60 #include <ctype.h>
    61 #include <stdarg.h>
    65 /* ======================================================================== */
    66 /* ============================= CONFIGURATION ============================ */
    67 /* ======================================================================== */
    69 #define MAX_PATH 1024
    70 #define MAX_DIR  1024
    72 #define NUM_CPUS                          3	/* 000, 010, 020 */
    73 #define MAX_LINE_LENGTH                 200	/* length of 1 line */
    74 #define MAX_BODY_LENGTH                 300	/* Number of lines in 1 function */
    75 #define MAX_REPLACE_LENGTH               30	/* Max number of replace strings */
    76 #define MAX_INSERT_LENGTH              5000	/* Max size of insert piece */
    77 #define MAX_NAME_LENGTH                  30	/* Max length of ophandler name */
    78 #define MAX_SPEC_PROC_LENGTH              4	/* Max length of special processing str */
    79 #define MAX_SPEC_EA_LENGTH                5	/* Max length of specified EA str */
    80 #define EA_ALLOWED_LENGTH                11	/* Max length of ea allowed str */
    81 #define MAX_OPCODE_INPUT_TABLE_LENGTH  1000	/* Max length of opcode handler tbl */
    82 #define MAX_OPCODE_OUTPUT_TABLE_LENGTH 3000	/* Max length of opcode handler tbl */
    84 /* Default filenames */
    85 #define FILENAME_INPUT      "m68k_in.c"
    86 #define FILENAME_PROTOTYPE  "m68kops.h"
    87 #define FILENAME_TABLE      "m68kops.c"
    88 #define FILENAME_OPS_AC     "m68kopac.c"
    89 #define FILENAME_OPS_DM     "m68kopdm.c"
    90 #define FILENAME_OPS_NZ     "m68kopnz.c"
    93 /* Identifier sequences recognized by this program */
    95 #define ID_INPUT_SEPARATOR "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    97 #define ID_BASE                 "M68KMAKE"
    98 #define ID_PROTOTYPE_HEADER     ID_BASE "_PROTOTYPE_HEADER"
    99 #define ID_PROTOTYPE_FOOTER     ID_BASE "_PROTOTYPE_FOOTER"
   100 #define ID_TABLE_HEADER         ID_BASE "_TABLE_HEADER"
   101 #define ID_TABLE_FOOTER         ID_BASE "_TABLE_FOOTER"
   102 #define ID_TABLE_BODY           ID_BASE "_TABLE_BODY"
   103 #define ID_TABLE_START          ID_BASE "_TABLE_START"
   104 #define ID_OPHANDLER_HEADER     ID_BASE "_OPCODE_HANDLER_HEADER"
   105 #define ID_OPHANDLER_FOOTER     ID_BASE "_OPCODE_HANDLER_FOOTER"
   106 #define ID_OPHANDLER_BODY       ID_BASE "_OPCODE_HANDLER_BODY"
   107 #define ID_END                  ID_BASE "_END"
   109 #define ID_OPHANDLER_NAME       ID_BASE "_OP"
   110 #define ID_OPHANDLER_EA_AY_8    ID_BASE "_GET_EA_AY_8"
   111 #define ID_OPHANDLER_EA_AY_16   ID_BASE "_GET_EA_AY_16"
   112 #define ID_OPHANDLER_EA_AY_32   ID_BASE "_GET_EA_AY_32"
   113 #define ID_OPHANDLER_OPER_AY_8  ID_BASE "_GET_OPER_AY_8"
   114 #define ID_OPHANDLER_OPER_AY_16 ID_BASE "_GET_OPER_AY_16"
   115 #define ID_OPHANDLER_OPER_AY_32 ID_BASE "_GET_OPER_AY_32"
   116 #define ID_OPHANDLER_CC         ID_BASE "_CC"
   117 #define ID_OPHANDLER_NOT_CC     ID_BASE "_NOT_CC"
   120 #ifndef DECL_SPEC
   121 #define DECL_SPEC
   122 #endif /* DECL_SPEC */
   126 /* ======================================================================== */
   127 /* ============================== PROTOTYPES ============================== */
   128 /* ======================================================================== */
   130 #define CPU_TYPE_000 0
   131 #define CPU_TYPE_010 1
   132 #define CPU_TYPE_020 2
   134 #define UNSPECIFIED "."
   135 #define UNSPECIFIED_CH '.'
   137 #define HAS_NO_EA_MODE(A) (strcmp(A, "..........") == 0)
   138 #define HAS_EA_AI(A)   ((A)[0] == 'A')
   139 #define HAS_EA_PI(A)   ((A)[1] == '+')
   140 #define HAS_EA_PD(A)   ((A)[2] == '-')
   141 #define HAS_EA_DI(A)   ((A)[3] == 'D')
   142 #define HAS_EA_IX(A)   ((A)[4] == 'X')
   143 #define HAS_EA_AW(A)   ((A)[5] == 'W')
   144 #define HAS_EA_AL(A)   ((A)[6] == 'L')
   145 #define HAS_EA_PCDI(A) ((A)[7] == 'd')
   146 #define HAS_EA_PCIX(A) ((A)[8] == 'x')
   147 #define HAS_EA_I(A)    ((A)[9] == 'I')
   149 enum
   150 {
   151 	EA_MODE_NONE,	/* No special addressing mode */
   152 	EA_MODE_AI,		/* Address register indirect */
   153 	EA_MODE_PI,		/* Address register indirect with postincrement */
   154 	EA_MODE_PI7,	/* Address register 7 indirect with postincrement */
   155 	EA_MODE_PD,		/* Address register indirect with predecrement */
   156 	EA_MODE_PD7,	/* Address register 7 indirect with predecrement */
   157 	EA_MODE_DI,		/* Address register indirect with displacement */
   158 	EA_MODE_IX,		/* Address register indirect with index */
   159 	EA_MODE_AW,		/* Absolute word */
   160 	EA_MODE_AL,		/* Absolute long */
   161 	EA_MODE_PCDI,	/* Program counter indirect with displacement */
   162 	EA_MODE_PCIX,	/* Program counter indirect with index */
   163 	EA_MODE_I		/* Immediate */
   164 };
   167 /* Everything we need to know about an opcode */
   168 typedef struct
   169 {
   170 	char name[MAX_NAME_LENGTH];           /* opcode handler name */
   171 	unsigned int size;                    /* Size of operation */
   172 	char spec_proc[MAX_SPEC_PROC_LENGTH]; /* Special processing mode */
   173 	char spec_ea[MAX_SPEC_EA_LENGTH];     /* Specified effective addressing mode */
   174 	unsigned int bits;                    /* Number of significant bits (used for sorting the table) */
   175 	unsigned int op_mask;                 /* Mask to apply for matching an opcode to a handler */
   176 	unsigned int op_match;                /* Value to match after masking */
   177 	char ea_allowed[EA_ALLOWED_LENGTH];   /* Effective addressing modes allowed */
   178 	char cpu_mode[NUM_CPUS];              /* User or supervisor mode */
   179 	char cpus[NUM_CPUS+1];                /* Allowed CPUs */
   180 	unsigned int cycles[NUM_CPUS];        /* cycles for 000, 010, 020 */
   181 } opcode_struct;
   184 /* All modifications necessary for a specific EA mode of an instruction */
   185 typedef struct
   186 {
   187 	char* fname_add;
   188 	char* ea_add;
   189 	unsigned int mask_add;
   190 	unsigned int match_add;
   191 } ea_info_struct;
   194 /* Holds the body of a function */
   195 typedef struct
   196 {
   197 	char body[MAX_BODY_LENGTH][MAX_LINE_LENGTH+1];
   198 	int length;
   199 } body_struct;
   202 /* Holds a sequence of search / replace strings */
   203 typedef struct
   204 {
   205 	char replace[MAX_REPLACE_LENGTH][2][MAX_LINE_LENGTH+1];
   206 	int length;
   207 } replace_struct;
   210 /* Function Prototypes */
   211 void error_exit(char* fmt, ...);
   212 void perror_exit(char* fmt, ...);
   213 int check_strsncpy(char* dst, char* src, int maxlength);
   214 int check_atoi(char* str, int *result);
   215 int skip_spaces(char* str);
   216 int num_bits(int value);
   217 int atoh(char* buff);
   218 int fgetline(char* buff, int nchars, FILE* file);
   219 int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type);
   220 opcode_struct* find_opcode(char* name, int size, char* spec_proc, char* spec_ea);
   221 opcode_struct* find_illegal_opcode(void);
   222 int extract_opcode_info(char* src, char* name, int* size, char* spec_proc, char* spec_ea);
   223 void add_replace_string(replace_struct* replace, char* search_str, char* replace_str);
   224 void write_body(FILE* filep, body_struct* body, replace_struct* replace);
   225 void get_base_name(char* base_name, opcode_struct* op);
   226 void write_prototype(FILE* filep, char* base_name);
   227 void write_function_name(FILE* filep, char* base_name);
   228 void add_opcode_output_table_entry(opcode_struct* op, char* name);
   229 static int DECL_SPEC compare_nof_true_bits(const void* aptr, const void* bptr);
   230 void print_opcode_output_table(FILE* filep);
   231 void write_table_entry(FILE* filep, opcode_struct* op);
   232 void set_opcode_struct(opcode_struct* src, opcode_struct* dst, int ea_mode);
   233 void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* opinfo, int ea_mode);
   234 void generate_opcode_ea_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op);
   235 void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op_in, int offset);
   236 void process_opcode_handlers(void);
   237 void populate_table(void);
   238 void read_insert(char* insert);
   242 /* ======================================================================== */
   243 /* ================================= DATA ================================= */
   244 /* ======================================================================== */
   246 /* Name of the input file */
   247 char g_input_filename[MAX_PATH] = FILENAME_INPUT;
   249 /* File handles */
   250 FILE* g_input_file = NULL;
   251 FILE* g_prototype_file = NULL;
   252 FILE* g_table_file = NULL;
   253 FILE* g_ops_ac_file = NULL;
   254 FILE* g_ops_dm_file = NULL;
   255 FILE* g_ops_nz_file = NULL;
   257 int g_num_functions = 0;  /* Number of functions processed */
   258 int g_num_primitives = 0; /* Number of function primitives read */
   259 int g_line_number = 1;    /* Current line number */
   261 /* Opcode handler table */
   262 opcode_struct g_opcode_input_table[MAX_OPCODE_INPUT_TABLE_LENGTH];
   264 opcode_struct g_opcode_output_table[MAX_OPCODE_OUTPUT_TABLE_LENGTH];
   265 int g_opcode_output_table_length = 0;
   267 ea_info_struct g_ea_info_table[13] =
   268 {/* fname    ea        mask  match */
   269 	{"",     "",       0x00, 0x00}, /* EA_MODE_NONE */
   270 	{"ai",   "AY_AI",  0x38, 0x10}, /* EA_MODE_AI   */
   271 	{"pi",   "AY_PI",  0x38, 0x18}, /* EA_MODE_PI   */
   272 	{"pi7",  "A7_PI",  0x3f, 0x1f}, /* EA_MODE_PI7  */
   273 	{"pd",   "AY_PD",  0x38, 0x20}, /* EA_MODE_PD   */
   274 	{"pd7",  "A7_PD",  0x3f, 0x27}, /* EA_MODE_PD7  */
   275 	{"di",   "AY_DI",  0x38, 0x28}, /* EA_MODE_DI   */
   276 	{"ix",   "AY_IX",  0x38, 0x30}, /* EA_MODE_IX   */
   277 	{"aw",   "AW",     0x3f, 0x38}, /* EA_MODE_AW   */
   278 	{"al",   "AL",     0x3f, 0x39}, /* EA_MODE_AL   */
   279 	{"pcdi", "PCDI",   0x3f, 0x3a}, /* EA_MODE_PCDI */
   280 	{"pcix", "PCIX",   0x3f, 0x3b}, /* EA_MODE_PCIX */
   281 	{"i",    "I",      0x3f, 0x3c}, /* EA_MODE_I    */
   282 };
   285 char* g_cc_table[16][2] =
   286 {
   287 	{ "t",  "T"}, /* 0000 */
   288 	{ "f",  "F"}, /* 0001 */
   289 	{"hi", "HI"}, /* 0010 */
   290 	{"ls", "LS"}, /* 0011 */
   291 	{"cc", "CC"}, /* 0100 */
   292 	{"cs", "CS"}, /* 0101 */
   293 	{"ne", "NE"}, /* 0110 */
   294 	{"eq", "EQ"}, /* 0111 */
   295 	{"vc", "VC"}, /* 1000 */
   296 	{"vs", "VS"}, /* 1001 */
   297 	{"pl", "PL"}, /* 1010 */
   298 	{"mi", "MI"}, /* 1011 */
   299 	{"ge", "GE"}, /* 1100 */
   300 	{"lt", "LT"}, /* 1101 */
   301 	{"gt", "GT"}, /* 1110 */
   302 	{"le", "LE"}, /* 1111 */
   303 };
   305 /* size to index translator (0 -> 0, 8 and 16 -> 1, 32 -> 2) */
   306 int g_size_select_table[33] =
   307 {
   308 	0,												/* unsized */
   309 	0, 0, 0, 0, 0, 0, 0, 1,							/*    8    */
   310 	0, 0, 0, 0, 0, 0, 0, 1,							/*   16    */
   311 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2	/*   32    */
   312 };
   314 /* Extra cycles required for certain EA modes */
   315 int g_ea_cycle_table[13][NUM_CPUS][3] =
   316 {/*       000           010           020   */
   317 	{{ 0,  0,  0}, { 0,  0,  0}, { 0,  0,  0}}, /* EA_MODE_NONE */
   318 	{{ 0,  4,  8}, { 0,  4,  8}, { 0,  4,  4}}, /* EA_MODE_AI   */
   319 	{{ 0,  4,  8}, { 0,  4,  8}, { 0,  4,  4}}, /* EA_MODE_PI   */
   320 	{{ 0,  4,  8}, { 0,  4,  8}, { 0,  4,  4}}, /* EA_MODE_PI7  */
   321 	{{ 0,  6, 10}, { 0,  6, 10}, { 0,  5,  5}}, /* EA_MODE_PD   */
   322 	{{ 0,  6, 10}, { 0,  6, 10}, { 0,  5,  5}}, /* EA_MODE_PD7  */
   323 	{{ 0,  8, 12}, { 0,  8, 12}, { 0,  5,  5}}, /* EA_MODE_DI   */
   324 	{{ 0, 10, 14}, { 0, 10, 14}, { 0,  7,  7}}, /* EA_MODE_IX   */
   325 	{{ 0,  8, 12}, { 0,  8, 12}, { 0,  4,  4}}, /* EA_MODE_AW   */
   326 	{{ 0, 12, 16}, { 0, 12, 16}, { 0,  4,  4}}, /* EA_MODE_AL   */
   327 	{{ 0,  8, 12}, { 0,  8, 12}, { 0,  5,  5}}, /* EA_MODE_PCDI */
   328 	{{ 0, 10, 14}, { 0, 10, 14}, { 0,  7,  7}}, /* EA_MODE_PCIX */
   329 	{{ 0,  4,  8}, { 0,  4,  8}, { 0,  2,  4}}, /* EA_MODE_I    */
   330 };
   332 /* Extra cycles for JMP instruction (000, 010) */
   333 int g_jmp_cycle_table[13] =
   334 {
   335 	 0, /* EA_MODE_NONE */
   336 	 4, /* EA_MODE_AI   */
   337 	 0, /* EA_MODE_PI   */
   338 	 0, /* EA_MODE_PI7  */
   339 	 0, /* EA_MODE_PD   */
   340 	 0, /* EA_MODE_PD7  */
   341 	 6, /* EA_MODE_DI   */
   342 	 8, /* EA_MODE_IX   */
   343 	 6, /* EA_MODE_AW   */
   344 	 8, /* EA_MODE_AL   */
   345 	 6, /* EA_MODE_PCDI */
   346 	10, /* EA_MODE_PCIX */
   347 	 0, /* EA_MODE_I    */
   348 };
   350 /* Extra cycles for JSR instruction (000, 010) */
   351 int g_jsr_cycle_table[13] =
   352 {
   353 	 0, /* EA_MODE_NONE */
   354 	 4, /* EA_MODE_AI   */
   355 	 0, /* EA_MODE_PI   */
   356 	 0, /* EA_MODE_PI7  */
   357 	 0, /* EA_MODE_PD   */
   358 	 0, /* EA_MODE_PD7  */
   359 	 6, /* EA_MODE_DI   */
   360 	10, /* EA_MODE_IX   */
   361 	 6, /* EA_MODE_AW   */
   362 	 8, /* EA_MODE_AL   */
   363 	 6, /* EA_MODE_PCDI */
   364 	10, /* EA_MODE_PCIX */
   365 	 0, /* EA_MODE_I    */
   366 };
   368 /* Extra cycles for LEA instruction (000, 010) */
   369 int g_lea_cycle_table[13] =
   370 {
   371 	 0, /* EA_MODE_NONE */
   372 	 4, /* EA_MODE_AI   */
   373 	 0, /* EA_MODE_PI   */
   374 	 0, /* EA_MODE_PI7  */
   375 	 0, /* EA_MODE_PD   */
   376 	 0, /* EA_MODE_PD7  */
   377 	 8, /* EA_MODE_DI   */
   378 	12, /* EA_MODE_IX   */
   379 	 8, /* EA_MODE_AW   */
   380 	12, /* EA_MODE_AL   */
   381 	 8, /* EA_MODE_PCDI */
   382 	12, /* EA_MODE_PCIX */
   383 	 0, /* EA_MODE_I    */
   384 };
   386 /* Extra cycles for PEA instruction (000, 010) */
   387 int g_pea_cycle_table[13] =
   388 {
   389 	 0, /* EA_MODE_NONE */
   390 	 4, /* EA_MODE_AI   */
   391 	 0, /* EA_MODE_PI   */
   392 	 0, /* EA_MODE_PI7  */
   393 	 0, /* EA_MODE_PD   */
   394 	 0, /* EA_MODE_PD7  */
   395 	10, /* EA_MODE_DI   */
   396 	14, /* EA_MODE_IX   */
   397 	10, /* EA_MODE_AW   */
   398 	14, /* EA_MODE_AL   */
   399 	10, /* EA_MODE_PCDI */
   400 	14, /* EA_MODE_PCIX */
   401 	 0, /* EA_MODE_I    */
   402 };
   404 /* Extra cycles for MOVES instruction (010) */
   405 int g_moves_cycle_table[13][3] =
   406 {
   407 	{ 0,  0,  0}, /* EA_MODE_NONE */
   408 	{ 0,  4,  6}, /* EA_MODE_AI   */
   409 	{ 0,  4,  6}, /* EA_MODE_PI   */
   410 	{ 0,  4,  6}, /* EA_MODE_PI7  */
   411 	{ 0,  6, 12}, /* EA_MODE_PD   */
   412 	{ 0,  6, 12}, /* EA_MODE_PD7  */
   413 	{ 0, 12, 16}, /* EA_MODE_DI   */
   414 	{ 0, 16, 20}, /* EA_MODE_IX   */
   415 	{ 0, 12, 16}, /* EA_MODE_AW   */
   416 	{ 0, 16, 20}, /* EA_MODE_AL   */
   417 	{ 0,  0,  0}, /* EA_MODE_PCDI */
   418 	{ 0,  0,  0}, /* EA_MODE_PCIX */
   419 	{ 0,  0,  0}, /* EA_MODE_I    */
   420 };
   422 /* Extra cycles for CLR instruction (010) */
   423 int g_clr_cycle_table[13][3] =
   424 {
   425 	{ 0,  0,  0}, /* EA_MODE_NONE */
   426 	{ 0,  4,  6}, /* EA_MODE_AI   */
   427 	{ 0,  4,  6}, /* EA_MODE_PI   */
   428 	{ 0,  4,  6}, /* EA_MODE_PI7  */
   429 	{ 0,  6,  8}, /* EA_MODE_PD   */
   430 	{ 0,  6,  8}, /* EA_MODE_PD7  */
   431 	{ 0,  8, 10}, /* EA_MODE_DI   */
   432 	{ 0, 10, 14}, /* EA_MODE_IX   */
   433 	{ 0,  8, 10}, /* EA_MODE_AW   */
   434 	{ 0, 10, 14}, /* EA_MODE_AL   */
   435 	{ 0,  0,  0}, /* EA_MODE_PCDI */
   436 	{ 0,  0,  0}, /* EA_MODE_PCIX */
   437 	{ 0,  0,  0}, /* EA_MODE_I    */
   438 };
   442 /* ======================================================================== */
   443 /* =========================== UTILITY FUNCTIONS ========================== */
   444 /* ======================================================================== */
   446 /* Print an error message and exit with status error */
   447 void error_exit(char* fmt, ...)
   448 {
   449 	va_list args;
   450 	fprintf(stderr, "In %s, near or on line %d:\n\t", g_input_filename, g_line_number);
   451 	va_start(args, fmt);
   452 	vfprintf(stderr, fmt, args);
   453 	va_end(args);
   454 	fprintf(stderr, "\n");
   456 	if(g_prototype_file) fclose(g_prototype_file);
   457 	if(g_table_file) fclose(g_table_file);
   458 	if(g_ops_ac_file) fclose(g_ops_ac_file);
   459 	if(g_ops_dm_file) fclose(g_ops_dm_file);
   460 	if(g_ops_nz_file) fclose(g_ops_nz_file);
   461 	if(g_input_file) fclose(g_input_file);
   463 	exit(EXIT_FAILURE);
   464 }
   466 /* Print an error message, call perror(), and exit with status error */
   467 void perror_exit(char* fmt, ...)
   468 {
   469 	va_list args;
   470 	va_start(args, fmt);
   471 	vfprintf(stderr, fmt, args);
   472 	va_end(args);
   473 	perror("");
   475 	if(g_prototype_file) fclose(g_prototype_file);
   476 	if(g_table_file) fclose(g_table_file);
   477 	if(g_ops_ac_file) fclose(g_ops_ac_file);
   478 	if(g_ops_dm_file) fclose(g_ops_dm_file);
   479 	if(g_ops_nz_file) fclose(g_ops_nz_file);
   480 	if(g_input_file) fclose(g_input_file);
   482 	exit(EXIT_FAILURE);
   483 }
   486 /* copy until 0 or space and exit with error if we read too far */
   487 int check_strsncpy(char* dst, char* src, int maxlength)
   488 {
   489 	char* p = dst;
   490 	while(*src && *src != ' ')
   491 	{
   492 		*p++ = *src++;
   493 		if(p - dst > maxlength)
   494 			error_exit("Field too long");
   495 	}
   496 	*p = 0;
   497 	return p - dst;
   498 }
   500 /* copy until 0 or specified character and exit with error if we read too far */
   501 int check_strcncpy(char* dst, char* src, char delim, int maxlength)
   502 {
   503 	char* p = dst;
   504 	while(*src && *src != delim)
   505 	{
   506 		*p++ = *src++;
   507 		if(p - dst > maxlength)
   508 			error_exit("Field too long");
   509 	}
   510 	*p = 0;
   511 	return p - dst;
   512 }
   514 /* convert ascii to integer and exit with error if we find invalid data */
   515 int check_atoi(char* str, int *result)
   516 {
   517 	int accum = 0;
   518 	char* p = str;
   519 	while(*p >= '0' && *p <= '9')
   520 	{
   521 		accum *= 10;
   522 		accum += *p++ - '0';
   523 	}
   524 	if(*p != ' ' && *p != 0)
   525 		error_exit("Malformed integer value (%c)", *p);
   526 	*result = accum;
   527 	return p - str;
   528 }
   530 /* Skip past spaces in a string */
   531 int skip_spaces(char* str)
   532 {
   533 	char* p = str;
   535 	while(*p == ' ')
   536 		p++;
   538 	return p - str;
   539 }
   541 /* Count the number of set bits in a value */
   542 int num_bits(int value)
   543 {
   544     value = ((value & 0xaaaa) >> 1) + (value & 0x5555);
   545     value = ((value & 0xcccc) >> 2) + (value & 0x3333);
   546     value = ((value & 0xf0f0) >> 4) + (value & 0x0f0f);
   547     value = ((value & 0xff00) >> 8) + (value & 0x00ff);
   548 	return value;
   549 }
   551 /* Convert a hex value written in ASCII */
   552 int atoh(char* buff)
   553 {
   554 	int accum = 0;
   556 	for(;;buff++)
   557 	{
   558 		if(*buff >= '0' && *buff <= '9')
   559 		{
   560 			accum <<= 4;
   561 			accum += *buff - '0';
   562 		}
   563 		else if(*buff >= 'a' && *buff <= 'f')
   564 		{
   565 			accum <<= 4;
   566 			accum += *buff - 'a' + 10;
   567 		}
   568 		else break;
   569 	}
   570 	return accum;
   571 }
   573 /* Get a line of text from a file, discarding any end-of-line characters */
   574 int fgetline(char* buff, int nchars, FILE* file)
   575 {
   576 	int length;
   578 	if(fgets(buff, nchars, file) == NULL)
   579 		return -1;
   580 	if(buff[0] == '\r')
   581 		memcpy(buff, buff + 1, nchars - 1);
   583 	length = strlen(buff);
   584 	while(length && (buff[length-1] == '\r' || buff[length-1] == '\n'))
   585 		length--;
   586 	buff[length] = 0;
   587 	g_line_number++;
   589 	return length;
   590 }
   594 /* ======================================================================== */
   595 /* =========================== HELPER FUNCTIONS =========================== */
   596 /* ======================================================================== */
   598 /* Calculate the number of cycles an opcode requires */
   599 int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type)
   600 {
   601 	int size = g_size_select_table[op->size];
   603 	if(op->cpus[cpu_type] == '.')
   604 		return 0;
   606 	if(cpu_type < CPU_TYPE_020)
   607 	{
   608 		if(cpu_type == CPU_TYPE_010)
   609 		{
   610 			if(strcmp(op->name, "moves") == 0)
   611 				return op->cycles[cpu_type] + g_moves_cycle_table[ea_mode][size];
   612 			if(strcmp(op->name, "clr") == 0)
   613 				return op->cycles[cpu_type] + g_clr_cycle_table[ea_mode][size];
   614 		}
   616 		/* ASG: added these cases -- immediate modes take 2 extra cycles here */
   617 		if(cpu_type == CPU_TYPE_000 && ea_mode == EA_MODE_I &&
   618 		   ((strcmp(op->name, "add") == 0 && strcmp(op->spec_proc, "er") == 0) ||
   619 			strcmp(op->name, "adda")   == 0                                    ||
   620 			(strcmp(op->name, "and") == 0 && strcmp(op->spec_proc, "er") == 0) ||
   621 			(strcmp(op->name, "or") == 0 && strcmp(op->spec_proc, "er") == 0)  ||
   622 			(strcmp(op->name, "sub") == 0 && strcmp(op->spec_proc, "er") == 0) ||
   623 			strcmp(op->name, "suba")   == 0))
   624 			return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size] + 2;
   626 		if(strcmp(op->name, "jmp") == 0)
   627 			return op->cycles[cpu_type] + g_jmp_cycle_table[ea_mode];
   628 		if(strcmp(op->name, "jsr") == 0)
   629 			return op->cycles[cpu_type] + g_jsr_cycle_table[ea_mode];
   630 		if(strcmp(op->name, "lea") == 0)
   631 			return op->cycles[cpu_type] + g_lea_cycle_table[ea_mode];
   632 		if(strcmp(op->name, "pea") == 0)
   633 			return op->cycles[cpu_type] + g_pea_cycle_table[ea_mode];
   634 	}
   635 	return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size];
   636 }
   638 /* Find an opcode in the opcode handler list */
   639 opcode_struct* find_opcode(char* name, int size, char* spec_proc, char* spec_ea)
   640 {
   641 	opcode_struct* op;
   644 	for(op = g_opcode_input_table;op->name != NULL;op++)
   645 	{
   646 		if(	strcmp(name, op->name) == 0 &&
   647 			(size == (int)op->size) &&
   648 			strcmp(spec_proc, op->spec_proc) == 0 &&
   649 			strcmp(spec_ea, op->spec_ea) == 0)
   650 				return op;
   651 	}
   652 	return NULL;
   653 }
   655 /* Specifically find the illegal opcode in the list */
   656 opcode_struct* find_illegal_opcode(void)
   657 {
   658 	opcode_struct* op;
   660 	for(op = g_opcode_input_table;op->name != NULL;op++)
   661 	{
   662 		if(strcmp(op->name, "illegal") == 0)
   663 			return op;
   664 	}
   665 	return NULL;
   666 }
   668 /* Parse an opcode handler name */
   669 int extract_opcode_info(char* src, char* name, int* size, char* spec_proc, char* spec_ea)
   670 {
   671 	char* ptr = strstr(src, ID_OPHANDLER_NAME);
   673 	if(ptr == NULL)
   674 		return 0;
   676 	ptr += strlen(ID_OPHANDLER_NAME) + 1;
   678 	ptr += check_strcncpy(name, ptr, ',', MAX_NAME_LENGTH);
   679 	if(*ptr != ',') return 0;
   680 	ptr++;
   681 	ptr += skip_spaces(ptr);
   683 	*size = atoi(ptr);
   684 	ptr = strstr(ptr, ",");
   685 	if(ptr == NULL) return 0;
   686     ptr++;
   687 	ptr += skip_spaces(ptr);
   689 	ptr += check_strcncpy(spec_proc, ptr, ',', MAX_SPEC_PROC_LENGTH);
   690 	if(*ptr != ',') return 0;
   691 	ptr++;
   692 	ptr += skip_spaces(ptr);
   694 	ptr += check_strcncpy(spec_ea, ptr, ')', MAX_SPEC_EA_LENGTH);
   695 	if(*ptr != ')') return 0;
   697 	return 1;
   698 }
   701 /* Add a search/replace pair to a replace structure */
   702 void add_replace_string(replace_struct* replace, char* search_str, char* replace_str)
   703 {
   704 	if(replace->length >= MAX_REPLACE_LENGTH)
   705 		error_exit("overflow in replace structure");
   707 	strcpy(replace->replace[replace->length][0], search_str);
   708 	strcpy(replace->replace[replace->length++][1], replace_str);
   709 }
   711 /* Write a function body while replacing any selected strings */
   712 void write_body(FILE* filep, body_struct* body, replace_struct* replace)
   713 {
   714 	int i;
   715 	int j;
   716 	char* ptr;
   717 	char output[MAX_LINE_LENGTH+1];
   718 	char temp_buff[MAX_LINE_LENGTH+1];
   719 	int found;
   721 	for(i=0;i<body->length;i++)
   722 	{
   723 		strcpy(output, body->body[i]);
   724 		/* Check for the base directive header */
   725 		if(strstr(output, ID_BASE) != NULL)
   726 		{
   727 			/* Search for any text we need to replace */
   728 			found = 0;
   729 			for(j=0;j<replace->length;j++)
   730 			{
   731 				ptr = strstr(output, replace->replace[j][0]);
   732 				if(ptr)
   733 				{
   734 					/* We found something to replace */
   735 					found = 1;
   736 					strcpy(temp_buff, ptr+strlen(replace->replace[j][0]));
   737 					strcpy(ptr, replace->replace[j][1]);
   738 					strcat(ptr, temp_buff);
   739 				}
   740 			}
   741 			/* Found a directive with no matching replace string */
   742 			if(!found)
   743 				error_exit("Unknown " ID_BASE " directive");
   744 		}
   745 		fprintf(filep, "%s\n", output);
   746 	}
   747 	fprintf(filep, "\n\n");
   748 }
   750 /* Generate a base function name from an opcode struct */
   751 void get_base_name(char* base_name, opcode_struct* op)
   752 {
   753 	sprintf(base_name, "m68k_op_%s", op->name);
   754 	if(op->size > 0)
   755 		sprintf(base_name+strlen(base_name), "_%d", op->size);
   756 	if(strcmp(op->spec_proc, UNSPECIFIED) != 0)
   757 		sprintf(base_name+strlen(base_name), "_%s", op->spec_proc);
   758 	if(strcmp(op->spec_ea, UNSPECIFIED) != 0)
   759 		sprintf(base_name+strlen(base_name), "_%s", op->spec_ea);
   760 }
   762 /* Write the prototype of an opcode handler function */
   763 void write_prototype(FILE* filep, char* base_name)
   764 {
   765 	fprintf(filep, "void %s(void);\n", base_name);
   766 }
   768 /* Write the name of an opcode handler function */
   769 void write_function_name(FILE* filep, char* base_name)
   770 {
   771 	fprintf(filep, "void %s(void)\n", base_name);
   772 }
   774 void add_opcode_output_table_entry(opcode_struct* op, char* name)
   775 {
   776 	opcode_struct* ptr;
   777 	if(g_opcode_output_table_length > MAX_OPCODE_OUTPUT_TABLE_LENGTH)
   778 		error_exit("Opcode output table overflow");
   780 	ptr = g_opcode_output_table + g_opcode_output_table_length++;
   782 	*ptr = *op;
   783 	strcpy(ptr->name, name);
   784 	ptr->bits = num_bits(ptr->op_mask);
   785 }
   787 /*
   788  * Comparison function for qsort()
   789  * For entries with an equal number of set bits in
   790  * the mask compare the match values
   791  */
   792 static int DECL_SPEC compare_nof_true_bits(const void* aptr, const void* bptr)
   793 {
   794 	const opcode_struct *a = aptr, *b = bptr;
   795 	if(a->bits != b->bits)
   796 		return a->bits - b->bits;
   797 	if(a->op_mask != b->op_mask)
   798 		return a->op_mask - b->op_mask;
   799 	return a->op_match - b->op_match;
   800 }
   802 void print_opcode_output_table(FILE* filep)
   803 {
   804 	int i;
   805 	qsort((void *)g_opcode_output_table, g_opcode_output_table_length, sizeof(g_opcode_output_table[0]), compare_nof_true_bits);
   807 	for(i=0;i<g_opcode_output_table_length;i++)
   808 		write_table_entry(filep, g_opcode_output_table+i);
   809 }
   811 /* Write an entry in the opcode handler table */
   812 void write_table_entry(FILE* filep, opcode_struct* op)
   813 {
   814 	int i;
   816 	fprintf(filep, "\t{%-28s, 0x%04x, 0x%04x, {",
   817 		op->name, op->op_mask, op->op_match);
   819 	for(i=0;i<NUM_CPUS;i++)
   820 	{
   821 		fprintf(filep, "%3d", op->cycles[i]);
   822 		if(i < NUM_CPUS-1)
   823 			fprintf(filep, ", ");
   824 	}
   826 	fprintf(filep, "}},\n");
   827 }
   829 /* Fill out an opcode struct with a specific addressing mode of the source opcode struct */
   830 void set_opcode_struct(opcode_struct* src, opcode_struct* dst, int ea_mode)
   831 {
   832 	int i;
   834 	*dst = *src;
   836 	for(i=0;i<NUM_CPUS;i++)
   837 		dst->cycles[i] = get_oper_cycles(dst, ea_mode, i);
   838 	if(strcmp(dst->spec_ea, UNSPECIFIED) == 0 && ea_mode != EA_MODE_NONE)
   839 		sprintf(dst->spec_ea, "%s", g_ea_info_table[ea_mode].fname_add);
   840 	dst->op_mask |= g_ea_info_table[ea_mode].mask_add;
   841 	dst->op_match |= g_ea_info_table[ea_mode].match_add;
   842 }
   845 /* Generate a final opcode handler from the provided data */
   846 void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* opinfo, int ea_mode)
   847 {
   848 	char str[MAX_LINE_LENGTH+1];
   849 	opcode_struct* op = malloc(sizeof(opcode_struct));
   851 	/* Set the opcode structure and write the tables, prototypes, etc */
   852 	set_opcode_struct(opinfo, op, ea_mode);
   853 	get_base_name(str, op);
   854 	write_prototype(g_prototype_file, str);
   855 	add_opcode_output_table_entry(op, str);
   856 	write_function_name(filep, str);
   858 	/* Add any replace strings needed */
   859 	if(ea_mode != EA_MODE_NONE)
   860 	{
   861 		sprintf(str, "EA_%s_8()", g_ea_info_table[ea_mode].ea_add);
   862 		add_replace_string(replace, ID_OPHANDLER_EA_AY_8, str);
   863 		sprintf(str, "EA_%s_16()", g_ea_info_table[ea_mode].ea_add);
   864 		add_replace_string(replace, ID_OPHANDLER_EA_AY_16, str);
   865 		sprintf(str, "EA_%s_32()", g_ea_info_table[ea_mode].ea_add);
   866 		add_replace_string(replace, ID_OPHANDLER_EA_AY_32, str);
   867 		sprintf(str, "OPER_%s_8()", g_ea_info_table[ea_mode].ea_add);
   868 		add_replace_string(replace, ID_OPHANDLER_OPER_AY_8, str);
   869 		sprintf(str, "OPER_%s_16()", g_ea_info_table[ea_mode].ea_add);
   870 		add_replace_string(replace, ID_OPHANDLER_OPER_AY_16, str);
   871 		sprintf(str, "OPER_%s_32()", g_ea_info_table[ea_mode].ea_add);
   872 		add_replace_string(replace, ID_OPHANDLER_OPER_AY_32, str);
   873 	}
   875 	/* Now write the function body with the selected replace strings */
   876 	write_body(filep, body, replace);
   877 	g_num_functions++;
   878 	free(op);
   879 }
   881 /* Generate opcode variants based on available addressing modes */
   882 void generate_opcode_ea_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op)
   883 {
   884 	int old_length = replace->length;
   886 	/* No ea modes available for this opcode */
   887 	if(HAS_NO_EA_MODE(op->ea_allowed))
   888 	{
   889 		generate_opcode_handler(filep, body, replace, op, EA_MODE_NONE);
   890 		return;
   891 	}
   893 	/* Check for and create specific opcodes for each available addressing mode */
   894 	if(HAS_EA_AI(op->ea_allowed))
   895 		generate_opcode_handler(filep, body, replace, op, EA_MODE_AI);
   896 	replace->length = old_length;
   897 	if(HAS_EA_PI(op->ea_allowed))
   898 	{
   899 		generate_opcode_handler(filep, body, replace, op, EA_MODE_PI);
   900 		replace->length = old_length;
   901 		if(op->size == 8)
   902 			generate_opcode_handler(filep, body, replace, op, EA_MODE_PI7);
   903 	}
   904 	replace->length = old_length;
   905 	if(HAS_EA_PD(op->ea_allowed))
   906 	{
   907 		generate_opcode_handler(filep, body, replace, op, EA_MODE_PD);
   908 		replace->length = old_length;
   909 		if(op->size == 8)
   910 			generate_opcode_handler(filep, body, replace, op, EA_MODE_PD7);
   911 	}
   912 	replace->length = old_length;
   913 	if(HAS_EA_DI(op->ea_allowed))
   914 		generate_opcode_handler(filep, body, replace, op, EA_MODE_DI);
   915 	replace->length = old_length;
   916 	if(HAS_EA_IX(op->ea_allowed))
   917 		generate_opcode_handler(filep, body, replace, op, EA_MODE_IX);
   918 	replace->length = old_length;
   919 	if(HAS_EA_AW(op->ea_allowed))
   920 		generate_opcode_handler(filep, body, replace, op, EA_MODE_AW);
   921 	replace->length = old_length;
   922 	if(HAS_EA_AL(op->ea_allowed))
   923 		generate_opcode_handler(filep, body, replace, op, EA_MODE_AL);
   924 	replace->length = old_length;
   925 	if(HAS_EA_PCDI(op->ea_allowed))
   926 		generate_opcode_handler(filep, body, replace, op, EA_MODE_PCDI);
   927 	replace->length = old_length;
   928 	if(HAS_EA_PCIX(op->ea_allowed))
   929 		generate_opcode_handler(filep, body, replace, op, EA_MODE_PCIX);
   930 	replace->length = old_length;
   931 	if(HAS_EA_I(op->ea_allowed))
   932 		generate_opcode_handler(filep, body, replace, op, EA_MODE_I);
   933 	replace->length = old_length;
   934 }
   936 /* Generate variants of condition code opcodes */
   937 void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op_in, int offset)
   938 {
   939 	char repl[20];
   940 	char replnot[20];
   941 	int i;
   942 	int old_length = replace->length;
   943 	opcode_struct* op = malloc(sizeof(opcode_struct));
   945 	*op = *op_in;
   947 	op->op_mask |= 0x0f00;
   949 	/* Do all condition codes except t and f */
   950 	for(i=2;i<16;i++)
   951 	{
   952 		/* Add replace strings for this condition code */
   953 		sprintf(repl, "COND_%s()", g_cc_table[i][1]);
   954 		sprintf(replnot, "COND_NOT_%s()", g_cc_table[i][1]);
   956 		add_replace_string(replace, ID_OPHANDLER_CC, repl);
   957 		add_replace_string(replace, ID_OPHANDLER_NOT_CC, replnot);
   959 		/* Set the new opcode info */
   960 		strcpy(op->name+offset, g_cc_table[i][0]);
   962 		op->op_match = (op->op_match & 0xf0ff) | (i<<8);
   964 		/* Generate all opcode variants for this modified opcode */
   965 		generate_opcode_ea_variants(filep, body, replace, op);
   966 		/* Remove the above replace strings */
   967 		replace->length = old_length;
   968 	}
   969 	free(op);
   970 }
   972 /* Process the opcode handlers section of the input file */
   973 void process_opcode_handlers(void)
   974 {
   975 	FILE* input_file = g_input_file;
   976 	FILE* output_file;
   977 	char func_name[MAX_LINE_LENGTH+1];
   978 	char oper_name[MAX_LINE_LENGTH+1];
   979 	int  oper_size;
   980 	char oper_spec_proc[MAX_LINE_LENGTH+1];
   981 	char oper_spec_ea[MAX_LINE_LENGTH+1];
   982 	opcode_struct* opinfo;
   983 	replace_struct* replace = malloc(sizeof(replace_struct));
   984 	body_struct* body = malloc(sizeof(body_struct));
   987 	output_file = g_ops_ac_file;
   989 	for(;;)
   990 	{
   991 		/* Find the first line of the function */
   992 		func_name[0] = 0;
   993 		while(strstr(func_name, ID_OPHANDLER_NAME) == NULL)
   994 		{
   995 			if(strcmp(func_name, ID_INPUT_SEPARATOR) == 0)
   996 			{
   997 				free(replace);
   998 				free(body);
   999 				return; /* all done */
  1001 			if(fgetline(func_name, MAX_LINE_LENGTH, input_file) < 0)
  1002 				error_exit("Premature end of file when getting function name");
  1004 		/* Get the rest of the function */
  1005 		for(body->length=0;;body->length++)
  1007 			if(body->length > MAX_BODY_LENGTH)
  1008 				error_exit("Function too long");
  1010 			if(fgetline(body->body[body->length], MAX_LINE_LENGTH, input_file) < 0)
  1011 				error_exit("Premature end of file when getting function body");
  1013 			if(body->body[body->length][0] == '}')
  1015 				body->length++;
  1016 				break;
  1020 		g_num_primitives++;
  1022 		/* Extract the function name information */
  1023 		if(!extract_opcode_info(func_name, oper_name, &oper_size, oper_spec_proc, oper_spec_ea))
  1024 			error_exit("Invalid " ID_OPHANDLER_NAME " format");
  1026 		/* Find the corresponding table entry */
  1027 		opinfo = find_opcode(oper_name, oper_size, oper_spec_proc, oper_spec_ea);
  1028 		if(opinfo == NULL)
  1029 			error_exit("Unable to find matching table entry for %s", func_name);
  1031         /* Change output files if we pass 'c' or 'n' */
  1032 		if(output_file == g_ops_ac_file && oper_name[0] > 'c')
  1033 			output_file = g_ops_dm_file;
  1034 		else if(output_file == g_ops_dm_file && oper_name[0] > 'm')
  1035 			output_file = g_ops_nz_file;
  1037 		replace->length = 0;
  1039 		/* Generate opcode variants */
  1040 		if(strcmp(opinfo->name, "bcc") == 0 || strcmp(opinfo->name, "scc") == 0)
  1041 			generate_opcode_cc_variants(output_file, body, replace, opinfo, 1);
  1042 		else if(strcmp(opinfo->name, "dbcc") == 0)
  1043 			generate_opcode_cc_variants(output_file, body, replace, opinfo, 2);
  1044 		else if(strcmp(opinfo->name, "trapcc") == 0)
  1045 			generate_opcode_cc_variants(output_file, body, replace, opinfo, 4);
  1046 		else
  1047 			generate_opcode_ea_variants(output_file, body, replace, opinfo);
  1052 /* Populate the opcode handler table from the input file */
  1053 void populate_table(void)
  1055 	char* ptr;
  1056 	char bitpattern[17];
  1057 	opcode_struct* op;
  1058 	char buff[MAX_LINE_LENGTH];
  1059 	int i;
  1060 	int temp;
  1062 	buff[0] = 0;
  1064 	/* Find the start of the table */
  1065 	while(strcmp(buff, ID_TABLE_START) != 0)
  1066 		if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0)
  1067 			error_exit("Premature EOF while reading table");
  1069 	/* Process the entire table */
  1070 	for(op = g_opcode_input_table;;op++)
  1072 		if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0)
  1073 			error_exit("Premature EOF while reading table");
  1074 		if(strlen(buff) == 0)
  1075 			continue;
  1076 		/* We finish when we find an input separator */
  1077 		if(strcmp(buff, ID_INPUT_SEPARATOR) == 0)
  1078 			break;
  1080 		/* Extract the info from the table */
  1081 		ptr = buff;
  1083 		/* Name */
  1084 		ptr += skip_spaces(ptr);
  1085 		ptr += check_strsncpy(op->name, ptr, MAX_NAME_LENGTH);
  1087 		/* Size */
  1088 		ptr += skip_spaces(ptr);
  1089 		ptr += check_atoi(ptr, &temp);
  1090 		op->size = (unsigned char)temp;
  1092 		/* Special processing */
  1093 		ptr += skip_spaces(ptr);
  1094 		ptr += check_strsncpy(op->spec_proc, ptr, MAX_SPEC_PROC_LENGTH);
  1096 		/* Specified EA Mode */
  1097 		ptr += skip_spaces(ptr);
  1098 		ptr += check_strsncpy(op->spec_ea, ptr, MAX_SPEC_EA_LENGTH);
  1100 		/* Bit Pattern (more processing later) */
  1101 		ptr += skip_spaces(ptr);
  1102 		ptr += check_strsncpy(bitpattern, ptr, 17);
  1104 		/* Allowed Addressing Mode List */
  1105 		ptr += skip_spaces(ptr);
  1106 		ptr += check_strsncpy(op->ea_allowed, ptr, EA_ALLOWED_LENGTH);
  1108 		/* CPU operating mode (U = user or supervisor, S = supervisor only */
  1109 		ptr += skip_spaces(ptr);
  1110 		for(i=0;i<NUM_CPUS;i++)
  1112 			op->cpu_mode[i] = *ptr++;
  1113 			ptr += skip_spaces(ptr);
  1116 		/* Allowed CPUs for this instruction */
  1117 		for(i=0;i<NUM_CPUS;i++)
  1119 			ptr += skip_spaces(ptr);
  1120 			if(*ptr == UNSPECIFIED_CH)
  1122 				op->cpus[i] = UNSPECIFIED_CH;
  1123 				op->cycles[i] = 0;
  1124 				ptr++;
  1126 			else
  1128 				op->cpus[i] = (char)('0' + i);
  1129 				ptr += check_atoi(ptr, &temp);
  1130 				op->cycles[i] = (unsigned char)temp;
  1134 		/* generate mask and match from bitpattern */
  1135 		op->op_mask = 0;
  1136 		op->op_match = 0;
  1137 		for(i=0;i<16;i++)
  1139 			op->op_mask |= (bitpattern[i] != '.') << (15-i);
  1140 			op->op_match |= (bitpattern[i] == '1') << (15-i);
  1143 	/* Terminate the list */
  1144 	op->name[0] = 0;
  1147 /* Read a header or footer insert from the input file */
  1148 void read_insert(char* insert)
  1150 	char* ptr = insert;
  1151 	char* overflow = insert + MAX_INSERT_LENGTH - MAX_LINE_LENGTH;
  1152 	int length;
  1153 	char* first_blank = NULL;
  1155 	/* Skip any leading blank lines */
  1156 	for(length = 0;length == 0;length = fgetline(ptr, MAX_LINE_LENGTH, g_input_file))
  1157 		if(ptr >= overflow)
  1158 			error_exit("Buffer overflow reading inserts");
  1159 	if(length < 0)
  1160 		error_exit("Premature EOF while reading inserts");
  1162 	/* Advance and append newline */
  1163 	ptr += length;
  1164 	strcpy(ptr++, "\n");
  1166 	/* Read until next separator */
  1167 	for(;;)
  1169 		/* Read a new line */
  1170 		if(ptr >= overflow)
  1171 			error_exit("Buffer overflow reading inserts");
  1172 		if((length = fgetline(ptr, MAX_LINE_LENGTH, g_input_file)) < 0)
  1173 			error_exit("Premature EOF while reading inserts");
  1175 		/* Stop if we read a separator */
  1176 		if(strcmp(ptr, ID_INPUT_SEPARATOR) == 0)
  1177 			break;
  1179 		/* keep track in case there are trailing blanks */
  1180 		if(length == 0)
  1182 			if(first_blank == NULL)
  1183 				first_blank = ptr;
  1185 		else
  1186 			first_blank = NULL;
  1188 		/* Advance and append newline */
  1189 		ptr += length;
  1190 		strcpy(ptr++, "\n");
  1193 	/* kill any trailing blank lines */
  1194 	if(first_blank)
  1195 		ptr = first_blank;
  1196 	*ptr = 0;
  1201 /* ======================================================================== */
  1202 /* ============================= MAIN FUNCTION ============================ */
  1203 /* ======================================================================== */
  1205 int main(int argc, char **argv)
  1207 	/* File stuff */
  1208 	char output_path[MAX_DIR] = "";
  1209 	char filename[MAX_PATH];
  1210 	/* Section identifier */
  1211 	char section_id[MAX_LINE_LENGTH+1];
  1212 	/* Inserts */
  1213 	char temp_insert[MAX_INSERT_LENGTH+1];
  1214 	char prototype_footer_insert[MAX_INSERT_LENGTH+1];
  1215 	char table_footer_insert[MAX_INSERT_LENGTH+1];
  1216 	char ophandler_footer_insert[MAX_INSERT_LENGTH+1];
  1217 	/* Flags if we've processed certain parts already */
  1218 	int prototype_header_read = 0;
  1219 	int prototype_footer_read = 0;
  1220 	int table_header_read = 0;
  1221 	int table_footer_read = 0;
  1222 	int ophandler_header_read = 0;
  1223 	int ophandler_footer_read = 0;
  1224 	int table_body_read = 0;
  1225 	int ophandler_body_read = 0;
  1227 	printf("\n\t\tMusashi v%s 68000, 68010, 68EC020, 68020 emulator\n", g_version);
  1228 	printf("\t\tCopyright 1998-2000 Karl Stenerud (karl@mame.net)\n\n");
  1230 	/* Check if output path and source for the input file are given */
  1231     if(argc > 1)
  1233 		char *ptr;
  1234 		strcpy(output_path, argv[1]);
  1236 		for(ptr = strchr(output_path, '\\'); ptr; ptr = strchr(ptr, '\\'))
  1237 			*ptr = '/';
  1238         if(output_path[strlen(output_path)-1] != '/')
  1239 			strcat(output_path, "/");
  1240 		if(argc > 2)
  1241 			strcpy(g_input_filename, argv[2]);
  1245 	/* Open the files we need */
  1246 	sprintf(filename, "%s%s", output_path, FILENAME_PROTOTYPE);
  1247 	if((g_prototype_file = fopen(filename, "wt")) == NULL)
  1248 		perror_exit("Unable to create prototype file (%s)\n", filename);
  1250 	sprintf(filename, "%s%s", output_path, FILENAME_TABLE);
  1251 	if((g_table_file = fopen(filename, "wt")) == NULL)
  1252 		perror_exit("Unable to create table file (%s)\n", filename);
  1254 	sprintf(filename, "%s%s", output_path, FILENAME_OPS_AC);
  1255 	if((g_ops_ac_file = fopen(filename, "wt")) == NULL)
  1256 		perror_exit("Unable to create ops ac file (%s)\n", filename);
  1258 	sprintf(filename, "%s%s", output_path, FILENAME_OPS_DM);
  1259 	if((g_ops_dm_file = fopen(filename, "wt")) == NULL)
  1260 		perror_exit("Unable to create ops dm file (%s)\n", filename);
  1262 	sprintf(filename, "%s%s", output_path, FILENAME_OPS_NZ);
  1263 	if((g_ops_nz_file = fopen(filename, "wt")) == NULL)
  1264 		perror_exit("Unable to create ops nz file (%s)\n", filename);
  1266 	if((g_input_file=fopen(g_input_filename, "rt")) == NULL)
  1267 		perror_exit("can't open %s for input", g_input_filename);
  1270 	/* Get to the first section of the input file */
  1271 	section_id[0] = 0;
  1272 	while(strcmp(section_id, ID_INPUT_SEPARATOR) != 0)
  1273 		if(fgetline(section_id, MAX_LINE_LENGTH, g_input_file) < 0)
  1274 			error_exit("Premature EOF while reading input file");
  1276 	/* Now process all sections */
  1277 	for(;;)
  1279 		if(fgetline(section_id, MAX_LINE_LENGTH, g_input_file) < 0)
  1280 			error_exit("Premature EOF while reading input file");
  1281 		if(strcmp(section_id, ID_PROTOTYPE_HEADER) == 0)
  1283 			if(prototype_header_read)
  1284 				error_exit("Duplicate prototype header");
  1285 			read_insert(temp_insert);
  1286 			fprintf(g_prototype_file, "%s\n\n", temp_insert);
  1287 			prototype_header_read = 1;
  1289 		else if(strcmp(section_id, ID_TABLE_HEADER) == 0)
  1291 			if(table_header_read)
  1292 				error_exit("Duplicate table header");
  1293 			read_insert(temp_insert);
  1294 			fprintf(g_table_file, "%s", temp_insert);
  1295 			table_header_read = 1;
  1297 		else if(strcmp(section_id, ID_OPHANDLER_HEADER) == 0)
  1299 			if(ophandler_header_read)
  1300 				error_exit("Duplicate opcode handler header");
  1301 			read_insert(temp_insert);
  1302 			fprintf(g_ops_ac_file, "%s\n\n", temp_insert);
  1303 			fprintf(g_ops_dm_file, "%s\n\n", temp_insert);
  1304 			fprintf(g_ops_nz_file, "%s\n\n", temp_insert);
  1305 			ophandler_header_read = 1;
  1307 		else if(strcmp(section_id, ID_PROTOTYPE_FOOTER) == 0)
  1309 			if(prototype_footer_read)
  1310 				error_exit("Duplicate prototype footer");
  1311 			read_insert(prototype_footer_insert);
  1312 			prototype_footer_read = 1;
  1314 		else if(strcmp(section_id, ID_TABLE_FOOTER) == 0)
  1316 			if(table_footer_read)
  1317 				error_exit("Duplicate table footer");
  1318 			read_insert(table_footer_insert);
  1319 			table_footer_read = 1;
  1321 		else if(strcmp(section_id, ID_OPHANDLER_FOOTER) == 0)
  1323 			if(ophandler_footer_read)
  1324 				error_exit("Duplicate opcode handler footer");
  1325 			read_insert(ophandler_footer_insert);
  1326 			ophandler_footer_read = 1;
  1328 		else if(strcmp(section_id, ID_TABLE_BODY) == 0)
  1330 			if(!prototype_header_read)
  1331 				error_exit("Table body encountered before prototype header");
  1332 			if(!table_header_read)
  1333 				error_exit("Table body encountered before table header");
  1334 			if(!ophandler_header_read)
  1335 				error_exit("Table body encountered before opcode handler header");
  1337 			if(table_body_read)
  1338 				error_exit("Duplicate table body");
  1340 			populate_table();
  1341 			table_body_read = 1;
  1343 		else if(strcmp(section_id, ID_OPHANDLER_BODY) == 0)
  1345 			if(!prototype_header_read)
  1346 				error_exit("Opcode handlers encountered before prototype header");
  1347 			if(!table_header_read)
  1348 				error_exit("Opcode handlers encountered before table header");
  1349 			if(!ophandler_header_read)
  1350 				error_exit("Opcode handlers encountered before opcode handler header");
  1351 			if(!table_body_read)
  1352 				error_exit("Opcode handlers encountered before table body");
  1354 			if(ophandler_body_read)
  1355 				error_exit("Duplicate opcode handler section");
  1357 			process_opcode_handlers();
  1359 			ophandler_body_read = 1;
  1361 		else if(strcmp(section_id, ID_END) == 0)
  1363 			/* End of input file.  Do a sanity check and then write footers */
  1364 			if(!prototype_header_read)
  1365 				error_exit("Missing prototype header");
  1366 			if(!prototype_footer_read)
  1367 				error_exit("Missing prototype footer");
  1368 			if(!table_header_read)
  1369 				error_exit("Missing table header");
  1370 			if(!table_footer_read)
  1371 				error_exit("Missing table footer");
  1372 			if(!table_body_read)
  1373 				error_exit("Missing table body");
  1374 			if(!ophandler_header_read)
  1375 				error_exit("Missing opcode handler header");
  1376 			if(!ophandler_footer_read)
  1377 				error_exit("Missing opcode handler footer");
  1378 			if(!ophandler_body_read)
  1379 				error_exit("Missing opcode handler body");
  1381 			print_opcode_output_table(g_table_file);
  1383 			fprintf(g_prototype_file, "%s\n\n", prototype_footer_insert);
  1384 			fprintf(g_table_file, "%s\n\n", table_footer_insert);
  1385 			fprintf(g_ops_ac_file, "%s\n\n", ophandler_footer_insert);
  1386 			fprintf(g_ops_dm_file, "%s\n\n", ophandler_footer_insert);
  1387 			fprintf(g_ops_nz_file, "%s\n\n", ophandler_footer_insert);
  1389 			break;
  1391 		else
  1393 			error_exit("Unknown section identifier: %s", section_id);
  1397 	/* Close all files and exit */
  1398 	fclose(g_prototype_file);
  1399 	fclose(g_table_file);
  1400 	fclose(g_ops_ac_file);
  1401 	fclose(g_ops_dm_file);
  1402 	fclose(g_ops_nz_file);
  1403 	fclose(g_input_file);
  1405 	printf("Generated %d opcode handlers from %d primitives\n", g_num_functions, g_num_primitives);
  1407 	return 0;
  1412 /* ======================================================================== */
  1413 /* ============================== END OF FILE ============================= */
  1414 /* ======================================================================== */