src/musashi/m68kmake.c

Thu, 11 Apr 2013 09:37:11 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Thu, 11 Apr 2013 09:37:11 +0100
changeset 138
d744db15cdf7
parent 0
8bf1bf91a36d
permissions
-rw-r--r--

Check return value of fread()

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