src/musashi/m68kmake.c

Sun, 05 Dec 2010 16:20:00 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Sun, 05 Dec 2010 16:20:00 +0000
changeset 52
a350dfa92895
parent 0
8bf1bf91a36d
permissions
-rw-r--r--

add preliminary WD279x emulation to core

     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 /* ======================================================================== */