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