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