simh-testsetgenerator/AltairZ80/m68k/m68kmake.c
Mark Pizzolato decbe5b76b Various simulators: Set line endings to CRLF for consistency, remove stray tabs
Project standard source code has tabs converted to spaces and CRLF line
endings.

Other text files have CRLF line endings.
2023-03-19 16:51:27 -04:00

1408 lines
44 KiB
C

/* ======================================================================== */
/* ========================= LICENSING & COPYRIGHT ======================== */
/* ======================================================================== */
/*
* MUSASHI
* Version 4.60
*
* A portable Motorola M680x0 processor emulation engine.
* Copyright Karl Stenerud. All rights reserved.
* FPU and MMU by R. Belmont.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/* ======================================================================== */
/* ============================ CODE GENERATOR ============================ */
/* ======================================================================== */
/*
* This is the code generator program which will generate the opcode table
* and the final opcode handlers.
*
* It requires an input file to function (default m68k_in.c), but you can
* specify your own like so:
*
* m68kmake <output path> <input file>
*
* where output path is the path where the output files should be placed, and
* input file is the file to use for input.
*
* If you modify the input file greatly from its released form, you may have
* to tweak the configuration section a bit since I'm using static allocation
* to keep things simple.
*
*
* TODO: - build a better code generator for the move instruction.
* - Add callm and rtm instructions
* - Fix RTE to handle other format words
* - Add address error (and bus error?) handling
*/
static const char g_version[] = "4.60";
/* ======================================================================== */
/* =============================== INCLUDES =============================== */
/* ======================================================================== */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
/* ======================================================================== */
/* ============================= CONFIGURATION ============================ */
/* ======================================================================== */
#define M68K_MAX_PATH 1024
#define M68K_MAX_DIR 1024
#define MAX_LINE_LENGTH 200 /* length of 1 line */
#define MAX_BODY_LENGTH 300 /* Number of lines in 1 function */
#define MAX_REPLACE_LENGTH 30 /* Max number of replace strings */
#define MAX_INSERT_LENGTH 5000 /* Max size of insert piece */
#define MAX_NAME_LENGTH 30 /* Max length of ophandler name */
#define MAX_SPEC_PROC_LENGTH 4 /* Max length of special processing str */
#define MAX_SPEC_EA_LENGTH 5 /* Max length of specified EA str */
#define EA_ALLOWED_LENGTH 11 /* Max length of ea allowed str */
#define MAX_OPCODE_INPUT_TABLE_LENGTH 1000 /* Max length of opcode handler tbl */
#define MAX_OPCODE_OUTPUT_TABLE_LENGTH 3000 /* Max length of opcode handler tbl */
/* Default filenames */
#define FILENAME_INPUT "m68k_in.c"
#define FILENAME_PROTOTYPE "m68kops.h"
#define FILENAME_TABLE "m68kops.c"
/* Identifier sequences recognized by this program */
#define ID_INPUT_SEPARATOR "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
#define ID_BASE "M68KMAKE"
#define ID_PROTOTYPE_HEADER ID_BASE "_PROTOTYPE_HEADER"
#define ID_PROTOTYPE_FOOTER ID_BASE "_PROTOTYPE_FOOTER"
#define ID_TABLE_HEADER ID_BASE "_TABLE_HEADER"
#define ID_TABLE_FOOTER ID_BASE "_TABLE_FOOTER"
#define ID_TABLE_BODY ID_BASE "_TABLE_BODY"
#define ID_TABLE_START ID_BASE "_TABLE_START"
#define ID_OPHANDLER_HEADER ID_BASE "_OPCODE_HANDLER_HEADER"
#define ID_OPHANDLER_FOOTER ID_BASE "_OPCODE_HANDLER_FOOTER"
#define ID_OPHANDLER_BODY ID_BASE "_OPCODE_HANDLER_BODY"
#define ID_END ID_BASE "_END"
#define ID_OPHANDLER_NAME ID_BASE "_OP"
#define ID_OPHANDLER_EA_AY_8 ID_BASE "_GET_EA_AY_8"
#define ID_OPHANDLER_EA_AY_16 ID_BASE "_GET_EA_AY_16"
#define ID_OPHANDLER_EA_AY_32 ID_BASE "_GET_EA_AY_32"
#define ID_OPHANDLER_OPER_AY_8 ID_BASE "_GET_OPER_AY_8"
#define ID_OPHANDLER_OPER_AY_16 ID_BASE "_GET_OPER_AY_16"
#define ID_OPHANDLER_OPER_AY_32 ID_BASE "_GET_OPER_AY_32"
#define ID_OPHANDLER_CC ID_BASE "_CC"
#define ID_OPHANDLER_NOT_CC ID_BASE "_NOT_CC"
#ifndef DECL_SPEC
#define DECL_SPEC
#endif /* DECL_SPEC */
/* ======================================================================== */
/* ============================== PROTOTYPES ============================== */
/* ======================================================================== */
enum {
CPU_TYPE_000=0,
CPU_TYPE_010,
CPU_TYPE_020,
CPU_TYPE_030,
CPU_TYPE_040,
NUM_CPUS
};
#define UNSPECIFIED "."
#define UNSPECIFIED_CH '.'
#define HAS_NO_EA_MODE(A) (strcmp(A, "..........") == 0)
#define HAS_EA_AI(A) ((A)[0] == 'A')
#define HAS_EA_PI(A) ((A)[1] == '+')
#define HAS_EA_PD(A) ((A)[2] == '-')
#define HAS_EA_DI(A) ((A)[3] == 'D')
#define HAS_EA_IX(A) ((A)[4] == 'X')
#define HAS_EA_AW(A) ((A)[5] == 'W')
#define HAS_EA_AL(A) ((A)[6] == 'L')
#define HAS_EA_PCDI(A) ((A)[7] == 'd')
#define HAS_EA_PCIX(A) ((A)[8] == 'x')
#define HAS_EA_I(A) ((A)[9] == 'I')
enum
{
EA_MODE_NONE, /* No special addressing mode */
EA_MODE_AI, /* Address register indirect */
EA_MODE_PI, /* Address register indirect with postincrement */
EA_MODE_PI7, /* Address register 7 indirect with postincrement */
EA_MODE_PD, /* Address register indirect with predecrement */
EA_MODE_PD7, /* Address register 7 indirect with predecrement */
EA_MODE_DI, /* Address register indirect with displacement */
EA_MODE_IX, /* Address register indirect with index */
EA_MODE_AW, /* Absolute word */
EA_MODE_AL, /* Absolute long */
EA_MODE_PCDI, /* Program counter indirect with displacement */
EA_MODE_PCIX, /* Program counter indirect with index */
EA_MODE_I /* Immediate */
};
/* Everything we need to know about an opcode */
typedef struct
{
char name[MAX_NAME_LENGTH]; /* opcode handler name */
unsigned char size; /* Size of operation */
char spec_proc[MAX_SPEC_PROC_LENGTH]; /* Special processing mode */
char spec_ea[MAX_SPEC_EA_LENGTH]; /* Specified effective addressing mode */
unsigned char bits; /* Number of significant bits (used for sorting the table) */
unsigned short op_mask; /* Mask to apply for matching an opcode to a handler */
unsigned short op_match; /* Value to match after masking */
char ea_allowed[EA_ALLOWED_LENGTH]; /* Effective addressing modes allowed */
char cpu_mode[NUM_CPUS]; /* User or supervisor mode */
char cpus[NUM_CPUS+1]; /* Allowed CPUs */
unsigned char cycles[NUM_CPUS]; /* cycles for 000, 010, 020, 030, 040 */
} opcode_struct;
/* All modifications necessary for a specific EA mode of an instruction */
typedef struct
{
char* fname_add;
char* ea_add;
unsigned int mask_add;
unsigned int match_add;
} ea_info_struct;
/* Holds the body of a function */
typedef struct
{
char body[MAX_BODY_LENGTH][MAX_LINE_LENGTH+1];
int length;
} body_struct;
/* Holds a sequence of search / replace strings */
typedef struct
{
char replace[MAX_REPLACE_LENGTH][2][MAX_LINE_LENGTH+1];
int length;
} replace_struct;
/* Function Prototypes */
void error_exit(const char* fmt, ...);
void perror_exit(const char* fmt, ...);
int check_strsncpy(char* dst, char* src, int maxlength);
int check_atoi(char* str, int *result);
int skip_spaces(char* str);
int num_bits(int value);
int atoh(char* buff);
int fgetline(char* buff, int nchars, FILE* file);
int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type);
opcode_struct* find_opcode(char* name, int size, char* spec_proc, char* spec_ea);
opcode_struct* find_illegal_opcode(void);
int extract_opcode_info(char* src, char* name, int* size, char* spec_proc, char* spec_ea);
void add_replace_string(replace_struct* replace, char* search_str, char* replace_str);
void write_body(FILE* filep, body_struct* body, replace_struct* replace);
void get_base_name(char* base_name, opcode_struct* op);
void write_function_name(FILE* filep, char* base_name);
void add_opcode_output_table_entry(opcode_struct* op, char* name);
static int DECL_SPEC compare_nof_true_bits(const void* aptr, const void* bptr);
void print_opcode_output_table(FILE* filep);
void write_table_entry(FILE* filep, opcode_struct* op);
void set_opcode_struct(opcode_struct* src, opcode_struct* dst, int ea_mode);
void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* opinfo, int ea_mode);
void generate_opcode_ea_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op);
void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op_in, int offset);
void process_opcode_handlers(FILE* filep);
void populate_table(void);
void read_insert(char* insert);
/* ======================================================================== */
/* ================================= DATA ================================= */
/* ======================================================================== */
/* Name of the input file */
char g_input_filename[M68K_MAX_PATH] = FILENAME_INPUT;
/* File handles */
FILE* g_input_file = NULL;
FILE* g_prototype_file = NULL;
FILE* g_table_file = NULL;
int g_num_functions = 0; /* Number of functions processed */
int g_num_primitives = 0; /* Number of function primitives read */
int g_line_number = 1; /* Current line number */
/* Opcode handler table */
opcode_struct g_opcode_input_table[MAX_OPCODE_INPUT_TABLE_LENGTH];
opcode_struct g_opcode_output_table[MAX_OPCODE_OUTPUT_TABLE_LENGTH];
int g_opcode_output_table_length = 0;
const ea_info_struct g_ea_info_table[13] =
{/* fname ea mask match */
{"", "", 0x00, 0x00}, /* EA_MODE_NONE */
{"ai", "AY_AI", 0x38, 0x10}, /* EA_MODE_AI */
{"pi", "AY_PI", 0x38, 0x18}, /* EA_MODE_PI */
{"pi7", "A7_PI", 0x3f, 0x1f}, /* EA_MODE_PI7 */
{"pd", "AY_PD", 0x38, 0x20}, /* EA_MODE_PD */
{"pd7", "A7_PD", 0x3f, 0x27}, /* EA_MODE_PD7 */
{"di", "AY_DI", 0x38, 0x28}, /* EA_MODE_DI */
{"ix", "AY_IX", 0x38, 0x30}, /* EA_MODE_IX */
{"aw", "AW", 0x3f, 0x38}, /* EA_MODE_AW */
{"al", "AL", 0x3f, 0x39}, /* EA_MODE_AL */
{"pcdi", "PCDI", 0x3f, 0x3a}, /* EA_MODE_PCDI */
{"pcix", "PCIX", 0x3f, 0x3b}, /* EA_MODE_PCIX */
{"i", "I", 0x3f, 0x3c}, /* EA_MODE_I */
};
const char *const g_cc_table[16][2] =
{
{ "t", "T"}, /* 0000 */
{ "f", "F"}, /* 0001 */
{"hi", "HI"}, /* 0010 */
{"ls", "LS"}, /* 0011 */
{"cc", "CC"}, /* 0100 */
{"cs", "CS"}, /* 0101 */
{"ne", "NE"}, /* 0110 */
{"eq", "EQ"}, /* 0111 */
{"vc", "VC"}, /* 1000 */
{"vs", "VS"}, /* 1001 */
{"pl", "PL"}, /* 1010 */
{"mi", "MI"}, /* 1011 */
{"ge", "GE"}, /* 1100 */
{"lt", "LT"}, /* 1101 */
{"gt", "GT"}, /* 1110 */
{"le", "LE"}, /* 1111 */
};
/* size to index translator (0 -> 0, 8 and 16 -> 1, 32 -> 2) */
const int g_size_select_table[33] =
{
0, /* unsized */
0, 0, 0, 0, 0, 0, 0, 1, /* 8 */
0, 0, 0, 0, 0, 0, 0, 1, /* 16 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 /* 32 */
};
/* Extra cycles required for certain EA modes */
/* TODO: correct timings for 030, 040 */
const int g_ea_cycle_table[13][NUM_CPUS][3] =
{/* 000 010 020 030 040 */
{{ 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}}, /* EA_MODE_NONE */
{{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AI */
{{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_PI */
{{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_PI7 */
{{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PD */
{{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PD7 */
{{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_DI */
{{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}, { 0, 7, 7}, { 0, 7, 7}}, /* EA_MODE_IX */
{{ 0, 8, 12}, { 0, 8, 12}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AW */
{{ 0, 12, 16}, { 0, 12, 16}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AL */
{{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PCDI */
{{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}, { 0, 7, 7}, { 0, 7, 7}}, /* EA_MODE_PCIX */
{{ 0, 4, 8}, { 0, 4, 8}, { 0, 2, 4}, { 0, 2, 4}, { 0, 2, 4}}, /* EA_MODE_I */
};
/* Extra cycles for JMP instruction (000, 010) */
const int g_jmp_cycle_table[13] =
{
0, /* EA_MODE_NONE */
4, /* EA_MODE_AI */
0, /* EA_MODE_PI */
0, /* EA_MODE_PI7 */
0, /* EA_MODE_PD */
0, /* EA_MODE_PD7 */
6, /* EA_MODE_DI */
10, /* EA_MODE_IX */
6, /* EA_MODE_AW */
8, /* EA_MODE_AL */
6, /* EA_MODE_PCDI */
10, /* EA_MODE_PCIX */
0, /* EA_MODE_I */
};
/* Extra cycles for JSR instruction (000, 010) */
const int g_jsr_cycle_table[13] =
{
0, /* EA_MODE_NONE */
4, /* EA_MODE_AI */
0, /* EA_MODE_PI */
0, /* EA_MODE_PI7 */
0, /* EA_MODE_PD */
0, /* EA_MODE_PD7 */
6, /* EA_MODE_DI */
10, /* EA_MODE_IX */
6, /* EA_MODE_AW */
8, /* EA_MODE_AL */
6, /* EA_MODE_PCDI */
10, /* EA_MODE_PCIX */
0, /* EA_MODE_I */
};
/* Extra cycles for LEA instruction (000, 010) */
const int g_lea_cycle_table[13] =
{
0, /* EA_MODE_NONE */
4, /* EA_MODE_AI */
0, /* EA_MODE_PI */
0, /* EA_MODE_PI7 */
0, /* EA_MODE_PD */
0, /* EA_MODE_PD7 */
8, /* EA_MODE_DI */
12, /* EA_MODE_IX */
8, /* EA_MODE_AW */
12, /* EA_MODE_AL */
8, /* EA_MODE_PCDI */
12, /* EA_MODE_PCIX */
0, /* EA_MODE_I */
};
/* Extra cycles for PEA instruction (000, 010) */
const int g_pea_cycle_table[13] =
{
0, /* EA_MODE_NONE */
6, /* EA_MODE_AI */
0, /* EA_MODE_PI */
0, /* EA_MODE_PI7 */
0, /* EA_MODE_PD */
0, /* EA_MODE_PD7 */
10, /* EA_MODE_DI */
14, /* EA_MODE_IX */
10, /* EA_MODE_AW */
14, /* EA_MODE_AL */
10, /* EA_MODE_PCDI */
14, /* EA_MODE_PCIX */
0, /* EA_MODE_I */
};
/* Extra cycles for MOVEM instruction (000, 010) */
const int g_movem_cycle_table[13] =
{
0, /* EA_MODE_NONE */
0, /* EA_MODE_AI */
0, /* EA_MODE_PI */
0, /* EA_MODE_PI7 */
0, /* EA_MODE_PD */
0, /* EA_MODE_PD7 */
4, /* EA_MODE_DI */
6, /* EA_MODE_IX */
4, /* EA_MODE_AW */
8, /* EA_MODE_AL */
0, /* EA_MODE_PCDI */
0, /* EA_MODE_PCIX */
0, /* EA_MODE_I */
};
/* Extra cycles for MOVES instruction (010) */
const int g_moves_cycle_table[13][3] =
{
{ 0, 0, 0}, /* EA_MODE_NONE */
{ 0, 4, 6}, /* EA_MODE_AI */
{ 0, 4, 6}, /* EA_MODE_PI */
{ 0, 4, 6}, /* EA_MODE_PI7 */
{ 0, 6, 12}, /* EA_MODE_PD */
{ 0, 6, 12}, /* EA_MODE_PD7 */
{ 0, 12, 16}, /* EA_MODE_DI */
{ 0, 16, 20}, /* EA_MODE_IX */
{ 0, 12, 16}, /* EA_MODE_AW */
{ 0, 16, 20}, /* EA_MODE_AL */
{ 0, 0, 0}, /* EA_MODE_PCDI */
{ 0, 0, 0}, /* EA_MODE_PCIX */
{ 0, 0, 0}, /* EA_MODE_I */
};
/* Extra cycles for CLR instruction (010) */
const int g_clr_cycle_table[13][3] =
{
{ 0, 0, 0}, /* EA_MODE_NONE */
{ 0, 4, 6}, /* EA_MODE_AI */
{ 0, 4, 6}, /* EA_MODE_PI */
{ 0, 4, 6}, /* EA_MODE_PI7 */
{ 0, 6, 8}, /* EA_MODE_PD */
{ 0, 6, 8}, /* EA_MODE_PD7 */
{ 0, 8, 10}, /* EA_MODE_DI */
{ 0, 10, 14}, /* EA_MODE_IX */
{ 0, 8, 10}, /* EA_MODE_AW */
{ 0, 10, 14}, /* EA_MODE_AL */
{ 0, 0, 0}, /* EA_MODE_PCDI */
{ 0, 0, 0}, /* EA_MODE_PCIX */
{ 0, 0, 0}, /* EA_MODE_I */
};
/* ======================================================================== */
/* =========================== UTILITY FUNCTIONS ========================== */
/* ======================================================================== */
/* Print an error message and exit with status error */
void error_exit(const char* fmt, ...)
{
va_list args;
fprintf(stderr, "In %s, near or on line %d:\n\t", g_input_filename, g_line_number);
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "\n");
if(g_prototype_file) fclose(g_prototype_file);
if(g_table_file) fclose(g_table_file);
if(g_input_file) fclose(g_input_file);
exit(EXIT_FAILURE);
}
/* Print an error message, call perror(), and exit with status error */
void perror_exit(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
perror("");
if(g_prototype_file) fclose(g_prototype_file);
if(g_table_file) fclose(g_table_file);
if(g_input_file) fclose(g_input_file);
exit(EXIT_FAILURE);
}
/* copy until 0 or space and exit with error if we read too far */
int check_strsncpy(char* dst, char* src, int maxlength)
{
char* p = dst;
while(*src && *src != ' ')
{
*p++ = *src++;
if(p - dst > maxlength)
error_exit("Field too long");
}
*p = 0;
return p - dst;
}
/* copy until 0 or specified character and exit with error if we read too far */
int check_strcncpy(char* dst, char* src, char delim, int maxlength)
{
char* p = dst;
while(*src && *src != delim)
{
*p++ = *src++;
if(p - dst > maxlength)
error_exit("Field too long");
}
*p = 0;
return p - dst;
}
/* convert ascii to integer and exit with error if we find invalid data */
int check_atoi(char* str, int *result)
{
int accum = 0;
char* p = str;
while(*p >= '0' && *p <= '9')
{
accum *= 10;
accum += *p++ - '0';
}
if(*p != ' ' && *p != 0)
error_exit("Malformed integer value (%c)", *p);
*result = accum;
return p - str;
}
/* Skip past spaces in a string */
int skip_spaces(char* str)
{
char* p = str;
while(*p == ' ')
p++;
return p - str;
}
/* Count the number of set bits in a value */
int num_bits(int value)
{
value = ((value & 0xaaaa) >> 1) + (value & 0x5555);
value = ((value & 0xcccc) >> 2) + (value & 0x3333);
value = ((value & 0xf0f0) >> 4) + (value & 0x0f0f);
value = ((value & 0xff00) >> 8) + (value & 0x00ff);
return value;
}
/* Convert a hex value written in ASCII */
int atoh(char* buff)
{
int accum = 0;
for(;;buff++)
{
if(*buff >= '0' && *buff <= '9')
{
accum <<= 4;
accum += *buff - '0';
}
else if(*buff >= 'a' && *buff <= 'f')
{
accum <<= 4;
accum += *buff - 'a' + 10;
}
else break;
}
return accum;
}
/* Get a line of text from a file, discarding any end-of-line characters */
int fgetline(char* buff, int nchars, FILE* file)
{
int length;
if(fgets(buff, nchars, file) == NULL)
return -1;
if(buff[0] == '\r')
memmove(buff, buff + 1, nchars - 1);
length = strlen(buff);
while(length && (buff[length-1] == '\r' || buff[length-1] == '\n'))
length--;
buff[length] = 0;
g_line_number++;
return length;
}
/* ======================================================================== */
/* =========================== HELPER FUNCTIONS =========================== */
/* ======================================================================== */
/* Calculate the number of cycles an opcode requires */
int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type)
{
int size = g_size_select_table[op->size];
if(op->cpus[cpu_type] == '.')
return 0;
if(cpu_type < CPU_TYPE_020)
{
if(cpu_type == CPU_TYPE_010)
{
if(strcmp(op->name, "moves") == 0)
return op->cycles[cpu_type] + g_moves_cycle_table[ea_mode][size];
if(strcmp(op->name, "clr") == 0)
return op->cycles[cpu_type] + g_clr_cycle_table[ea_mode][size];
}
/* ASG: added these cases -- immediate modes take 2 extra cycles here */
if(cpu_type == CPU_TYPE_000 && ea_mode == EA_MODE_I &&
((strcmp(op->name, "add") == 0 && strcmp(op->spec_proc, "er") == 0) ||
strcmp(op->name, "adda") == 0 ||
(strcmp(op->name, "and") == 0 && strcmp(op->spec_proc, "er") == 0) ||
(strcmp(op->name, "or") == 0 && strcmp(op->spec_proc, "er") == 0) ||
(strcmp(op->name, "sub") == 0 && strcmp(op->spec_proc, "er") == 0) ||
strcmp(op->name, "suba") == 0))
return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size] + 2;
if(strcmp(op->name, "jmp") == 0)
return op->cycles[cpu_type] + g_jmp_cycle_table[ea_mode];
if(strcmp(op->name, "jsr") == 0)
return op->cycles[cpu_type] + g_jsr_cycle_table[ea_mode];
if(strcmp(op->name, "lea") == 0)
return op->cycles[cpu_type] + g_lea_cycle_table[ea_mode];
if(strcmp(op->name, "pea") == 0)
return op->cycles[cpu_type] + g_pea_cycle_table[ea_mode];
if(strcmp(op->name, "movem") == 0)
return op->cycles[cpu_type] + g_movem_cycle_table[ea_mode];
}
return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size];
}
/* Find an opcode in the opcode handler list */
opcode_struct* find_opcode(char* name, int size, char* spec_proc, char* spec_ea)
{
opcode_struct* op;
for(op = g_opcode_input_table;op < &g_opcode_input_table[MAX_OPCODE_INPUT_TABLE_LENGTH];op++)
{
if( strcmp(name, op->name) == 0 &&
(size == op->size) &&
strcmp(spec_proc, op->spec_proc) == 0 &&
strcmp(spec_ea, op->spec_ea) == 0)
return op;
}
return NULL;
}
/* Specifically find the illegal opcode in the list */
opcode_struct* find_illegal_opcode(void)
{
opcode_struct* op;
for(op = g_opcode_input_table;op < &g_opcode_input_table[MAX_OPCODE_INPUT_TABLE_LENGTH];op++)
{
if(strcmp(op->name, "illegal") == 0)
return op;
}
return NULL;
}
/* Parse an opcode handler name */
int extract_opcode_info(char* src, char* name, int* size, char* spec_proc, char* spec_ea)
{
char* ptr = strstr(src, ID_OPHANDLER_NAME);
if(ptr == NULL)
return 0;
ptr += strlen(ID_OPHANDLER_NAME) + 1;
ptr += check_strcncpy(name, ptr, ',', MAX_NAME_LENGTH);
if(*ptr != ',') return 0;
ptr++;
ptr += skip_spaces(ptr);
*size = atoi(ptr);
ptr = strstr(ptr, ",");
if(ptr == NULL) return 0;
ptr++;
ptr += skip_spaces(ptr);
ptr += check_strcncpy(spec_proc, ptr, ',', MAX_SPEC_PROC_LENGTH);
if(*ptr != ',') return 0;
ptr++;
ptr += skip_spaces(ptr);
ptr += check_strcncpy(spec_ea, ptr, ')', MAX_SPEC_EA_LENGTH);
if(*ptr != ')') return 0;
ptr++;
ptr += skip_spaces(ptr);
return 1;
}
/* Add a search/replace pair to a replace structure */
void add_replace_string(replace_struct* replace, char* search_str, char* replace_str)
{
if(replace->length >= MAX_REPLACE_LENGTH)
error_exit("overflow in replace structure");
strcpy(replace->replace[replace->length][0], search_str);
strcpy(replace->replace[replace->length++][1], replace_str);
}
/* Write a function body while replacing any selected strings */
void write_body(FILE* filep, body_struct* body, replace_struct* replace)
{
int i;
int j;
char* ptr;
char output[MAX_LINE_LENGTH+1];
char temp_buff[MAX_LINE_LENGTH+1];
int found;
for(i=0;i<body->length;i++)
{
strcpy(output, body->body[i]);
/* Check for the base directive header */
if(strstr(output, ID_BASE) != NULL)
{
/* Search for any text we need to replace */
found = 0;
for(j=0;j<replace->length;j++)
{
ptr = strstr(output, replace->replace[j][0]);
if(ptr)
{
/* We found something to replace */
found = 1;
strcpy(temp_buff, ptr+strlen(replace->replace[j][0]));
strcpy(ptr, replace->replace[j][1]);
strcat(ptr, temp_buff);
}
}
/* Found a directive with no matching replace string */
if(!found)
error_exit("Unknown " ID_BASE " directive [%s]", output);
}
fprintf(filep, "%s\n", output);
}
fprintf(filep, "\n\n");
}
/* Generate a base function name from an opcode struct */
void get_base_name(char* base_name, opcode_struct* op)
{
sprintf(base_name, "m68k_op_%s", op->name);
if(op->size > 0)
sprintf(base_name+strlen(base_name), "_%d", op->size);
if(strcmp(op->spec_proc, UNSPECIFIED) != 0)
sprintf(base_name+strlen(base_name), "_%s", op->spec_proc);
if(strcmp(op->spec_ea, UNSPECIFIED) != 0)
sprintf(base_name+strlen(base_name), "_%s", op->spec_ea);
}
/* Write the name of an opcode handler function */
void write_function_name(FILE* filep, char* base_name)
{
fprintf(filep, "static void %s(void)\n", base_name);
}
void add_opcode_output_table_entry(opcode_struct* op, char* name)
{
opcode_struct* ptr;
if(g_opcode_output_table_length > MAX_OPCODE_OUTPUT_TABLE_LENGTH)
error_exit("Opcode output table overflow");
ptr = g_opcode_output_table + g_opcode_output_table_length++;
*ptr = *op;
strcpy(ptr->name, name);
ptr->bits = num_bits(ptr->op_mask);
}
/*
* Comparison function for qsort()
* For entries with an equal number of set bits in
* the mask compare the match values
*/
static int DECL_SPEC compare_nof_true_bits(const void* aptr, const void* bptr)
{
const opcode_struct *a = aptr, *b = bptr;
if(a->bits != b->bits)
return a->bits - b->bits;
if(a->op_mask != b->op_mask)
return a->op_mask - b->op_mask;
return a->op_match - b->op_match;
}
void print_opcode_output_table(FILE* filep)
{
int i;
qsort((void *)g_opcode_output_table, g_opcode_output_table_length, sizeof(g_opcode_output_table[0]), compare_nof_true_bits);
for(i=0;i<g_opcode_output_table_length;i++)
write_table_entry(filep, g_opcode_output_table+i);
}
/* Write an entry in the opcode handler table */
void write_table_entry(FILE* filep, opcode_struct* op)
{
int i;
fprintf(filep, "\t{%-28s, 0x%04x, 0x%04x, {",
op->name, op->op_mask, op->op_match);
for(i=0;i<NUM_CPUS;i++)
{
fprintf(filep, "%3d", op->cycles[i]);
if(i < NUM_CPUS-1)
fprintf(filep, ", ");
}
fprintf(filep, "}},\n");
}
/* Fill out an opcode struct with a specific addressing mode of the source opcode struct */
void set_opcode_struct(opcode_struct* src, opcode_struct* dst, int ea_mode)
{
int i;
*dst = *src;
for(i=0;i<NUM_CPUS;i++)
dst->cycles[i] = get_oper_cycles(dst, ea_mode, i);
if(strcmp(dst->spec_ea, UNSPECIFIED) == 0 && ea_mode != EA_MODE_NONE)
sprintf(dst->spec_ea, "%s", g_ea_info_table[ea_mode].fname_add);
dst->op_mask |= g_ea_info_table[ea_mode].mask_add;
dst->op_match |= g_ea_info_table[ea_mode].match_add;
}
/* Generate a final opcode handler from the provided data */
void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* opinfo, int ea_mode)
{
char str[MAX_LINE_LENGTH+1];
opcode_struct* op = malloc(sizeof(opcode_struct));
/* Set the opcode structure and write the tables, prototypes, etc */
set_opcode_struct(opinfo, op, ea_mode);
get_base_name(str, op);
add_opcode_output_table_entry(op, str);
write_function_name(filep, str);
/* Add any replace strings needed */
if(ea_mode != EA_MODE_NONE)
{
sprintf(str, "EA_%s_8()", g_ea_info_table[ea_mode].ea_add);
add_replace_string(replace, ID_OPHANDLER_EA_AY_8, str);
sprintf(str, "EA_%s_16()", g_ea_info_table[ea_mode].ea_add);
add_replace_string(replace, ID_OPHANDLER_EA_AY_16, str);
sprintf(str, "EA_%s_32()", g_ea_info_table[ea_mode].ea_add);
add_replace_string(replace, ID_OPHANDLER_EA_AY_32, str);
sprintf(str, "OPER_%s_8()", g_ea_info_table[ea_mode].ea_add);
add_replace_string(replace, ID_OPHANDLER_OPER_AY_8, str);
sprintf(str, "OPER_%s_16()", g_ea_info_table[ea_mode].ea_add);
add_replace_string(replace, ID_OPHANDLER_OPER_AY_16, str);
sprintf(str, "OPER_%s_32()", g_ea_info_table[ea_mode].ea_add);
add_replace_string(replace, ID_OPHANDLER_OPER_AY_32, str);
}
/* Now write the function body with the selected replace strings */
write_body(filep, body, replace);
g_num_functions++;
free(op);
}
/* Generate opcode variants based on available addressing modes */
void generate_opcode_ea_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op)
{
int old_length = replace->length;
/* No ea modes available for this opcode */
if(HAS_NO_EA_MODE(op->ea_allowed))
{
generate_opcode_handler(filep, body, replace, op, EA_MODE_NONE);
return;
}
/* Check for and create specific opcodes for each available addressing mode */
if(HAS_EA_AI(op->ea_allowed))
generate_opcode_handler(filep, body, replace, op, EA_MODE_AI);
replace->length = old_length;
if(HAS_EA_PI(op->ea_allowed))
{
generate_opcode_handler(filep, body, replace, op, EA_MODE_PI);
replace->length = old_length;
if(op->size == 8)
generate_opcode_handler(filep, body, replace, op, EA_MODE_PI7);
}
replace->length = old_length;
if(HAS_EA_PD(op->ea_allowed))
{
generate_opcode_handler(filep, body, replace, op, EA_MODE_PD);
replace->length = old_length;
if(op->size == 8)
generate_opcode_handler(filep, body, replace, op, EA_MODE_PD7);
}
replace->length = old_length;
if(HAS_EA_DI(op->ea_allowed))
generate_opcode_handler(filep, body, replace, op, EA_MODE_DI);
replace->length = old_length;
if(HAS_EA_IX(op->ea_allowed))
generate_opcode_handler(filep, body, replace, op, EA_MODE_IX);
replace->length = old_length;
if(HAS_EA_AW(op->ea_allowed))
generate_opcode_handler(filep, body, replace, op, EA_MODE_AW);
replace->length = old_length;
if(HAS_EA_AL(op->ea_allowed))
generate_opcode_handler(filep, body, replace, op, EA_MODE_AL);
replace->length = old_length;
if(HAS_EA_PCDI(op->ea_allowed))
generate_opcode_handler(filep, body, replace, op, EA_MODE_PCDI);
replace->length = old_length;
if(HAS_EA_PCIX(op->ea_allowed))
generate_opcode_handler(filep, body, replace, op, EA_MODE_PCIX);
replace->length = old_length;
if(HAS_EA_I(op->ea_allowed))
generate_opcode_handler(filep, body, replace, op, EA_MODE_I);
replace->length = old_length;
}
/* Generate variants of condition code opcodes */
void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op_in, int offset)
{
char repl[20];
char replnot[20];
int i;
int old_length = replace->length;
opcode_struct* op = malloc(sizeof(opcode_struct));
*op = *op_in;
op->op_mask |= 0x0f00;
/* Do all condition codes except t and f */
for(i=2;i<16;i++)
{
/* Add replace strings for this condition code */
sprintf(repl, "COND_%s()", g_cc_table[i][1]);
sprintf(replnot, "COND_NOT_%s()", g_cc_table[i][1]);
add_replace_string(replace, ID_OPHANDLER_CC, repl);
add_replace_string(replace, ID_OPHANDLER_NOT_CC, replnot);
/* Set the new opcode info */
strcpy(op->name+offset, g_cc_table[i][0]);
op->op_match = (op->op_match & 0xf0ff) | (i<<8);
/* Generate all opcode variants for this modified opcode */
generate_opcode_ea_variants(filep, body, replace, op);
/* Remove the above replace strings */
replace->length = old_length;
}
free(op);
}
/* Process the opcode handlers section of the input file */
void process_opcode_handlers(FILE* filep)
{
FILE* input_file = g_input_file;
char func_name[MAX_LINE_LENGTH+1];
char oper_name[MAX_LINE_LENGTH+1];
int oper_size;
char oper_spec_proc[MAX_LINE_LENGTH+1];
char oper_spec_ea[MAX_LINE_LENGTH+1];
opcode_struct* opinfo;
replace_struct* replace = malloc(sizeof(replace_struct));
body_struct* body = malloc(sizeof(body_struct));
for(;;)
{
/* Find the first line of the function */
func_name[0] = 0;
while(strstr(func_name, ID_OPHANDLER_NAME) == NULL)
{
if(strcmp(func_name, ID_INPUT_SEPARATOR) == 0)
{
free(replace);
free(body);
return; /* all done */
}
if(fgetline(func_name, MAX_LINE_LENGTH, input_file) < 0)
error_exit("Premature end of file when getting function name");
}
/* Get the rest of the function */
for(body->length=0;;body->length++)
{
if(body->length > MAX_BODY_LENGTH)
error_exit("Function too long");
if(fgetline(body->body[body->length], MAX_LINE_LENGTH, input_file) < 0)
error_exit("Premature end of file when getting function body");
if(body->body[body->length][0] == '}')
{
body->length++;
break;
}
}
g_num_primitives++;
/* Extract the function name information */
if(!extract_opcode_info(func_name, oper_name, &oper_size, oper_spec_proc, oper_spec_ea))
error_exit("Invalid " ID_OPHANDLER_NAME " format");
/* Find the corresponding table entry */
opinfo = find_opcode(oper_name, oper_size, oper_spec_proc, oper_spec_ea);
if(opinfo == NULL)
error_exit("Unable to find matching table entry for %s", func_name);
replace->length = 0;
/* Generate opcode variants */
if(strcmp(opinfo->name, "bcc") == 0 || strcmp(opinfo->name, "scc") == 0)
generate_opcode_cc_variants(filep, body, replace, opinfo, 1);
else if(strcmp(opinfo->name, "dbcc") == 0)
generate_opcode_cc_variants(filep, body, replace, opinfo, 2);
else if(strcmp(opinfo->name, "trapcc") == 0)
generate_opcode_cc_variants(filep, body, replace, opinfo, 4);
else
generate_opcode_ea_variants(filep, body, replace, opinfo);
}
free(replace);
free(body);
}
/* Populate the opcode handler table from the input file */
void populate_table(void)
{
char* ptr;
char bitpattern[17];
opcode_struct* op;
char buff[MAX_LINE_LENGTH];
int i;
int temp;
buff[0] = 0;
/* Find the start of the table */
while(strcmp(buff, ID_TABLE_START) != 0)
if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0)
error_exit("(table_start) Premature EOF while reading table");
/* Process the entire table */
for(op = g_opcode_input_table;;op++)
{
if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0)
error_exit("(inline) Premature EOF while reading table");
if(strlen(buff) == 0)
continue;
/* We finish when we find an input separator */
if(strcmp(buff, ID_INPUT_SEPARATOR) == 0)
break;
/* Extract the info from the table */
ptr = buff;
/* Name */
ptr += skip_spaces(ptr);
ptr += check_strsncpy(op->name, ptr, MAX_NAME_LENGTH);
/* Size */
ptr += skip_spaces(ptr);
ptr += check_atoi(ptr, &temp);
op->size = (unsigned char)temp;
/* Special processing */
ptr += skip_spaces(ptr);
ptr += check_strsncpy(op->spec_proc, ptr, MAX_SPEC_PROC_LENGTH);
/* Specified EA Mode */
ptr += skip_spaces(ptr);
ptr += check_strsncpy(op->spec_ea, ptr, MAX_SPEC_EA_LENGTH);
/* Bit Pattern (more processing later) */
ptr += skip_spaces(ptr);
ptr += check_strsncpy(bitpattern, ptr, 17);
/* Allowed Addressing Mode List */
ptr += skip_spaces(ptr);
ptr += check_strsncpy(op->ea_allowed, ptr, EA_ALLOWED_LENGTH);
/* CPU operating mode (U = user or supervisor, S = supervisor only */
ptr += skip_spaces(ptr);
for(i=0;i<NUM_CPUS;i++)
{
op->cpu_mode[i] = *ptr++;
ptr += skip_spaces(ptr);
}
/* Allowed CPUs for this instruction */
for(i=0;i<NUM_CPUS;i++)
{
ptr += skip_spaces(ptr);
if(*ptr == UNSPECIFIED_CH)
{
op->cpus[i] = UNSPECIFIED_CH;
op->cycles[i] = 0;
ptr++;
}
else
{
op->cpus[i] = '0' + i;
ptr += check_atoi(ptr, &temp);
op->cycles[i] = (unsigned char)temp;
}
}
/* generate mask and match from bitpattern */
op->op_mask = 0;
op->op_match = 0;
for(i=0;i<16;i++)
{
op->op_mask |= (bitpattern[i] != '.') << (15-i);
op->op_match |= (bitpattern[i] == '1') << (15-i);
}
}
/* Terminate the list */
op->name[0] = 0;
}
/* Read a header or footer insert from the input file */
void read_insert(char* insert)
{
char* ptr = insert;
char* overflow = insert + MAX_INSERT_LENGTH - MAX_LINE_LENGTH;
int length;
char* first_blank = NULL;
first_blank = NULL;
/* Skip any leading blank lines */
for(length = 0;length == 0;length = fgetline(ptr, MAX_LINE_LENGTH, g_input_file))
if(ptr >= overflow)
error_exit("Buffer overflow reading inserts");
if(length < 0)
error_exit("Premature EOF while reading inserts");
/* Advance and append newline */
ptr += length;
strcpy(ptr++, "\n");
/* Read until next separator */
for(;;)
{
/* Read a new line */
if(ptr >= overflow)
error_exit("Buffer overflow reading inserts");
if((length = fgetline(ptr, MAX_LINE_LENGTH, g_input_file)) < 0)
error_exit("Premature EOF while reading inserts");
/* Stop if we read a separator */
if(strcmp(ptr, ID_INPUT_SEPARATOR) == 0)
break;
/* keep track in case there are trailing blanks */
if(length == 0)
{
if(first_blank == NULL)
first_blank = ptr;
}
else
first_blank = NULL;
/* Advance and append newline */
ptr += length;
strcpy(ptr++, "\n");
}
/* kill any trailing blank lines */
if(first_blank)
ptr = first_blank;
*ptr++ = 0;
}
/* ======================================================================== */
/* ============================= MAIN FUNCTION ============================ */
/* ======================================================================== */
int main(int argc, char **argv)
{
/* File stuff */
char output_path[M68K_MAX_DIR] = "";
char filename[M68K_MAX_PATH*2];
/* Section identifier */
char section_id[MAX_LINE_LENGTH+1];
/* Inserts */
char temp_insert[MAX_INSERT_LENGTH+1];
char prototype_footer_insert[MAX_INSERT_LENGTH+1];
char table_header_insert[MAX_INSERT_LENGTH+1];
char table_footer_insert[MAX_INSERT_LENGTH+1];
char ophandler_header_insert[MAX_INSERT_LENGTH+1];
char ophandler_footer_insert[MAX_INSERT_LENGTH+1];
/* Flags if we've processed certain parts already */
int prototype_header_read = 0;
int prototype_footer_read = 0;
int table_header_read = 0;
int table_footer_read = 0;
int ophandler_header_read = 0;
int ophandler_footer_read = 0;
int table_body_read = 0;
int ophandler_body_read = 0;
printf("\n\tMusashi v%s 68000, 68008, 68010, 68EC020, 68020, 68EC030, 68030, 68EC040, 68040 emulator\n", g_version);
printf("\t\tCopyright Karl Stenerud (kstenerud@gmail.com)\n\n");
/* Check if output path and source for the input file are given */
if(argc > 1)
{
char *ptr;
strcpy(output_path, argv[1]);
for(ptr = strchr(output_path, '\\'); ptr; ptr = strchr(ptr, '\\'))
*ptr = '/';
if(output_path[strlen(output_path)-1] != '/')
strcat(output_path, "/");
if(argc > 2)
strcpy(g_input_filename, argv[2]);
}
/* Open the files we need */
sprintf(filename, "%s%s", output_path, FILENAME_PROTOTYPE);
if((g_prototype_file = fopen(filename, "wt")) == NULL)
perror_exit("Unable to create prototype file (%s)\n", filename);
sprintf(filename, "%s%s", output_path, FILENAME_TABLE);
if((g_table_file = fopen(filename, "wt")) == NULL)
perror_exit("Unable to create table file (%s)\n", filename);
if((g_input_file=fopen(g_input_filename, "rt")) == NULL)
perror_exit("can't open %s for input", g_input_filename);
/* Get to the first section of the input file */
section_id[0] = 0;
while(strcmp(section_id, ID_INPUT_SEPARATOR) != 0)
if(fgetline(section_id, MAX_LINE_LENGTH, g_input_file) < 0)
error_exit("Premature EOF while reading input file");
/* Now process all sections */
for(;;)
{
if(fgetline(section_id, MAX_LINE_LENGTH, g_input_file) < 0)
error_exit("Premature EOF while reading input file");
if(strcmp(section_id, ID_PROTOTYPE_HEADER) == 0)
{
if(prototype_header_read)
error_exit("Duplicate prototype header");
read_insert(temp_insert);
fprintf(g_prototype_file, "%s\n\n", temp_insert);
prototype_header_read = 1;
}
else if(strcmp(section_id, ID_TABLE_HEADER) == 0)
{
if(table_header_read)
error_exit("Duplicate table header");
read_insert(table_header_insert);
table_header_read = 1;
}
else if(strcmp(section_id, ID_OPHANDLER_HEADER) == 0)
{
if(ophandler_header_read)
error_exit("Duplicate opcode handler header");
read_insert(ophandler_header_insert);
ophandler_header_read = 1;
}
else if(strcmp(section_id, ID_PROTOTYPE_FOOTER) == 0)
{
if(prototype_footer_read)
error_exit("Duplicate prototype footer");
read_insert(prototype_footer_insert);
prototype_footer_read = 1;
}
else if(strcmp(section_id, ID_TABLE_FOOTER) == 0)
{
if(table_footer_read)
error_exit("Duplicate table footer");
read_insert(table_footer_insert);
table_footer_read = 1;
}
else if(strcmp(section_id, ID_OPHANDLER_FOOTER) == 0)
{
if(ophandler_footer_read)
error_exit("Duplicate opcode handler footer");
read_insert(ophandler_footer_insert);
ophandler_footer_read = 1;
}
else if(strcmp(section_id, ID_TABLE_BODY) == 0)
{
if(!prototype_header_read)
error_exit("Table body encountered before prototype header");
if(!table_header_read)
error_exit("Table body encountered before table header");
if(!ophandler_header_read)
error_exit("Table body encountered before opcode handler header");
if(table_body_read)
error_exit("Duplicate table body");
populate_table();
table_body_read = 1;
}
else if(strcmp(section_id, ID_OPHANDLER_BODY) == 0)
{
if(!prototype_header_read)
error_exit("Opcode handlers encountered before prototype header");
if(!table_header_read)
error_exit("Opcode handlers encountered before table header");
if(!ophandler_header_read)
error_exit("Opcode handlers encountered before opcode handler header");
if(!table_body_read)
error_exit("Opcode handlers encountered before table body");
if(ophandler_body_read)
error_exit("Duplicate opcode handler section");
fprintf(g_table_file, "%s\n\n", ophandler_header_insert);
process_opcode_handlers(g_table_file);
fprintf(g_table_file, "%s\n\n", ophandler_footer_insert);
ophandler_body_read = 1;
}
else if(strcmp(section_id, ID_END) == 0)
{
/* End of input file. Do a sanity check and then write footers */
if(!prototype_header_read)
error_exit("Missing prototype header");
if(!prototype_footer_read)
error_exit("Missing prototype footer");
if(!table_header_read)
error_exit("Missing table header");
if(!table_footer_read)
error_exit("Missing table footer");
if(!table_body_read)
error_exit("Missing table body");
if(!ophandler_header_read)
error_exit("Missing opcode handler header");
if(!ophandler_footer_read)
error_exit("Missing opcode handler footer");
if(!ophandler_body_read)
error_exit("Missing opcode handler body");
fprintf(g_table_file, "%s\n\n", table_header_insert);
print_opcode_output_table(g_table_file);
fprintf(g_table_file, "%s\n\n", table_footer_insert);
fprintf(g_prototype_file, "%s\n\n", prototype_footer_insert);
break;
}
else
{
error_exit("Unknown section identifier: %s", section_id);
}
}
/* Close all files and exit */
fclose(g_prototype_file);
fclose(g_table_file);
fclose(g_input_file);
printf("Generated %d opcode handlers from %d primitives\n", g_num_functions, g_num_primitives);
return 0;
}
/* ======================================================================== */
/* ============================== END OF FILE ============================= */
/* ======================================================================== */