source: buchla-emu/cpu/m68kmake.c@ 7ba3613

Last change on this file since 7ba3613 was 93280c2, checked in by Thomas Lopatic <thomas@…>, 7 years ago

Added Musashi CPU emulator.

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