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