bugfix
[picodrive.git] / cpu / musashi / m68kmake.c
CommitLineData
cc68a136 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
55const 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
133enum {\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
156enum\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
175typedef 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
192typedef 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
202typedef 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
210typedef 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
218void error_exit(const char* fmt, ...);\r
219void perror_exit(const char* fmt, ...);\r
220int check_strsncpy(char* dst, char* src, int maxlength);\r
221int check_atoi(char* str, int *result);\r
222int skip_spaces(char* str);\r
223int num_bits(int value);\r
224int atoh(char* buff);\r
225int fgetline(char* buff, int nchars, FILE* file);\r
226int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type);\r
227opcode_struct* find_opcode(char* name, int size, char* spec_proc, char* spec_ea);\r
228opcode_struct* find_illegal_opcode(void);\r
229int extract_opcode_info(char* src, char* name, int* size, char* spec_proc, char* spec_ea);\r
230void add_replace_string(replace_struct* replace, const char* search_str, const char* replace_str);\r
231void write_body(FILE* filep, body_struct* body, replace_struct* replace);\r
232void get_base_name(char* base_name, opcode_struct* op);\r
233void write_prototype(FILE* filep, char* base_name);\r
234void write_function_name(FILE* filep, char* base_name);\r
235void add_opcode_output_table_entry(opcode_struct* op, char* name);\r
236static int DECL_SPEC compare_nof_true_bits(const void* aptr, const void* bptr);\r
237void print_opcode_output_table(FILE* filep);\r
238void write_table_entry(FILE* filep, opcode_struct* op);\r
239void set_opcode_struct(opcode_struct* src, opcode_struct* dst, int ea_mode);\r
240void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* opinfo, int ea_mode);\r
241void generate_opcode_ea_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op);\r
242void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op_in, int offset);\r
243void process_opcode_handlers(void);\r
244void populate_table(void);\r
245void 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
254char g_input_filename[M68K_MAX_PATH] = FILENAME_INPUT;\r
255\r
256/* File handles */\r
257FILE* g_input_file = NULL;\r
258FILE* g_prototype_file = NULL;\r
259FILE* g_table_file = NULL;\r
260FILE* g_ops_ac_file = NULL;\r
261FILE* g_ops_dm_file = NULL;\r
262FILE* g_ops_nz_file = NULL;\r
263\r
264int g_num_functions = 0; /* Number of functions processed */\r
265int g_num_primitives = 0; /* Number of function primitives read */\r
266int g_line_number = 1; /* Current line number */\r
267\r
268/* Opcode handler table */\r
269opcode_struct g_opcode_input_table[MAX_OPCODE_INPUT_TABLE_LENGTH];\r
270\r
271opcode_struct g_opcode_output_table[MAX_OPCODE_OUTPUT_TABLE_LENGTH];\r
272int g_opcode_output_table_length = 0;\r
273\r
274ea_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
292const 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
313int 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
323int 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
341int 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
359int 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
377int 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
395int 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
413int 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
431int 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
449int 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
473void 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
493void 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
513int 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
527int 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
541int 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
557int 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
568int 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
578int 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
600int 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
625int 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
668opcode_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
685opcode_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
698int 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
733void 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
743void 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
782void 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
794void 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
800void 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
805void 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
823static 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
833void 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
843void 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
861void 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
877void 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
913void 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
968void 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
1004void 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
1087void 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
1182void 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
1241int 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