1 /* ======================================================================== */
\r
2 /* ========================= LICENSING & COPYRIGHT ======================== */
\r
3 /* ======================================================================== */
\r
8 * A portable Motorola M680x0 processor emulation engine.
\r
9 * Copyright 1998-2001 Karl Stenerud. All rights reserved.
\r
11 * This code may be freely used for non-commercial purposes as long as this
\r
12 * copyright notice remains unaltered in the source code and any binary files
\r
13 * containing this code in compiled form.
\r
15 * All other lisencing terms must be negotiated with the author
\r
18 * The latest version of this code can be obtained at:
\r
19 * http://kstenerud.cjb.net
\r
23 * Modified For OpenVMS By: Robert Alan Byer
\r
24 * byer@mail.ourservers.net
\r
28 /* ======================================================================== */
\r
29 /* ============================ CODE GENERATOR ============================ */
\r
30 /* ======================================================================== */
\r
32 * This is the code generator program which will generate the opcode table
\r
33 * and the final opcode handlers.
\r
35 * It requires an input file to function (default m68k_in.c), but you can
\r
36 * specify your own like so:
\r
38 * m68kmake <output path> <input file>
\r
40 * where output path is the path where the output files should be placed, and
\r
41 * input file is the file to use for input.
\r
43 * If you modify the input file greatly from its released form, you may have
\r
44 * to tweak the configuration section a bit since I'm using static allocation
\r
45 * to keep things simple.
\r
48 * TODO: - build a better code generator for the move instruction.
\r
49 * - Add callm and rtm instructions
\r
50 * - Fix RTE to handle other format words
\r
51 * - Add address error (and bus error?) handling
\r
55 const char* g_version = "3.3";
\r
57 /* ======================================================================== */
\r
58 /* =============================== INCLUDES =============================== */
\r
59 /* ======================================================================== */
\r
69 /* ======================================================================== */
\r
70 /* ============================= CONFIGURATION ============================ */
\r
71 /* ======================================================================== */
\r
73 #define M68K_MAX_PATH 1024
\r
74 #define M68K_MAX_DIR 1024
\r
76 #define MAX_LINE_LENGTH 200 /* length of 1 line */
\r
77 #define MAX_BODY_LENGTH 300 /* Number of lines in 1 function */
\r
78 #define MAX_REPLACE_LENGTH 30 /* Max number of replace strings */
\r
79 #define MAX_INSERT_LENGTH 5000 /* Max size of insert piece */
\r
80 #define MAX_NAME_LENGTH 30 /* Max length of ophandler name */
\r
81 #define MAX_SPEC_PROC_LENGTH 4 /* Max length of special processing str */
\r
82 #define MAX_SPEC_EA_LENGTH 5 /* Max length of specified EA str */
\r
83 #define EA_ALLOWED_LENGTH 11 /* Max length of ea allowed str */
\r
84 #define MAX_OPCODE_INPUT_TABLE_LENGTH 1000 /* Max length of opcode handler tbl */
\r
85 #define MAX_OPCODE_OUTPUT_TABLE_LENGTH 3000 /* Max length of opcode handler tbl */
\r
87 /* Default filenames */
\r
88 #define FILENAME_INPUT "m68k_in.c"
\r
89 #define FILENAME_PROTOTYPE "m68kops.h"
\r
90 #define FILENAME_TABLE "m68kops.c"
\r
91 #define FILENAME_OPS_AC "m68kopac.c"
\r
92 #define FILENAME_OPS_DM "m68kopdm.c"
\r
93 #define FILENAME_OPS_NZ "m68kopnz.c"
\r
96 /* Identifier sequences recognized by this program */
\r
98 #define ID_INPUT_SEPARATOR "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
\r
100 #define ID_BASE "M68KMAKE"
\r
101 #define ID_PROTOTYPE_HEADER ID_BASE "_PROTOTYPE_HEADER"
\r
102 #define ID_PROTOTYPE_FOOTER ID_BASE "_PROTOTYPE_FOOTER"
\r
103 #define ID_TABLE_HEADER ID_BASE "_TABLE_HEADER"
\r
104 #define ID_TABLE_FOOTER ID_BASE "_TABLE_FOOTER"
\r
105 #define ID_TABLE_BODY ID_BASE "_TABLE_BODY"
\r
106 #define ID_TABLE_START ID_BASE "_TABLE_START"
\r
107 #define ID_OPHANDLER_HEADER ID_BASE "_OPCODE_HANDLER_HEADER"
\r
108 #define ID_OPHANDLER_FOOTER ID_BASE "_OPCODE_HANDLER_FOOTER"
\r
109 #define ID_OPHANDLER_BODY ID_BASE "_OPCODE_HANDLER_BODY"
\r
110 #define ID_END ID_BASE "_END"
\r
112 #define ID_OPHANDLER_NAME ID_BASE "_OP"
\r
113 #define ID_OPHANDLER_EA_AY_8 ID_BASE "_GET_EA_AY_8"
\r
114 #define ID_OPHANDLER_EA_AY_16 ID_BASE "_GET_EA_AY_16"
\r
115 #define ID_OPHANDLER_EA_AY_32 ID_BASE "_GET_EA_AY_32"
\r
116 #define ID_OPHANDLER_OPER_AY_8 ID_BASE "_GET_OPER_AY_8"
\r
117 #define ID_OPHANDLER_OPER_AY_16 ID_BASE "_GET_OPER_AY_16"
\r
118 #define ID_OPHANDLER_OPER_AY_32 ID_BASE "_GET_OPER_AY_32"
\r
119 #define ID_OPHANDLER_CC ID_BASE "_CC"
\r
120 #define ID_OPHANDLER_NOT_CC ID_BASE "_NOT_CC"
\r
125 #endif /* DECL_SPEC */
\r
129 /* ======================================================================== */
\r
130 /* ============================== PROTOTYPES ============================== */
\r
131 /* ======================================================================== */
\r
141 #define UNSPECIFIED "."
\r
142 #define UNSPECIFIED_CH '.'
\r
144 #define HAS_NO_EA_MODE(A) (strcmp(A, "..........") == 0)
\r
145 #define HAS_EA_AI(A) ((A)[0] == 'A')
\r
146 #define HAS_EA_PI(A) ((A)[1] == '+')
\r
147 #define HAS_EA_PD(A) ((A)[2] == '-')
\r
148 #define HAS_EA_DI(A) ((A)[3] == 'D')
\r
149 #define HAS_EA_IX(A) ((A)[4] == 'X')
\r
150 #define HAS_EA_AW(A) ((A)[5] == 'W')
\r
151 #define HAS_EA_AL(A) ((A)[6] == 'L')
\r
152 #define HAS_EA_PCDI(A) ((A)[7] == 'd')
\r
153 #define HAS_EA_PCIX(A) ((A)[8] == 'x')
\r
154 #define HAS_EA_I(A) ((A)[9] == 'I')
\r
158 EA_MODE_NONE, /* No special addressing mode */
\r
159 EA_MODE_AI, /* Address register indirect */
\r
160 EA_MODE_PI, /* Address register indirect with postincrement */
\r
161 EA_MODE_PI7, /* Address register 7 indirect with postincrement */
\r
162 EA_MODE_PD, /* Address register indirect with predecrement */
\r
163 EA_MODE_PD7, /* Address register 7 indirect with predecrement */
\r
164 EA_MODE_DI, /* Address register indirect with displacement */
\r
165 EA_MODE_IX, /* Address register indirect with index */
\r
166 EA_MODE_AW, /* Absolute word */
\r
167 EA_MODE_AL, /* Absolute long */
\r
168 EA_MODE_PCDI, /* Program counter indirect with displacement */
\r
169 EA_MODE_PCIX, /* Program counter indirect with index */
\r
170 EA_MODE_I /* Immediate */
\r
174 /* Everything we need to know about an opcode */
\r
177 char name[MAX_NAME_LENGTH]; /* opcode handler name */
\r
178 unsigned char size; /* Size of operation */
\r
179 char spec_proc[MAX_SPEC_PROC_LENGTH]; /* Special processing mode */
\r
180 char spec_ea[MAX_SPEC_EA_LENGTH]; /* Specified effective addressing mode */
\r
181 unsigned char bits; /* Number of significant bits (used for sorting the table) */
\r
182 unsigned short op_mask; /* Mask to apply for matching an opcode to a handler */
\r
183 unsigned short op_match; /* Value to match after masking */
\r
184 char ea_allowed[EA_ALLOWED_LENGTH]; /* Effective addressing modes allowed */
\r
185 char cpu_mode[NUM_CPUS]; /* User or supervisor mode */
\r
186 char cpus[NUM_CPUS+1]; /* Allowed CPUs */
\r
187 unsigned char cycles[NUM_CPUS]; /* cycles for 000, 010, 020 */
\r
191 /* All modifications necessary for a specific EA mode of an instruction */
\r
194 const char* fname_add;
\r
195 const char* ea_add;
\r
196 unsigned int mask_add;
\r
197 unsigned int match_add;
\r
201 /* Holds the body of a function */
\r
204 char body[MAX_BODY_LENGTH][MAX_LINE_LENGTH+1];
\r
209 /* Holds a sequence of search / replace strings */
\r
212 char replace[MAX_REPLACE_LENGTH][2][MAX_LINE_LENGTH+1];
\r
217 /* Function Prototypes */
\r
218 void error_exit(const char* fmt, ...);
\r
219 void perror_exit(const char* fmt, ...);
\r
220 int check_strsncpy(char* dst, char* src, int maxlength);
\r
221 int check_atoi(char* str, int *result);
\r
222 int skip_spaces(char* str);
\r
223 int num_bits(int value);
\r
224 int atoh(char* buff);
\r
225 int fgetline(char* buff, int nchars, FILE* file);
\r
226 int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type);
\r
227 opcode_struct* find_opcode(char* name, int size, char* spec_proc, char* spec_ea);
\r
228 opcode_struct* find_illegal_opcode(void);
\r
229 int extract_opcode_info(char* src, char* name, int* size, char* spec_proc, char* spec_ea);
\r
230 void add_replace_string(replace_struct* replace, const char* search_str, const char* replace_str);
\r
231 void write_body(FILE* filep, body_struct* body, replace_struct* replace);
\r
232 void get_base_name(char* base_name, opcode_struct* op);
\r
233 void write_prototype(FILE* filep, char* base_name);
\r
234 void write_function_name(FILE* filep, char* base_name);
\r
235 void add_opcode_output_table_entry(opcode_struct* op, char* name);
\r
236 static int DECL_SPEC compare_nof_true_bits(const void* aptr, const void* bptr);
\r
237 void print_opcode_output_table(FILE* filep);
\r
238 void write_table_entry(FILE* filep, opcode_struct* op);
\r
239 void set_opcode_struct(opcode_struct* src, opcode_struct* dst, int ea_mode);
\r
240 void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* opinfo, int ea_mode);
\r
241 void generate_opcode_ea_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op);
\r
242 void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op_in, int offset);
\r
243 void process_opcode_handlers(void);
\r
244 void populate_table(void);
\r
245 void read_insert(char* insert);
\r
249 /* ======================================================================== */
\r
250 /* ================================= DATA ================================= */
\r
251 /* ======================================================================== */
\r
253 /* Name of the input file */
\r
254 char g_input_filename[M68K_MAX_PATH] = FILENAME_INPUT;
\r
257 FILE* g_input_file = NULL;
\r
258 FILE* g_prototype_file = NULL;
\r
259 FILE* g_table_file = NULL;
\r
260 FILE* g_ops_ac_file = NULL;
\r
261 FILE* g_ops_dm_file = NULL;
\r
262 FILE* g_ops_nz_file = NULL;
\r
264 int g_num_functions = 0; /* Number of functions processed */
\r
265 int g_num_primitives = 0; /* Number of function primitives read */
\r
266 int g_line_number = 1; /* Current line number */
\r
268 /* Opcode handler table */
\r
269 opcode_struct g_opcode_input_table[MAX_OPCODE_INPUT_TABLE_LENGTH];
\r
271 opcode_struct g_opcode_output_table[MAX_OPCODE_OUTPUT_TABLE_LENGTH];
\r
272 int g_opcode_output_table_length = 0;
\r
274 ea_info_struct g_ea_info_table[13] =
\r
275 {/* fname ea mask match */
\r
276 {"", "", 0x00, 0x00}, /* EA_MODE_NONE */
\r
277 {"ai", "AY_AI", 0x38, 0x10}, /* EA_MODE_AI */
\r
278 {"pi", "AY_PI", 0x38, 0x18}, /* EA_MODE_PI */
\r
279 {"pi7", "A7_PI", 0x3f, 0x1f}, /* EA_MODE_PI7 */
\r
280 {"pd", "AY_PD", 0x38, 0x20}, /* EA_MODE_PD */
\r
281 {"pd7", "A7_PD", 0x3f, 0x27}, /* EA_MODE_PD7 */
\r
282 {"di", "AY_DI", 0x38, 0x28}, /* EA_MODE_DI */
\r
283 {"ix", "AY_IX", 0x38, 0x30}, /* EA_MODE_IX */
\r
284 {"aw", "AW", 0x3f, 0x38}, /* EA_MODE_AW */
\r
285 {"al", "AL", 0x3f, 0x39}, /* EA_MODE_AL */
\r
286 {"pcdi", "PCDI", 0x3f, 0x3a}, /* EA_MODE_PCDI */
\r
287 {"pcix", "PCIX", 0x3f, 0x3b}, /* EA_MODE_PCIX */
\r
288 {"i", "I", 0x3f, 0x3c}, /* EA_MODE_I */
\r
292 const char* g_cc_table[16][2] =
\r
294 { "t", "T"}, /* 0000 */
\r
295 { "f", "F"}, /* 0001 */
\r
296 {"hi", "HI"}, /* 0010 */
\r
297 {"ls", "LS"}, /* 0011 */
\r
298 {"cc", "CC"}, /* 0100 */
\r
299 {"cs", "CS"}, /* 0101 */
\r
300 {"ne", "NE"}, /* 0110 */
\r
301 {"eq", "EQ"}, /* 0111 */
\r
302 {"vc", "VC"}, /* 1000 */
\r
303 {"vs", "VS"}, /* 1001 */
\r
304 {"pl", "PL"}, /* 1010 */
\r
305 {"mi", "MI"}, /* 1011 */
\r
306 {"ge", "GE"}, /* 1100 */
\r
307 {"lt", "LT"}, /* 1101 */
\r
308 {"gt", "GT"}, /* 1110 */
\r
309 {"le", "LE"}, /* 1111 */
\r
312 /* size to index translator (0 -> 0, 8 and 16 -> 1, 32 -> 2) */
\r
313 int g_size_select_table[33] =
\r
316 0, 0, 0, 0, 0, 0, 0, 1, /* 8 */
\r
317 0, 0, 0, 0, 0, 0, 0, 1, /* 16 */
\r
318 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 /* 32 */
\r
321 /* Extra cycles required for certain EA modes */
\r
322 /* TODO: correct timings for 040 */
\r
323 int g_ea_cycle_table[13][NUM_CPUS][3] =
\r
324 {/* 000 010 020 040 */
\r
325 {{ 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}}, /* EA_MODE_NONE */
\r
326 {{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AI */
\r
327 {{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_PI */
\r
328 {{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_PI7 */
\r
329 {{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PD */
\r
330 {{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PD7 */
\r
331 {{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_DI */
\r
332 {{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}, { 0, 7, 7}}, /* EA_MODE_IX */
\r
333 {{ 0, 8, 12}, { 0, 8, 12}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AW */
\r
334 {{ 0, 12, 16}, { 0, 12, 16}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AL */
\r
335 {{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PCDI */
\r
336 {{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}, { 0, 7, 7}}, /* EA_MODE_PCIX */
\r
337 {{ 0, 4, 8}, { 0, 4, 8}, { 0, 2, 4}, { 0, 2, 4}}, /* EA_MODE_I */
\r
340 /* Extra cycles for JMP instruction (000, 010) */
\r
341 int g_jmp_cycle_table[13] =
\r
343 0, /* EA_MODE_NONE */
\r
344 4, /* EA_MODE_AI */
\r
345 0, /* EA_MODE_PI */
\r
346 0, /* EA_MODE_PI7 */
\r
347 0, /* EA_MODE_PD */
\r
348 0, /* EA_MODE_PD7 */
\r
349 6, /* EA_MODE_DI */
\r
350 10, /* EA_MODE_IX */
\r
351 6, /* EA_MODE_AW */
\r
352 8, /* EA_MODE_AL */
\r
353 6, /* EA_MODE_PCDI */
\r
354 10, /* EA_MODE_PCIX */
\r
358 /* Extra cycles for JSR instruction (000, 010) */
\r
359 int g_jsr_cycle_table[13] =
\r
361 0, /* EA_MODE_NONE */
\r
362 4, /* EA_MODE_AI */
\r
363 0, /* EA_MODE_PI */
\r
364 0, /* EA_MODE_PI7 */
\r
365 0, /* EA_MODE_PD */
\r
366 0, /* EA_MODE_PD7 */
\r
367 6, /* EA_MODE_DI */
\r
368 10, /* EA_MODE_IX */
\r
369 6, /* EA_MODE_AW */
\r
370 8, /* EA_MODE_AL */
\r
371 6, /* EA_MODE_PCDI */
\r
372 10, /* EA_MODE_PCIX */
\r
376 /* Extra cycles for LEA instruction (000, 010) */
\r
377 int g_lea_cycle_table[13] =
\r
379 0, /* EA_MODE_NONE */
\r
380 4, /* EA_MODE_AI */
\r
381 0, /* EA_MODE_PI */
\r
382 0, /* EA_MODE_PI7 */
\r
383 0, /* EA_MODE_PD */
\r
384 0, /* EA_MODE_PD7 */
\r
385 8, /* EA_MODE_DI */
\r
386 12, /* EA_MODE_IX */
\r
387 8, /* EA_MODE_AW */
\r
388 12, /* EA_MODE_AL */
\r
389 8, /* EA_MODE_PCDI */
\r
390 12, /* EA_MODE_PCIX */
\r
394 /* Extra cycles for PEA instruction (000, 010) */
\r
395 int g_pea_cycle_table[13] =
\r
397 0, /* EA_MODE_NONE */
\r
398 6, /* EA_MODE_AI */
\r
399 0, /* EA_MODE_PI */
\r
400 0, /* EA_MODE_PI7 */
\r
401 0, /* EA_MODE_PD */
\r
402 0, /* EA_MODE_PD7 */
\r
403 10, /* EA_MODE_DI */
\r
404 14, /* EA_MODE_IX */
\r
405 10, /* EA_MODE_AW */
\r
406 14, /* EA_MODE_AL */
\r
407 10, /* EA_MODE_PCDI */
\r
408 14, /* EA_MODE_PCIX */
\r
412 /* Extra cycles for MOVEM instruction (000, 010) */
\r
413 int g_movem_cycle_table[13] =
\r
415 0, /* EA_MODE_NONE */
\r
416 0, /* EA_MODE_AI */
\r
417 0, /* EA_MODE_PI */
\r
418 0, /* EA_MODE_PI7 */
\r
419 0, /* EA_MODE_PD */
\r
420 0, /* EA_MODE_PD7 */
\r
421 4, /* EA_MODE_DI */
\r
422 6, /* EA_MODE_IX */
\r
423 4, /* EA_MODE_AW */
\r
424 8, /* EA_MODE_AL */
\r
425 0, /* EA_MODE_PCDI */
\r
426 0, /* EA_MODE_PCIX */
\r
430 /* Extra cycles for MOVES instruction (010) */
\r
431 int g_moves_cycle_table[13][3] =
\r
433 { 0, 0, 0}, /* EA_MODE_NONE */
\r
434 { 0, 4, 6}, /* EA_MODE_AI */
\r
435 { 0, 4, 6}, /* EA_MODE_PI */
\r
436 { 0, 4, 6}, /* EA_MODE_PI7 */
\r
437 { 0, 6, 12}, /* EA_MODE_PD */
\r
438 { 0, 6, 12}, /* EA_MODE_PD7 */
\r
439 { 0, 12, 16}, /* EA_MODE_DI */
\r
440 { 0, 16, 20}, /* EA_MODE_IX */
\r
441 { 0, 12, 16}, /* EA_MODE_AW */
\r
442 { 0, 16, 20}, /* EA_MODE_AL */
\r
443 { 0, 0, 0}, /* EA_MODE_PCDI */
\r
444 { 0, 0, 0}, /* EA_MODE_PCIX */
\r
445 { 0, 0, 0}, /* EA_MODE_I */
\r
448 /* Extra cycles for CLR instruction (010) */
\r
449 int g_clr_cycle_table[13][3] =
\r
451 { 0, 0, 0}, /* EA_MODE_NONE */
\r
452 { 0, 4, 6}, /* EA_MODE_AI */
\r
453 { 0, 4, 6}, /* EA_MODE_PI */
\r
454 { 0, 4, 6}, /* EA_MODE_PI7 */
\r
455 { 0, 6, 8}, /* EA_MODE_PD */
\r
456 { 0, 6, 8}, /* EA_MODE_PD7 */
\r
457 { 0, 8, 10}, /* EA_MODE_DI */
\r
458 { 0, 10, 14}, /* EA_MODE_IX */
\r
459 { 0, 8, 10}, /* EA_MODE_AW */
\r
460 { 0, 10, 14}, /* EA_MODE_AL */
\r
461 { 0, 0, 0}, /* EA_MODE_PCDI */
\r
462 { 0, 0, 0}, /* EA_MODE_PCIX */
\r
463 { 0, 0, 0}, /* EA_MODE_I */
\r
468 /* ======================================================================== */
\r
469 /* =========================== UTILITY FUNCTIONS ========================== */
\r
470 /* ======================================================================== */
\r
472 /* Print an error message and exit with status error */
\r
473 void error_exit(const char* fmt, ...)
\r
476 fprintf(stderr, "In %s, near or on line %d:\n\t", g_input_filename, g_line_number);
\r
477 va_start(args, fmt);
\r
478 vfprintf(stderr, fmt, args);
\r
480 fprintf(stderr, "\n");
\r
482 if(g_prototype_file) fclose(g_prototype_file);
\r
483 if(g_table_file) fclose(g_table_file);
\r
484 if(g_ops_ac_file) fclose(g_ops_ac_file);
\r
485 if(g_ops_dm_file) fclose(g_ops_dm_file);
\r
486 if(g_ops_nz_file) fclose(g_ops_nz_file);
\r
487 if(g_input_file) fclose(g_input_file);
\r
489 exit(EXIT_FAILURE);
\r
492 /* Print an error message, call perror(), and exit with status error */
\r
493 void perror_exit(const char* fmt, ...)
\r
496 va_start(args, fmt);
\r
497 vfprintf(stderr, fmt, args);
\r
501 if(g_prototype_file) fclose(g_prototype_file);
\r
502 if(g_table_file) fclose(g_table_file);
\r
503 if(g_ops_ac_file) fclose(g_ops_ac_file);
\r
504 if(g_ops_dm_file) fclose(g_ops_dm_file);
\r
505 if(g_ops_nz_file) fclose(g_ops_nz_file);
\r
506 if(g_input_file) fclose(g_input_file);
\r
508 exit(EXIT_FAILURE);
\r
512 /* copy until 0 or space and exit with error if we read too far */
\r
513 int check_strsncpy(char* dst, char* src, int maxlength)
\r
516 while(*src && *src != ' ')
\r
519 if(p - dst > maxlength)
\r
520 error_exit("Field too long");
\r
526 /* copy until 0 or specified character and exit with error if we read too far */
\r
527 int check_strcncpy(char* dst, char* src, char delim, int maxlength)
\r
530 while(*src && *src != delim)
\r
533 if(p - dst > maxlength)
\r
534 error_exit("Field too long");
\r
540 /* convert ascii to integer and exit with error if we find invalid data */
\r
541 int check_atoi(char* str, int *result)
\r
545 while(*p >= '0' && *p <= '9')
\r
548 accum += *p++ - '0';
\r
550 if(*p != ' ' && *p != 0)
\r
551 error_exit("Malformed integer value (%c)", *p);
\r
556 /* Skip past spaces in a string */
\r
557 int skip_spaces(char* str)
\r
567 /* Count the number of set bits in a value */
\r
568 int num_bits(int value)
\r
570 value = ((value & 0xaaaa) >> 1) + (value & 0x5555);
\r
571 value = ((value & 0xcccc) >> 2) + (value & 0x3333);
\r
572 value = ((value & 0xf0f0) >> 4) + (value & 0x0f0f);
\r
573 value = ((value & 0xff00) >> 8) + (value & 0x00ff);
\r
577 /* Convert a hex value written in ASCII */
\r
578 int atoh(char* buff)
\r
584 if(*buff >= '0' && *buff <= '9')
\r
587 accum += *buff - '0';
\r
589 else if(*buff >= 'a' && *buff <= 'f')
\r
592 accum += *buff - 'a' + 10;
\r
599 /* Get a line of text from a file, discarding any end-of-line characters */
\r
600 int fgetline(char* buff, int nchars, FILE* file)
\r
604 if(fgets(buff, nchars, file) == NULL)
\r
606 if(buff[0] == '\r')
\r
607 memcpy(buff, buff + 1, nchars - 1);
\r
609 length = strlen(buff);
\r
610 while(length && (buff[length-1] == '\r' || buff[length-1] == '\n'))
\r
620 /* ======================================================================== */
\r
621 /* =========================== HELPER FUNCTIONS =========================== */
\r
622 /* ======================================================================== */
\r
624 /* Calculate the number of cycles an opcode requires */
\r
625 int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type)
\r
627 int size = g_size_select_table[op->size];
\r
629 if(op->cpus[cpu_type] == '.')
\r
632 if(cpu_type < CPU_TYPE_020)
\r
634 if(cpu_type == CPU_TYPE_010)
\r
636 if(strcmp(op->name, "moves") == 0)
\r
637 return op->cycles[cpu_type] + g_moves_cycle_table[ea_mode][size];
\r
638 if(strcmp(op->name, "clr") == 0)
\r
639 return op->cycles[cpu_type] + g_clr_cycle_table[ea_mode][size];
\r
642 /* ASG: added these cases -- immediate modes take 2 extra cycles here */
\r
643 /* SV: but only when operating on long, and also on register direct mode */
\r
644 if(cpu_type == CPU_TYPE_000 && (ea_mode == EA_MODE_I || ea_mode == EA_MODE_NONE) && op->size == 32 &&
\r
645 ((strcmp(op->name, "add") == 0 && strcmp(op->spec_proc, "er") == 0) ||
\r
646 strcmp(op->name, "adda") == 0 ||
\r
647 (strcmp(op->name, "and") == 0 && strcmp(op->spec_proc, "er") == 0) ||
\r
648 (strcmp(op->name, "or") == 0 && strcmp(op->spec_proc, "er") == 0) ||
\r
649 (strcmp(op->name, "sub") == 0 && strcmp(op->spec_proc, "er") == 0) ||
\r
650 strcmp(op->name, "suba") == 0))
\r
651 return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size] + 2;
\r
653 if(strcmp(op->name, "jmp") == 0)
\r
654 return op->cycles[cpu_type] + g_jmp_cycle_table[ea_mode];
\r
655 if(strcmp(op->name, "jsr") == 0)
\r
656 return op->cycles[cpu_type] + g_jsr_cycle_table[ea_mode];
\r
657 if(strcmp(op->name, "lea") == 0)
\r
658 return op->cycles[cpu_type] + g_lea_cycle_table[ea_mode];
\r
659 if(strcmp(op->name, "pea") == 0)
\r
660 return op->cycles[cpu_type] + g_pea_cycle_table[ea_mode];
\r
661 if(strcmp(op->name, "movem") == 0)
\r
662 return op->cycles[cpu_type] + g_movem_cycle_table[ea_mode];
\r
664 return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size];
\r
667 /* Find an opcode in the opcode handler list */
\r
668 opcode_struct* find_opcode(char* name, int size, char* spec_proc, char* spec_ea)
\r
673 for(op = g_opcode_input_table;op->name != NULL;op++)
\r
675 if( strcmp(name, op->name) == 0 &&
\r
676 (size == op->size) &&
\r
677 strcmp(spec_proc, op->spec_proc) == 0 &&
\r
678 strcmp(spec_ea, op->spec_ea) == 0)
\r
684 /* Specifically find the illegal opcode in the list */
\r
685 opcode_struct* find_illegal_opcode(void)
\r
689 for(op = g_opcode_input_table;op->name != NULL;op++)
\r
691 if(strcmp(op->name, "illegal") == 0)
\r
697 /* Parse an opcode handler name */
\r
698 int extract_opcode_info(char* src, char* name, int* size, char* spec_proc, char* spec_ea)
\r
700 char* ptr = strstr(src, ID_OPHANDLER_NAME);
\r
705 ptr += strlen(ID_OPHANDLER_NAME) + 1;
\r
707 ptr += check_strcncpy(name, ptr, ',', MAX_NAME_LENGTH);
\r
708 if(*ptr != ',') return 0;
\r
710 ptr += skip_spaces(ptr);
\r
713 ptr = strstr(ptr, ",");
\r
714 if(ptr == NULL) return 0;
\r
716 ptr += skip_spaces(ptr);
\r
718 ptr += check_strcncpy(spec_proc, ptr, ',', MAX_SPEC_PROC_LENGTH);
\r
719 if(*ptr != ',') return 0;
\r
721 ptr += skip_spaces(ptr);
\r
723 ptr += check_strcncpy(spec_ea, ptr, ')', MAX_SPEC_EA_LENGTH);
\r
724 if(*ptr != ')') return 0;
\r
726 ptr += skip_spaces(ptr);
\r
732 /* Add a search/replace pair to a replace structure */
\r
733 void add_replace_string(replace_struct* replace, const char* search_str, const char* replace_str)
\r
735 if(replace->length >= MAX_REPLACE_LENGTH)
\r
736 error_exit("overflow in replace structure");
\r
738 strcpy(replace->replace[replace->length][0], search_str);
\r
739 strcpy(replace->replace[replace->length++][1], replace_str);
\r
742 /* Write a function body while replacing any selected strings */
\r
743 void write_body(FILE* filep, body_struct* body, replace_struct* replace)
\r
748 char output[MAX_LINE_LENGTH+1];
\r
749 char temp_buff[MAX_LINE_LENGTH+1];
\r
752 for(i=0;i<body->length;i++)
\r
754 strcpy(output, body->body[i]);
\r
755 /* Check for the base directive header */
\r
756 if(strstr(output, ID_BASE) != NULL)
\r
758 /* Search for any text we need to replace */
\r
760 for(j=0;j<replace->length;j++)
\r
762 ptr = strstr(output, replace->replace[j][0]);
\r
765 /* We found something to replace */
\r
767 strcpy(temp_buff, ptr+strlen(replace->replace[j][0]));
\r
768 strcpy(ptr, replace->replace[j][1]);
\r
769 strcat(ptr, temp_buff);
\r
772 /* Found a directive with no matching replace string */
\r
774 error_exit("Unknown " ID_BASE " directive");
\r
776 fprintf(filep, "%s\n", output);
\r
778 fprintf(filep, "\n\n");
\r
781 /* Generate a base function name from an opcode struct */
\r
782 void get_base_name(char* base_name, opcode_struct* op)
\r
784 sprintf(base_name, "m68k_op_%s", op->name);
\r
786 sprintf(base_name+strlen(base_name), "_%d", op->size);
\r
787 if(strcmp(op->spec_proc, UNSPECIFIED) != 0)
\r
788 sprintf(base_name+strlen(base_name), "_%s", op->spec_proc);
\r
789 if(strcmp(op->spec_ea, UNSPECIFIED) != 0)
\r
790 sprintf(base_name+strlen(base_name), "_%s", op->spec_ea);
\r
793 /* Write the prototype of an opcode handler function */
\r
794 void write_prototype(FILE* filep, char* base_name)
\r
796 fprintf(filep, "void %s(void);\n", base_name);
\r
799 /* Write the name of an opcode handler function */
\r
800 void write_function_name(FILE* filep, char* base_name)
\r
802 fprintf(filep, "void %s(void)\n", base_name);
\r
805 void add_opcode_output_table_entry(opcode_struct* op, char* name)
\r
807 opcode_struct* ptr;
\r
808 if(g_opcode_output_table_length > MAX_OPCODE_OUTPUT_TABLE_LENGTH)
\r
809 error_exit("Opcode output table overflow");
\r
811 ptr = g_opcode_output_table + g_opcode_output_table_length++;
\r
814 strcpy(ptr->name, name);
\r
815 ptr->bits = num_bits(ptr->op_mask);
\r
819 * Comparison function for qsort()
\r
820 * For entries with an equal number of set bits in
\r
821 * the mask compare the match values
\r
823 static int DECL_SPEC compare_nof_true_bits(const void* aptr, const void* bptr)
\r
825 const opcode_struct *a = aptr, *b = bptr;
\r
826 if(a->bits != b->bits)
\r
827 return a->bits - b->bits;
\r
828 if(a->op_mask != b->op_mask)
\r
829 return a->op_mask - b->op_mask;
\r
830 return a->op_match - b->op_match;
\r
833 void print_opcode_output_table(FILE* filep)
\r
836 qsort((void *)g_opcode_output_table, g_opcode_output_table_length, sizeof(g_opcode_output_table[0]), compare_nof_true_bits);
\r
838 for(i=0;i<g_opcode_output_table_length;i++)
\r
839 write_table_entry(filep, g_opcode_output_table+i);
\r
842 /* Write an entry in the opcode handler table */
\r
843 void write_table_entry(FILE* filep, opcode_struct* op)
\r
847 fprintf(filep, "\t{%-28s, 0x%04x, 0x%04x, {",
\r
848 op->name, op->op_mask, op->op_match);
\r
850 for(i=0;i<NUM_CPUS;i++)
\r
852 fprintf(filep, "%3d", op->cycles[i]);
\r
854 fprintf(filep, ", ");
\r
857 fprintf(filep, "}},\n");
\r
860 /* Fill out an opcode struct with a specific addressing mode of the source opcode struct */
\r
861 void set_opcode_struct(opcode_struct* src, opcode_struct* dst, int ea_mode)
\r
867 for(i=0;i<NUM_CPUS;i++)
\r
868 dst->cycles[i] = get_oper_cycles(dst, ea_mode, i);
\r
869 if(strcmp(dst->spec_ea, UNSPECIFIED) == 0 && ea_mode != EA_MODE_NONE)
\r
870 sprintf(dst->spec_ea, "%s", g_ea_info_table[ea_mode].fname_add);
\r
871 dst->op_mask |= g_ea_info_table[ea_mode].mask_add;
\r
872 dst->op_match |= g_ea_info_table[ea_mode].match_add;
\r
876 /* Generate a final opcode handler from the provided data */
\r
877 void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* opinfo, int ea_mode)
\r
879 char str[MAX_LINE_LENGTH+1];
\r
880 opcode_struct* op = malloc(sizeof(opcode_struct));
\r
882 /* Set the opcode structure and write the tables, prototypes, etc */
\r
883 set_opcode_struct(opinfo, op, ea_mode);
\r
884 get_base_name(str, op);
\r
885 write_prototype(g_prototype_file, str);
\r
886 add_opcode_output_table_entry(op, str);
\r
887 write_function_name(filep, str);
\r
889 /* Add any replace strings needed */
\r
890 if(ea_mode != EA_MODE_NONE)
\r
892 sprintf(str, "EA_%s_8()", g_ea_info_table[ea_mode].ea_add);
\r
893 add_replace_string(replace, ID_OPHANDLER_EA_AY_8, str);
\r
894 sprintf(str, "EA_%s_16()", g_ea_info_table[ea_mode].ea_add);
\r
895 add_replace_string(replace, ID_OPHANDLER_EA_AY_16, str);
\r
896 sprintf(str, "EA_%s_32()", g_ea_info_table[ea_mode].ea_add);
\r
897 add_replace_string(replace, ID_OPHANDLER_EA_AY_32, str);
\r
898 sprintf(str, "OPER_%s_8()", g_ea_info_table[ea_mode].ea_add);
\r
899 add_replace_string(replace, ID_OPHANDLER_OPER_AY_8, str);
\r
900 sprintf(str, "OPER_%s_16()", g_ea_info_table[ea_mode].ea_add);
\r
901 add_replace_string(replace, ID_OPHANDLER_OPER_AY_16, str);
\r
902 sprintf(str, "OPER_%s_32()", g_ea_info_table[ea_mode].ea_add);
\r
903 add_replace_string(replace, ID_OPHANDLER_OPER_AY_32, str);
\r
906 /* Now write the function body with the selected replace strings */
\r
907 write_body(filep, body, replace);
\r
912 /* Generate opcode variants based on available addressing modes */
\r
913 void generate_opcode_ea_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op)
\r
915 int old_length = replace->length;
\r
917 /* No ea modes available for this opcode */
\r
918 if(HAS_NO_EA_MODE(op->ea_allowed))
\r
920 generate_opcode_handler(filep, body, replace, op, EA_MODE_NONE);
\r
924 /* Check for and create specific opcodes for each available addressing mode */
\r
925 if(HAS_EA_AI(op->ea_allowed))
\r
926 generate_opcode_handler(filep, body, replace, op, EA_MODE_AI);
\r
927 replace->length = old_length;
\r
928 if(HAS_EA_PI(op->ea_allowed))
\r
930 generate_opcode_handler(filep, body, replace, op, EA_MODE_PI);
\r
931 replace->length = old_length;
\r
933 generate_opcode_handler(filep, body, replace, op, EA_MODE_PI7);
\r
935 replace->length = old_length;
\r
936 if(HAS_EA_PD(op->ea_allowed))
\r
938 generate_opcode_handler(filep, body, replace, op, EA_MODE_PD);
\r
939 replace->length = old_length;
\r
941 generate_opcode_handler(filep, body, replace, op, EA_MODE_PD7);
\r
943 replace->length = old_length;
\r
944 if(HAS_EA_DI(op->ea_allowed))
\r
945 generate_opcode_handler(filep, body, replace, op, EA_MODE_DI);
\r
946 replace->length = old_length;
\r
947 if(HAS_EA_IX(op->ea_allowed))
\r
948 generate_opcode_handler(filep, body, replace, op, EA_MODE_IX);
\r
949 replace->length = old_length;
\r
950 if(HAS_EA_AW(op->ea_allowed))
\r
951 generate_opcode_handler(filep, body, replace, op, EA_MODE_AW);
\r
952 replace->length = old_length;
\r
953 if(HAS_EA_AL(op->ea_allowed))
\r
954 generate_opcode_handler(filep, body, replace, op, EA_MODE_AL);
\r
955 replace->length = old_length;
\r
956 if(HAS_EA_PCDI(op->ea_allowed))
\r
957 generate_opcode_handler(filep, body, replace, op, EA_MODE_PCDI);
\r
958 replace->length = old_length;
\r
959 if(HAS_EA_PCIX(op->ea_allowed))
\r
960 generate_opcode_handler(filep, body, replace, op, EA_MODE_PCIX);
\r
961 replace->length = old_length;
\r
962 if(HAS_EA_I(op->ea_allowed))
\r
963 generate_opcode_handler(filep, body, replace, op, EA_MODE_I);
\r
964 replace->length = old_length;
\r
967 /* Generate variants of condition code opcodes */
\r
968 void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op_in, int offset)
\r
973 int old_length = replace->length;
\r
974 opcode_struct* op = malloc(sizeof(opcode_struct));
\r
978 op->op_mask |= 0x0f00;
\r
980 /* Do all condition codes except t and f */
\r
983 /* Add replace strings for this condition code */
\r
984 sprintf(repl, "COND_%s()", g_cc_table[i][1]);
\r
985 sprintf(replnot, "COND_NOT_%s()", g_cc_table[i][1]);
\r
987 add_replace_string(replace, ID_OPHANDLER_CC, repl);
\r
988 add_replace_string(replace, ID_OPHANDLER_NOT_CC, replnot);
\r
990 /* Set the new opcode info */
\r
991 strcpy(op->name+offset, g_cc_table[i][0]);
\r
993 op->op_match = (op->op_match & 0xf0ff) | (i<<8);
\r
995 /* Generate all opcode variants for this modified opcode */
\r
996 generate_opcode_ea_variants(filep, body, replace, op);
\r
997 /* Remove the above replace strings */
\r
998 replace->length = old_length;
\r
1003 /* Process the opcode handlers section of the input file */
\r
1004 void process_opcode_handlers(void)
\r
1006 FILE* input_file = g_input_file;
\r
1007 FILE* output_file;
\r
1008 char func_name[MAX_LINE_LENGTH+1];
\r
1009 char oper_name[MAX_LINE_LENGTH+1];
\r
1011 char oper_spec_proc[MAX_LINE_LENGTH+1];
\r
1012 char oper_spec_ea[MAX_LINE_LENGTH+1];
\r
1013 opcode_struct* opinfo;
\r
1014 replace_struct* replace = malloc(sizeof(replace_struct));
\r
1015 body_struct* body = malloc(sizeof(body_struct));
\r
1018 output_file = g_ops_ac_file;
\r
1022 /* Find the first line of the function */
\r
1024 while(strstr(func_name, ID_OPHANDLER_NAME) == NULL)
\r
1026 if(strcmp(func_name, ID_INPUT_SEPARATOR) == 0)
\r
1030 return; /* all done */
\r
1032 if(fgetline(func_name, MAX_LINE_LENGTH, input_file) < 0)
\r
1033 error_exit("Premature end of file when getting function name");
\r
1035 /* Get the rest of the function */
\r
1036 for(body->length=0;;body->length++)
\r
1038 if(body->length > MAX_BODY_LENGTH)
\r
1039 error_exit("Function too long");
\r
1041 if(fgetline(body->body[body->length], MAX_LINE_LENGTH, input_file) < 0)
\r
1042 error_exit("Premature end of file when getting function body");
\r
1044 if(body->body[body->length][0] == '}')
\r
1051 g_num_primitives++;
\r
1053 /* Extract the function name information */
\r
1054 if(!extract_opcode_info(func_name, oper_name, &oper_size, oper_spec_proc, oper_spec_ea))
\r
1055 error_exit("Invalid " ID_OPHANDLER_NAME " format");
\r
1057 /* Find the corresponding table entry */
\r
1058 opinfo = find_opcode(oper_name, oper_size, oper_spec_proc, oper_spec_ea);
\r
1059 if(opinfo == NULL)
\r
1060 error_exit("Unable to find matching table entry for %s", func_name);
\r
1062 /* Change output files if we pass 'c' or 'n' */
\r
1063 if(output_file == g_ops_ac_file && oper_name[0] > 'c')
\r
1064 output_file = g_ops_dm_file;
\r
1065 else if(output_file == g_ops_dm_file && oper_name[0] > 'm')
\r
1066 output_file = g_ops_nz_file;
\r
1068 replace->length = 0;
\r
1070 /* Generate opcode variants */
\r
1071 if(strcmp(opinfo->name, "bcc") == 0 || strcmp(opinfo->name, "scc") == 0)
\r
1072 generate_opcode_cc_variants(output_file, body, replace, opinfo, 1);
\r
1073 else if(strcmp(opinfo->name, "dbcc") == 0)
\r
1074 generate_opcode_cc_variants(output_file, body, replace, opinfo, 2);
\r
1075 else if(strcmp(opinfo->name, "trapcc") == 0)
\r
1076 generate_opcode_cc_variants(output_file, body, replace, opinfo, 4);
\r
1078 generate_opcode_ea_variants(output_file, body, replace, opinfo);
\r
1086 /* Populate the opcode handler table from the input file */
\r
1087 void populate_table(void)
\r
1090 char bitpattern[17];
\r
1091 opcode_struct* op;
\r
1092 char buff[MAX_LINE_LENGTH];
\r
1098 /* Find the start of the table */
\r
1099 while(strcmp(buff, ID_TABLE_START) != 0)
\r
1100 if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0)
\r
1101 error_exit("Premature EOF while reading table");
\r
1103 /* Process the entire table */
\r
1104 for(op = g_opcode_input_table;;op++)
\r
1106 if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0)
\r
1107 error_exit("Premature EOF while reading table");
\r
1108 if(strlen(buff) == 0)
\r
1110 /* We finish when we find an input separator */
\r
1111 if(strcmp(buff, ID_INPUT_SEPARATOR) == 0)
\r
1114 /* Extract the info from the table */
\r
1118 ptr += skip_spaces(ptr);
\r
1119 ptr += check_strsncpy(op->name, ptr, MAX_NAME_LENGTH);
\r
1122 ptr += skip_spaces(ptr);
\r
1123 ptr += check_atoi(ptr, &temp);
\r
1124 op->size = (unsigned char)temp;
\r
1126 /* Special processing */
\r
1127 ptr += skip_spaces(ptr);
\r
1128 ptr += check_strsncpy(op->spec_proc, ptr, MAX_SPEC_PROC_LENGTH);
\r
1130 /* Specified EA Mode */
\r
1131 ptr += skip_spaces(ptr);
\r
1132 ptr += check_strsncpy(op->spec_ea, ptr, MAX_SPEC_EA_LENGTH);
\r
1134 /* Bit Pattern (more processing later) */
\r
1135 ptr += skip_spaces(ptr);
\r
1136 ptr += check_strsncpy(bitpattern, ptr, 17);
\r
1138 /* Allowed Addressing Mode List */
\r
1139 ptr += skip_spaces(ptr);
\r
1140 ptr += check_strsncpy(op->ea_allowed, ptr, EA_ALLOWED_LENGTH);
\r
1142 /* CPU operating mode (U = user or supervisor, S = supervisor only */
\r
1143 ptr += skip_spaces(ptr);
\r
1144 for(i=0;i<NUM_CPUS;i++)
\r
1146 op->cpu_mode[i] = *ptr++;
\r
1147 ptr += skip_spaces(ptr);
\r
1150 /* Allowed CPUs for this instruction */
\r
1151 for(i=0;i<NUM_CPUS;i++)
\r
1153 ptr += skip_spaces(ptr);
\r
1154 if(*ptr == UNSPECIFIED_CH)
\r
1156 op->cpus[i] = UNSPECIFIED_CH;
\r
1157 op->cycles[i] = 0;
\r
1162 op->cpus[i] = '0' + i;
\r
1163 ptr += check_atoi(ptr, &temp);
\r
1164 op->cycles[i] = (unsigned char)temp;
\r
1168 /* generate mask and match from bitpattern */
\r
1173 op->op_mask |= (bitpattern[i] != '.') << (15-i);
\r
1174 op->op_match |= (bitpattern[i] == '1') << (15-i);
\r
1177 /* Terminate the list */
\r
1181 /* Read a header or footer insert from the input file */
\r
1182 void read_insert(char* insert)
\r
1184 char* ptr = insert;
\r
1185 char* overflow = insert + MAX_INSERT_LENGTH - MAX_LINE_LENGTH;
\r
1187 char* first_blank = NULL;
\r
1189 first_blank = NULL;
\r
1191 /* Skip any leading blank lines */
\r
1192 for(length = 0;length == 0;length = fgetline(ptr, MAX_LINE_LENGTH, g_input_file))
\r
1193 if(ptr >= overflow)
\r
1194 error_exit("Buffer overflow reading inserts");
\r
1196 error_exit("Premature EOF while reading inserts");
\r
1198 /* Advance and append newline */
\r
1200 strcpy(ptr++, "\n");
\r
1202 /* Read until next separator */
\r
1205 /* Read a new line */
\r
1206 if(ptr >= overflow)
\r
1207 error_exit("Buffer overflow reading inserts");
\r
1208 if((length = fgetline(ptr, MAX_LINE_LENGTH, g_input_file)) < 0)
\r
1209 error_exit("Premature EOF while reading inserts");
\r
1211 /* Stop if we read a separator */
\r
1212 if(strcmp(ptr, ID_INPUT_SEPARATOR) == 0)
\r
1215 /* keep track in case there are trailing blanks */
\r
1218 if(first_blank == NULL)
\r
1219 first_blank = ptr;
\r
1222 first_blank = NULL;
\r
1224 /* Advance and append newline */
\r
1226 strcpy(ptr++, "\n");
\r
1229 /* kill any trailing blank lines */
\r
1231 ptr = first_blank;
\r
1237 /* ======================================================================== */
\r
1238 /* ============================= MAIN FUNCTION ============================ */
\r
1239 /* ======================================================================== */
\r
1241 int main(int argc, char **argv)
\r
1244 char output_path[M68K_MAX_DIR] = "";
\r
1245 char filename[M68K_MAX_PATH];
\r
1246 /* Section identifier */
\r
1247 char section_id[MAX_LINE_LENGTH+1];
\r
1249 char temp_insert[MAX_INSERT_LENGTH+1];
\r
1250 char prototype_footer_insert[MAX_INSERT_LENGTH+1];
\r
1251 char table_footer_insert[MAX_INSERT_LENGTH+1];
\r
1252 char ophandler_footer_insert[MAX_INSERT_LENGTH+1];
\r
1253 /* Flags if we've processed certain parts already */
\r
1254 int prototype_header_read = 0;
\r
1255 int prototype_footer_read = 0;
\r
1256 int table_header_read = 0;
\r
1257 int table_footer_read = 0;
\r
1258 int ophandler_header_read = 0;
\r
1259 int ophandler_footer_read = 0;
\r
1260 int table_body_read = 0;
\r
1261 int ophandler_body_read = 0;
\r
1263 printf("\n\t\tMusashi v%s 68000, 68008, 68010, 68EC020, 68020 emulator\n", g_version);
\r
1264 printf("\t\tCopyright 1998-2000 Karl Stenerud (karl@mame.net)\n\n");
\r
1266 /* Check if output path and source for the input file are given */
\r
1270 strcpy(output_path, argv[1]);
\r
1272 for(ptr = strchr(output_path, '\\'); ptr; ptr = strchr(ptr, '\\'))
\r
1275 #if !(defined(__DECC) && defined(VMS))
\r
1276 if(output_path[strlen(output_path)-1] != '/')
\r
1277 strcat(output_path, "/");
\r
1281 strcpy(g_input_filename, argv[2]);
\r
1285 #if defined(__DECC) && defined(VMS)
\r
1287 /* Open the files we need */
\r
1288 sprintf(filename, "%s%s", output_path, FILENAME_PROTOTYPE);
\r
1289 if((g_prototype_file = fopen(filename, "w")) == NULL)
\r
1290 perror_exit("Unable to create prototype file (%s)\n", filename);
\r
1292 sprintf(filename, "%s%s", output_path, FILENAME_TABLE);
\r
1293 if((g_table_file = fopen(filename, "w")) == NULL)
\r
1294 perror_exit("Unable to create table file (%s)\n", filename);
\r
1296 sprintf(filename, "%s%s", output_path, FILENAME_OPS_AC);
\r
1297 if((g_ops_ac_file = fopen(filename, "w")) == NULL)
\r
1298 perror_exit("Unable to create ops ac file (%s)\n", filename);
\r
1300 sprintf(filename, "%s%s", output_path, FILENAME_OPS_DM);
\r
1301 if((g_ops_dm_file = fopen(filename, "w")) == NULL)
\r
1302 perror_exit("Unable to create ops dm file (%s)\n", filename);
\r
1304 sprintf(filename, "%s%s", output_path, FILENAME_OPS_NZ);
\r
1305 if((g_ops_nz_file = fopen(filename, "w")) == NULL)
\r
1306 perror_exit("Unable to create ops nz file (%s)\n", filename);
\r
1308 if((g_input_file=fopen(g_input_filename, "r")) == NULL)
\r
1309 perror_exit("can't open %s for input", g_input_filename);
\r
1314 /* Open the files we need */
\r
1315 sprintf(filename, "%s%s", output_path, FILENAME_PROTOTYPE);
\r
1316 if((g_prototype_file = fopen(filename, "wt")) == NULL)
\r
1317 perror_exit("Unable to create prototype file (%s)\n", filename);
\r
1319 sprintf(filename, "%s%s", output_path, FILENAME_TABLE);
\r
1320 if((g_table_file = fopen(filename, "wt")) == NULL)
\r
1321 perror_exit("Unable to create table file (%s)\n", filename);
\r
1323 sprintf(filename, "%s%s", output_path, FILENAME_OPS_AC);
\r
1324 if((g_ops_ac_file = fopen(filename, "wt")) == NULL)
\r
1325 perror_exit("Unable to create ops ac file (%s)\n", filename);
\r
1327 sprintf(filename, "%s%s", output_path, FILENAME_OPS_DM);
\r
1328 if((g_ops_dm_file = fopen(filename, "wt")) == NULL)
\r
1329 perror_exit("Unable to create ops dm file (%s)\n", filename);
\r
1331 sprintf(filename, "%s%s", output_path, FILENAME_OPS_NZ);
\r
1332 if((g_ops_nz_file = fopen(filename, "wt")) == NULL)
\r
1333 perror_exit("Unable to create ops nz file (%s)\n", filename);
\r
1335 if((g_input_file=fopen(g_input_filename, "rt")) == NULL)
\r
1336 perror_exit("can't open %s for input", g_input_filename);
\r
1340 /* Get to the first section of the input file */
\r
1341 section_id[0] = 0;
\r
1342 while(strcmp(section_id, ID_INPUT_SEPARATOR) != 0)
\r
1343 if(fgetline(section_id, MAX_LINE_LENGTH, g_input_file) < 0)
\r
1344 error_exit("Premature EOF while reading input file");
\r
1346 /* Now process all sections */
\r
1349 if(fgetline(section_id, MAX_LINE_LENGTH, g_input_file) < 0)
\r
1350 error_exit("Premature EOF while reading input file");
\r
1351 if(strcmp(section_id, ID_PROTOTYPE_HEADER) == 0)
\r
1353 if(prototype_header_read)
\r
1354 error_exit("Duplicate prototype header");
\r
1355 read_insert(temp_insert);
\r
1356 fprintf(g_prototype_file, "%s\n\n", temp_insert);
\r
1357 prototype_header_read = 1;
\r
1359 else if(strcmp(section_id, ID_TABLE_HEADER) == 0)
\r
1361 if(table_header_read)
\r
1362 error_exit("Duplicate table header");
\r
1363 read_insert(temp_insert);
\r
1364 fprintf(g_table_file, "%s", temp_insert);
\r
1365 table_header_read = 1;
\r
1367 else if(strcmp(section_id, ID_OPHANDLER_HEADER) == 0)
\r
1369 if(ophandler_header_read)
\r
1370 error_exit("Duplicate opcode handler header");
\r
1371 read_insert(temp_insert);
\r
1372 fprintf(g_ops_ac_file, "%s\n\n", temp_insert);
\r
1373 fprintf(g_ops_dm_file, "%s\n\n", temp_insert);
\r
1374 fprintf(g_ops_nz_file, "%s\n\n", temp_insert);
\r
1375 ophandler_header_read = 1;
\r
1377 else if(strcmp(section_id, ID_PROTOTYPE_FOOTER) == 0)
\r
1379 if(prototype_footer_read)
\r
1380 error_exit("Duplicate prototype footer");
\r
1381 read_insert(prototype_footer_insert);
\r
1382 prototype_footer_read = 1;
\r
1384 else if(strcmp(section_id, ID_TABLE_FOOTER) == 0)
\r
1386 if(table_footer_read)
\r
1387 error_exit("Duplicate table footer");
\r
1388 read_insert(table_footer_insert);
\r
1389 table_footer_read = 1;
\r
1391 else if(strcmp(section_id, ID_OPHANDLER_FOOTER) == 0)
\r
1393 if(ophandler_footer_read)
\r
1394 error_exit("Duplicate opcode handler footer");
\r
1395 read_insert(ophandler_footer_insert);
\r
1396 ophandler_footer_read = 1;
\r
1398 else if(strcmp(section_id, ID_TABLE_BODY) == 0)
\r
1400 if(!prototype_header_read)
\r
1401 error_exit("Table body encountered before prototype header");
\r
1402 if(!table_header_read)
\r
1403 error_exit("Table body encountered before table header");
\r
1404 if(!ophandler_header_read)
\r
1405 error_exit("Table body encountered before opcode handler header");
\r
1407 if(table_body_read)
\r
1408 error_exit("Duplicate table body");
\r
1411 table_body_read = 1;
\r
1413 else if(strcmp(section_id, ID_OPHANDLER_BODY) == 0)
\r
1415 if(!prototype_header_read)
\r
1416 error_exit("Opcode handlers encountered before prototype header");
\r
1417 if(!table_header_read)
\r
1418 error_exit("Opcode handlers encountered before table header");
\r
1419 if(!ophandler_header_read)
\r
1420 error_exit("Opcode handlers encountered before opcode handler header");
\r
1421 if(!table_body_read)
\r
1422 error_exit("Opcode handlers encountered before table body");
\r
1424 if(ophandler_body_read)
\r
1425 error_exit("Duplicate opcode handler section");
\r
1427 process_opcode_handlers();
\r
1429 ophandler_body_read = 1;
\r
1431 else if(strcmp(section_id, ID_END) == 0)
\r
1433 /* End of input file. Do a sanity check and then write footers */
\r
1434 if(!prototype_header_read)
\r
1435 error_exit("Missing prototype header");
\r
1436 if(!prototype_footer_read)
\r
1437 error_exit("Missing prototype footer");
\r
1438 if(!table_header_read)
\r
1439 error_exit("Missing table header");
\r
1440 if(!table_footer_read)
\r
1441 error_exit("Missing table footer");
\r
1442 if(!table_body_read)
\r
1443 error_exit("Missing table body");
\r
1444 if(!ophandler_header_read)
\r
1445 error_exit("Missing opcode handler header");
\r
1446 if(!ophandler_footer_read)
\r
1447 error_exit("Missing opcode handler footer");
\r
1448 if(!ophandler_body_read)
\r
1449 error_exit("Missing opcode handler body");
\r
1451 print_opcode_output_table(g_table_file);
\r
1453 fprintf(g_prototype_file, "%s\n\n", prototype_footer_insert);
\r
1454 fprintf(g_table_file, "%s\n\n", table_footer_insert);
\r
1455 fprintf(g_ops_ac_file, "%s\n\n", ophandler_footer_insert);
\r
1456 fprintf(g_ops_dm_file, "%s\n\n", ophandler_footer_insert);
\r
1457 fprintf(g_ops_nz_file, "%s\n\n", ophandler_footer_insert);
\r
1463 error_exit("Unknown section identifier: %s", section_id);
\r
1467 /* Close all files and exit */
\r
1468 fclose(g_prototype_file);
\r
1469 fclose(g_table_file);
\r
1470 fclose(g_ops_ac_file);
\r
1471 fclose(g_ops_dm_file);
\r
1472 fclose(g_ops_nz_file);
\r
1473 fclose(g_input_file);
\r
1475 printf("Generated %d opcode handlers from %d primitives\n", g_num_functions, g_num_primitives);
\r
1482 /* ======================================================================== */
\r
1483 /* ============================== END OF FILE ============================= */
\r
1484 /* ======================================================================== */
\r