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