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