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