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