Search
lxdream.org :: lxdream/src/tools/gendec.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/tools/gendec.c
changeset 359:c588dce7ebde
next420:e6f43dec3cf0
author nkeynes
date Thu Aug 23 12:33:27 2007 +0000 (14 years ago)
permissions -rw-r--r--
last change Commit decoder generator
Translator work in progress
Fix mac.l, mac.w in emu core
view annotate diff log raw
     1 /**
     2  * $Id: gendec.c,v 1.1 2007-08-23 12:33:27 nkeynes Exp $
     3  * 
     4  * Parse the instruction and action files and generate an appropriate
     5  * instruction decoder.
     6  *
     7  * Copyright (c) 2005 Nathan Keynes.
     8  *
     9  * This program is free software; you can redistribute it and/or modify
    10  * it under the terms of the GNU General Public License as published by
    11  * the Free Software Foundation; either version 2 of the License, or
    12  * (at your option) any later version.
    13  *
    14  * This program is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    17  * GNU General Public License for more details.
    18  */
    20 #include <stdio.h>
    21 #include <stdlib.h>
    22 #include <string.h>
    23 #include <getopt.h>
    24 #include <errno.h>
    25 #include <ctype.h>
    26 #include <glib/gstrfuncs.h>
    27 #include <assert.h>
    28 #include "tools/gendec.h"
    30 #define DEFAULT_OUT_EXT ".c"
    32 const char *ins_filename = NULL;
    33 const char *act_filename = NULL;
    34 const char *out_filename = NULL;
    36 #define GEN_SOURCE 1
    37 #define GEN_TEMPLATE 2
    39 FILE *ins_file, *act_file, *out_file;
    41 char *option_list = "tmho:";
    42 int gen_mode = GEN_SOURCE;
    43 struct option longopts[1] = { { NULL, 0, 0, 0 } };
    45 void usage() {
    46     printf( "gendec <instruction-file> <action-file> [ -o <output-file> ]\n" );
    47 }
    49 int main( int argc, char *argv[] )
    50 {
    51     int opt, i;
    53     /* Parse the command line */
    54     while( (opt = getopt_long( argc, argv, option_list, longopts, NULL )) != -1 ) {
    55         switch( opt ) {
    56 	case 't':
    57 	    gen_mode = GEN_TEMPLATE;
    58 	    break;
    59 	case 'o':
    60 	    out_filename = optarg;
    61 	    break;
    62 	case 'h':
    63 	    usage();
    64 	    exit(0);
    65 	}
    66     }
    67     if( optind < argc ) {
    68 	ins_filename = argv[optind++];
    69     }
    70     if( optind < argc ) {
    71 	act_filename = argv[optind++];
    72     }
    74     if( optind < argc || ins_filename == NULL || act_filename == NULL ) {
    75 	usage();
    76 	exit(1);
    77     }
    79     if( out_filename == NULL ) {
    80 	if( gen_mode == GEN_TEMPLATE ) {
    81 	    out_filename = act_filename;
    82 	} else {
    83 	    char tmp[strlen(act_filename)+1];
    84 	    strcpy( tmp, act_filename);
    85 	    char *c = strrchr( tmp, '.' );
    86 	    if( c != NULL ) {
    87 		*c = '\0';
    88 	    }
    89 	    out_filename = g_strconcat( tmp, DEFAULT_OUT_EXT );
    90 	}
    91     }
    93     /* Open the files */
    94     ins_file = fopen( ins_filename, "ro" );
    95     if( ins_file == NULL ) {
    96         fprintf( stderr, "Unable to open '%s' for reading (%s)\n", ins_filename, strerror(errno) );
    97 	exit(2);
    98     }
   100     act_file = fopen( act_filename, "ro" );
   101     if( act_file == NULL ) {
   102         fprintf( stderr, "Unable to open '%s' for reading (%s)\n", act_filename, strerror(errno) );
   103 	exit(3);
   104     }
   106     /* Parse the input */
   107     struct ruleset *rules = parse_ruleset_file( ins_file );
   108     fclose( ins_file );
   109     if( rules == NULL ) {
   110 	exit(5);
   111     }
   113     struct actionset *actions = parse_action_file( rules, act_file );
   114     fclose( act_file );
   115     if( actions == NULL ) {
   116 	exit(6);
   117     }
   119     /* Finally write out the results */
   120     out_file = fopen( out_filename, "wo" );
   121     if( out_file == NULL ) {
   122         fprintf( stderr, "Unable to open '%s' for writing (%s)\n", out_filename, strerror(errno) );
   123 	exit(4);
   124     }
   126     switch( gen_mode ) {
   127     case GEN_SOURCE:
   128 	if( generate_decoder( rules, actions, out_file ) != 0 ) {
   129 	    exit(7);
   130 	}
   131 	break;
   132     case GEN_TEMPLATE:
   133 	if( generate_template( rules, actions, out_file ) != 0 ) {
   134 	    exit(7);
   135 	}
   136 	break;
   137     }
   138     fclose( out_file );
   139     return 0;
   140 }
   142 /**
   143  * Find a mask that can be used to split up the given rules
   144  */
   145 uint32_t find_mask( struct ruleset *rules, int ruleidx[], int rule_count, 
   146 		    uint32_t input_mask )
   147 {
   148     int i;
   149     uint32_t mask = rules->rules[ruleidx[0]]->mask;
   151     for( i=1; i<rule_count; i++ ) {
   152 	mask = mask & rules->rules[ruleidx[i]]->mask;
   153     }
   155     assert( (mask & input_mask) == input_mask ); /* input_mask should always be included in the mask */
   157     return mask & (~input_mask); /* but we don't want to see the input mask again */
   158 }
   160 int get_option_count_for_mask( uint32_t mask ) {
   161     int count = 0;
   163     while( mask ) {
   164 	if( mask&1 ) 
   165 	    count++;
   166 	mask >>= 1;
   167     }
   168     return 1<<count;
   169 }
   171 int get_bitshift_for_mask( uint32_t mask ) {
   172     int shift = 0;
   173     while( mask && !(mask&1) ) {
   174 	shift++;
   175 	mask >>= 1;
   176     }
   177     return shift;
   178 }
   180 void get_option_values_for_mask( uint32_t *options, 
   181 				      uint32_t mask ) 
   182 {
   183     /* This could be a lot smarter. But it's not */
   184     int i;
   185     *options = 0;
   186     for( i=1; i<=mask; i++ ) {
   187 	if( (i & mask) > *options ) {
   188 	    options++;
   189 	    *options = (i&mask);
   190 	}
   191     }
   192 }
   194 fprint_indent( char *action, int depth, FILE *f )
   195 {
   196     int spaces = 0, needed = depth*8, i;
   197     char *text = action;
   199     /* Determine number of spaces in first line of input */
   200     for( i=0; isspace(action[i]); i++ ) {
   201 	if( action[i] == '\n' ) {
   202 	    spaces = 0;
   203 	    text = &action[i+1];
   204 	} else {
   205 	    spaces++;
   206 	}
   207     }
   209     needed -= spaces;
   210     fprintf( f, "%*c", needed, ' ' );
   211     for( i=0; text[i] != '\0'; i++ ) {
   212 	fputc( text[i], f );
   213 	if( text[i] == '\n' && text[i+1] != '\0' ) {
   214 	    fprintf( f, "%*c", needed, ' ' );
   215 	}
   216     }
   217     if( text[i-1] != '\n' ) {
   218 	fprintf( f, "\n" );
   219     }
   220 }
   222 fprint_action( struct rule *rule, char *action, int depth, FILE *f ) 
   223 {
   224     int i;
   225     char tmp[64];
   226     if( action == NULL ) {
   227 	fprintf( f, "%*cUNIMP(ir); /* %s */\n", depth*8, ' ', rule->format );
   228     } else {
   229 	fprintf( f, "%*c{ /* %s */", depth*8, ' ', rule->format );
   230 	if( rule->operand_count != 0 ) {
   231 	    fprintf( f, "\n%*c", depth*8, ' ' );
   232 	    for( i=0; i<rule->operand_count; i++ ) {
   233 		if( rule->operands[i].is_signed ) {
   234 		    fprintf( f, "int32_t %s = SIGNEXT%d", rule->operands[i].name, rule->operands[i].bit_count );
   235 		} else {
   236 		    fprintf( f, "uint32_t %s = ", rule->operands[i].name );
   237 		}
   238 		if( rule->operands[i].bit_shift == 0 ) {
   239 		    fprintf( f, "(ir&0x%X)", (1<<(rule->operands[i].bit_count))-1 );
   240 		} else {
   241 		    fprintf( f, "((ir>>%d)&0x%X)", rule->operands[i].bit_shift,
   242 			     (1<<(rule->operands[i].bit_count))-1 );
   243 		}
   244 		if( rule->operands[i].left_shift != 0 ) {
   245 		    fprintf( f, "<<%d", rule->operands[i].left_shift );
   246 		}
   247 		fprintf( f, "; " );
   248 	    }
   249 	}
   250 	fputs( "\n", f );
   251 	if( action[0] != '\0' ) {
   252 	    fprint_indent( action, depth, f );
   253 	}
   254 	fprintf( f, "%*c}\n", depth*8, ' ' );
   255     }
   256 }
   258 int split_and_generate( struct ruleset *rules, struct actionset *actions, 
   259 			int ruleidx[], int rule_count, int input_mask, 
   260 			int depth, FILE *f ) {
   261     char tmp[64];
   262     uint32_t mask;
   263     int i,j;
   265     if( rule_count == 0 ) {
   266 	fprintf( f, "%*cUNDEF(ir);\n", depth*8, ' ' );
   267     } else if( rule_count == 1 ) {
   268 	fprint_action( rules->rules[ruleidx[0]], actions->actions[ruleidx[0]], depth, f );
   269     } else {
   271 	mask = find_mask(rules, ruleidx, rule_count, input_mask);
   272 	if( mask == 0 ) { /* No matching mask? */
   273 	    fprintf( stderr, "Error: unable to find a valid bitmask (%d rules, %08X input mask)\n", rule_count, input_mask );
   274 	    dump_rulesubset( rules, ruleidx, rule_count, stderr );
   275 	    return -1;
   276 	}
   278 	/* break up the rules into sub-sets, and process each sub-set.
   279 	 * NB: We could do this in one pass at the cost of more complex
   280 	 * data structures. For now though, this keeps it simple
   281 	 */
   282 	int option_count = get_option_count_for_mask( mask );
   283 	uint32_t options[option_count];
   284 	int subruleidx[rule_count];
   285 	int subrule_count;
   286 	int mask_shift = get_bitshift_for_mask( mask );
   287 	int has_empty_options = 0;
   288 	get_option_values_for_mask( options, mask );
   290 	if( mask_shift == 0 ) {
   291 	    fprintf( f, "%*cswitch( ir&0x%X ) {\n", depth*8, ' ', mask );
   292 	} else {
   293 	    fprintf( f, "%*cswitch( (ir&0x%X) >> %d ) {\n", depth*8, ' ',
   294 		     mask, mask_shift);
   295 	}
   296 	for( i=0; i<option_count; i++ ) {
   297 	    subrule_count = 0;
   298 	    for( j=0; j<rule_count; j++ ) {
   299 		int match = rules->rules[ruleidx[j]]->bits & mask;
   300 		if( match == options[i] ) {
   301 		    subruleidx[subrule_count++] = ruleidx[j];
   302 		}
   303 	    }
   304 	    if( subrule_count == 0 ) {
   305 		has_empty_options = 1;
   306 	    } else {
   307 		fprintf( f, "%*ccase 0x%X:\n", depth*8+4, ' ', options[i]>>mask_shift );
   308 		split_and_generate( rules, actions, subruleidx, subrule_count,
   309 				    mask|input_mask, depth+1, f );
   310 		fprintf( f, "%*cbreak;\n", depth*8+8, ' ' );
   311 	    }
   312 	}
   313 	if( has_empty_options ) {
   314 	    fprintf( f, "%*cdefault:\n%*cUNDEF();\n%*cbreak;\n",
   315 		     depth*8+4, ' ', depth*8+8, ' ', depth*8 + 8, ' ' );
   316 	}
   317 	fprintf( f, "%*c}\n", depth*8, ' ' );
   318     }
   319 }
   321 int generate_decoder( struct ruleset *rules, struct actionset *actions, FILE *f )
   322 {
   323     int ruleidx[rules->rule_count];
   324     int i;
   326     for( i=0; i<rules->rule_count; i++ ) {
   327 	ruleidx[i] = i;
   328     }
   330     fputs( actions->pretext, f );
   332     split_and_generate( rules, actions, ruleidx, rules->rule_count, 0, 1, f );
   334     fputs( actions->posttext, f );
   336     return 0;
   337 }
   339 int generate_template( struct ruleset *rules, struct actionset *actions, FILE *f )
   340 {
   341     int i;
   342     fputs( actions->pretext, f );
   343     fputs( "%%\n", f );
   345     for( i=0; i<rules->rule_count; i++ ) {
   346 	fprintf( f, "%s {: %s :}\n", rules->rules[i]->format, 
   347 		 actions->actions[i] == NULL ? "" : actions->actions[i] );
   348     }
   349     fputs( "%%\n", f );
   350     fputs( actions->posttext, f );
   352     return 0;
   353 }
.