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