src/musashi/m68kmake.c

Wed, 16 Apr 2014 02:20:43 -0600

author
andrew@localhost
date
Wed, 16 Apr 2014 02:20:43 -0600
changeset 147
ad888290cdff
parent 0
8bf1bf91a36d
permissions
-rw-r--r--

fixed bus error handling for real this time (save registers before every instruction and push the saved registers if a bus error occurs, since the instruction may have changed registers before the bus error, and also stop the instruction immediately with longjmp so it won't change memory after the bus error)

This isn't actually what a real 68k does, but it is a good enough approximation. A real 68k will jump back into the middle of the faulted instruction and resume it from the memory access that faulted as opposed to restarting from the beginning like this CPU emulation does. It would be a lot harder to do that with the way this CPU library is designed. Newer versions of MESS basically do the same thing (they use a newer version of this library).

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