Search
lxdream.org :: lxdream/src/tools/gendec.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/tools/gendec.c
changeset 979:2cc7b486ea6c
prev969:3f178ca1398c
next1084:852412cf56e0
author nkeynes
date Wed Feb 04 00:58:54 2009 +0000 (13 years ago)
permissions -rw-r--r--
last change Emit #line directives in output to make debugging a little easier
view annotate diff log raw
     1 /**
     2  * $Id$
     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 static void usage() {
    46     printf( "gendec <instruction-file> <action-file> [ -o <output-file> ]\n" );
    47 }
    49 /**
    50  * Find a mask that can be used to split up the given rules
    51  */
    52 static uint32_t find_mask( struct ruleset *rules, int ruleidx[], int rule_count, 
    53                     uint32_t input_mask )
    54 {
    55     int i;
    56     uint32_t mask = rules->rules[ruleidx[0]]->mask;
    58     for( i=1; i<rule_count; i++ ) {
    59         mask = mask & rules->rules[ruleidx[i]]->mask;
    60     }
    62     assert( (mask & input_mask) == input_mask ); /* input_mask should always be included in the mask */
    64     return mask & (~input_mask); /* but we don't want to see the input mask again */
    65 }
    67 static int get_option_count_for_mask( uint32_t mask ) {
    68     int count = 0;
    70     while( mask ) {
    71         if( mask&1 ) 
    72             count++;
    73         mask >>= 1;
    74     }
    75     return 1<<count;
    76 }
    78 int get_bitshift_for_mask( uint32_t mask ) {
    79     int shift = 0;
    80     while( mask && !(mask&1) ) {
    81         shift++;
    82         mask >>= 1;
    83     }
    84     return shift;
    85 }
    87 static void get_option_values_for_mask( uint32_t *options, 
    88                                  uint32_t mask ) 
    89 {
    90     /* This could be a lot smarter. But it's not */
    91     int i;
    92     *options = 0;
    93     for( i=1; i<=mask; i++ ) {
    94         if( (i & mask) > *options ) {
    95             options++;
    96             *options = (i&mask);
    97         }
    98     }
    99 }
   101 static void fprint_indent( const char *action, int depth, FILE *f )
   102 {
   103     int spaces = 0, needed = depth*8, i;
   104     const char *text = action;
   106     /* Determine number of spaces in first line of input */
   107     for( i=0; isspace(action[i]); i++ ) {
   108         if( action[i] == '\n' ) {
   109             spaces = 0;
   110             text = &action[i+1];
   111         } else {
   112             spaces++;
   113         }
   114     }
   116     needed -= spaces;
   117     fprintf( f, "%*c", needed, ' ' );
   118     for( i=0; text[i] != '\0'; i++ ) {
   119         fputc( text[i], f );
   120         if( text[i] == '\n' && text[i+1] != '\0' ) {
   121             fprintf( f, "%*c", needed, ' ' );
   122         }
   123     }
   124     if( text[i-1] != '\n' ) {
   125         fprintf( f, "\n" );
   126     }
   127 }
   129 static void fprint_action( struct rule *rule, const struct action *action, int depth, FILE *f ) 
   130 {
   131     int i;
   132     if( action == NULL ) {
   133         fprintf( f, "%*cUNIMP(ir); /* %s */\n", depth*8, ' ', rule->format );
   134     } else {
   135         fprintf( f, "%*c{ /* %s */", depth*8, ' ', rule->format );
   136         if( rule->operand_count != 0 ) {
   137             fprintf( f, "\n%*c", depth*8, ' ' );
   138             for( i=0; i<rule->operand_count; i++ ) {
   139                 if( rule->operands[i].is_signed ) {
   140                     fprintf( f, "int32_t %s = SIGNEXT%d", rule->operands[i].name, rule->operands[i].bit_count );
   141                 } else {
   142                     fprintf( f, "uint32_t %s = ", rule->operands[i].name );
   143                 }
   144                 if( rule->operands[i].bit_shift == 0 ) {
   145                     fprintf( f, "(ir&0x%X)", (1<<(rule->operands[i].bit_count))-1 );
   146                 } else {
   147                     fprintf( f, "((ir>>%d)&0x%X)", rule->operands[i].bit_shift,
   148                             (1<<(rule->operands[i].bit_count))-1 );
   149                 }
   150                 if( rule->operands[i].left_shift != 0 ) {
   151                     fprintf( f, "<<%d", rule->operands[i].left_shift );
   152                 }
   153                 fprintf( f, "; " );
   154             }
   155         }
   156         fputs( "\n", f );
   157         if( action->text && action->text[0] != '\0' ) {
   158             fprintf( f, "#line %d \"%s\"\n", action->lineno, action->filename );
   159             fprint_indent( action->text, depth, f );
   160         }
   161         fprintf( f, "%*c}\n", depth*8, ' ' );
   162     }
   163 }
   165 static void split_and_generate( struct ruleset *rules, const struct action *actions, 
   166                          int ruleidx[], int rule_count, int input_mask, 
   167                          int depth, FILE *f ) {
   168     uint32_t mask;
   169     int i,j;
   171     if( rule_count == 0 ) {
   172         fprintf( f, "%*cUNDEF(ir);\n", depth*8, ' ' );
   173     } else if( rule_count == 1 ) {
   174         fprint_action( rules->rules[ruleidx[0]], &actions[ruleidx[0]], depth, f );
   175     } else {
   177         mask = find_mask(rules, ruleidx, rule_count, input_mask);
   178         if( mask == 0 ) { /* No matching mask? */
   179             fprintf( stderr, "Error: unable to find a valid bitmask (%d rules, %08X input mask)\n", rule_count, input_mask );
   180             dump_rulesubset( rules, ruleidx, rule_count, stderr );
   181             return;
   182         }
   184         /* break up the rules into sub-sets, and process each sub-set.
   185          * NB: We could do this in one pass at the cost of more complex
   186          * data structures. For now though, this keeps it simple
   187          */
   188         int option_count = get_option_count_for_mask( mask );
   189         uint32_t options[option_count];
   190         int subruleidx[rule_count];
   191         int subrule_count;
   192         int mask_shift = get_bitshift_for_mask( mask );
   193         int has_empty_options = 0;
   194         get_option_values_for_mask( options, mask );
   196         if( mask_shift == 0 ) {
   197             fprintf( f, "%*cswitch( ir&0x%X ) {\n", depth*8, ' ', mask );
   198         } else {
   199             fprintf( f, "%*cswitch( (ir&0x%X) >> %d ) {\n", depth*8, ' ',
   200                     mask, mask_shift);
   201         }
   202         for( i=0; i<option_count; i++ ) {
   203             subrule_count = 0;
   204             for( j=0; j<rule_count; j++ ) {
   205                 int match = rules->rules[ruleidx[j]]->bits & mask;
   206                 if( match == options[i] ) {
   207                     subruleidx[subrule_count++] = ruleidx[j];
   208                 }
   209             }
   210             if( subrule_count == 0 ) {
   211                 has_empty_options = 1;
   212             } else {
   213                 fprintf( f, "%*ccase 0x%X:\n", depth*8+4, ' ', options[i]>>mask_shift );
   214                 split_and_generate( rules, actions, subruleidx, subrule_count,
   215                                     mask|input_mask, depth+1, f );
   216                 fprintf( f, "%*cbreak;\n", depth*8+8, ' ' );
   217             }
   218         }
   219         if( has_empty_options ) {
   220             fprintf( f, "%*cdefault:\n%*cUNDEF(ir);\n%*cbreak;\n",
   221                     depth*8+4, ' ', depth*8+8, ' ', depth*8 + 8, ' ' );
   222         }
   223         fprintf( f, "%*c}\n", depth*8, ' ' );
   224     }
   225 }
   227 static int generate_decoder( struct ruleset *rules, actionfile_t af, FILE *out )
   228 {
   229     int ruleidx[rules->rule_count];
   230     int i;
   232     for( i=0; i<rules->rule_count; i++ ) {
   233         ruleidx[i] = i;
   234     }
   236     actiontoken_t token = action_file_next(af);
   237     while( token->symbol != END ) {
   238         if( token->symbol == TEXT ) {
   239             fprintf( out, "#line %d \"%s\"\n", token->lineno, token->filename );
   240             fputs( token->text, out );
   241         } else if( token->symbol == ERROR ) {
   242             fprintf( stderr, "Error parsing action file" );
   243             return -1;
   244         } else {
   245             split_and_generate( rules, token->actions, ruleidx, rules->rule_count, 0, 1, out );
   246         }
   247         token = action_file_next(af);
   248     }
   249     return 0;
   250 }
   252 static int generate_template( struct ruleset *rules, actionfile_t af, FILE *out )
   253 {
   254     int i;
   256     actiontoken_t token = action_file_next(af);
   257     while( token->symbol != END ) {
   258         if( token->symbol == TEXT ) {
   259             fputs( token->text, out );
   260         } else if( token->symbol == ERROR ) {
   261             fprintf( stderr, "Error parsing action file" );
   262             return -1;
   263         } else {
   264             fputs( "%%\n", out );
   265             for( i=0; i<rules->rule_count; i++ ) {
   266                 fprintf( out, "%s {: %s :}\n", rules->rules[i]->format,
   267                         token->actions[i].text == NULL ? "" : token->actions[i].text );
   268             }
   269             fputs( "%%\n", out );
   270         }
   271         token = action_file_next(af);
   272     }
   274     return 0;
   275 }
   278 int main( int argc, char *argv[] )
   279 {
   280     int opt;
   282     /* Parse the command line */
   283     while( (opt = getopt_long( argc, argv, option_list, longopts, NULL )) != -1 ) {
   284         switch( opt ) {
   285         case 't':
   286             gen_mode = GEN_TEMPLATE;
   287             break;
   288         case 'o':
   289             out_filename = optarg;
   290             break;
   291         case 'h':
   292             usage();
   293             exit(0);
   294         }
   295     }
   296     if( optind < argc ) {
   297         ins_filename = argv[optind++];
   298     }
   299     if( optind < argc ) {
   300         act_filename = argv[optind++];
   301     }
   303     if( optind < argc || ins_filename == NULL || act_filename == NULL ) {
   304         usage();
   305         exit(1);
   306     }
   308     if( out_filename == NULL ) {
   309         if( gen_mode == GEN_TEMPLATE ) {
   310             out_filename = act_filename;
   311         } else {
   312             char tmp[strlen(act_filename)+1];
   313             strcpy( tmp, act_filename);
   314             char *c = strrchr( tmp, '.' );
   315             if( c != NULL ) {
   316                 *c = '\0';
   317             }
   318             out_filename = g_strconcat( tmp, DEFAULT_OUT_EXT, NULL );
   319         }
   320     }
   322     /* Open the files */
   323     ins_file = fopen( ins_filename, "ro" );
   324     if( ins_file == NULL ) {
   325         fprintf( stderr, "Unable to open '%s' for reading (%s)\n", ins_filename, strerror(errno) );
   326         exit(2);
   327     }
   329     /* Parse the input */
   330     struct ruleset *rules = parse_ruleset_file( ins_file );
   331     fclose( ins_file );
   332     if( rules == NULL ) {
   333         exit(5);
   334     }
   336     actionfile_t af = action_file_open( act_filename, rules );
   337     if( af == NULL ) {
   338         fprintf( stderr, "Unable to open '%s' for reading (%s)\n", act_filename, strerror(errno) );
   339         exit(3);
   340     }
   343     /* Open the output file */
   344     out_file = fopen( out_filename, "wo" );
   345     if( out_file == NULL ) {
   346         fprintf( stderr, "Unable to open '%s' for writing (%s)\n", out_filename, strerror(errno) );
   347         exit(4);
   348     }
   350     switch( gen_mode ) {
   351     case GEN_SOURCE:
   352         if( generate_decoder( rules, af, out_file ) != 0 ) {
   353             exit(7);
   354         }
   355         break;
   356     case GEN_TEMPLATE:
   357         if( generate_template( rules, af, out_file ) != 0 ) {
   358             exit(7);
   359         }
   360         break;
   361     }
   363     action_file_close(af);
   364     fclose( out_file );
   365     return 0;
   366 }
.