Search
lxdream.org :: lxdream/src/tools/gendec.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/tools/gendec.c
changeset 1298:d0eb2307b847
prev1296:30ecee61f811
author nkeynes
date Wed Feb 04 08:38:23 2015 +1000 (5 years ago)
permissions -rw-r--r--
last change Fix assorted compile warnings reported by Clang
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.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:w";
    42 int gen_mode = GEN_SOURCE;
    43 int emit_warnings = 0;
    45 struct option longopts[] = { 
    46     { "help", no_argument, NULL, 'h' },
    47     { "output", required_argument, NULL, 'o' },
    48     { "template", no_argument, NULL, 't' },
    49     { "warnings", no_argument, NULL, 'w' },
    50     { NULL, 0, 0, 0 } };
    52 static void usage() {
    53     printf( "Usage: gendec [options] <instruction-file> <action-file> [ -o <output-file> ]\n" );
    54     printf( "Options:\n" );
    55     printf( "  -h, --help         Print this help message\n" );
    56     printf( "  -o, --output=FILE  Generate output to the given file\n" );
    57     printf( "  -t, --template     Generate a template skeleton instead of an instruction matcher\n" );
    58     printf( "  -w, --warnings     Emit warnings when unmatched instructions are found\n" );
    59 }
    61 /**
    62  * Check that rules are provided for all actions
    63  */
    64 static void check_actions( struct ruleset *rules, const actiontoken_t token )
    65 {
    66     int i;
    67     int warnings = 0;
    68     for( i=0; i<rules->rule_count; i++ ) {
    69         if( token->actions[i].text == NULL ) {
    70             if( warnings == 0 ) {
    71                 fprintf( stderr, "In action block starting at line %d of file %s:\n",
    72                          token->lineno, token->filename );
    73             }
    74             fprintf( stderr, "Warning: No action matches rule %d %s\n", i, rules->rules[i]->format );
    75             warnings++;
    76         } else {
    77             const char *s = token->actions[i].text;
    78             while( *s ) {
    79                 if( !isspace(*s) )
    80                     break;
    81                 s++;
    82             }
    83             if( !*s ) {
    84                 if( warnings == 0 ) {
    85                     fprintf( stderr, "In action block starting at line %d of file %s:\n",
    86                          token->lineno, token->filename );
    87                 }
    88                 fprintf( stderr, "Warning: Empty action for rule %d %s at line %d\n", i, rules->rules[i]->format,
    89                     token->actions[i].lineno );
    90                 warnings++;
    91             }
    92         }
    93     }
    94 }
    96 /**
    97  * Find a mask that can be used to split up the given rules
    98  */
    99 static uint32_t find_mask( struct ruleset *rules, int ruleidx[], int rule_count, 
   100                     uint32_t input_mask )
   101 {
   102     int i;
   103     uint32_t mask = rules->rules[ruleidx[0]]->mask;
   105     for( i=1; i<rule_count; i++ ) {
   106         mask = mask & rules->rules[ruleidx[i]]->mask;
   107     }
   109     assert( (mask & input_mask) == input_mask ); /* input_mask should always be included in the mask */
   111     return mask & (~input_mask); /* but we don't want to see the input mask again */
   112 }
   114 static int get_option_count_for_mask( uint32_t mask ) {
   115     int count = 0;
   117     while( mask ) {
   118         if( mask&1 ) 
   119             count++;
   120         mask >>= 1;
   121     }
   122     return 1<<count;
   123 }
   125 int get_bitshift_for_mask( uint32_t mask ) {
   126     int shift = 0;
   127     while( mask && !(mask&1) ) {
   128         shift++;
   129         mask >>= 1;
   130     }
   131     return shift;
   132 }
   134 static void get_option_values_for_mask( uint32_t *options, 
   135                                  uint32_t mask ) 
   136 {
   137     /* This could be a lot smarter. But it's not */
   138     int i;
   139     *options = 0;
   140     for( i=1; i<=mask; i++ ) {
   141         if( (i & mask) > *options ) {
   142             options++;
   143             *options = (i&mask);
   144         }
   145     }
   146 }
   148 static void fprint_indent( const char *action, int depth, FILE *f )
   149 {
   150     int spaces = 0, needed = depth*8, i;
   151     const char *text = action;
   153     /* Determine number of spaces in first line of input */
   154     for( i=0; isspace(action[i]); i++ ) {
   155         if( action[i] == '\n' ) {
   156             spaces = 0;
   157             text = &action[i+1];
   158         } else {
   159             spaces++;
   160         }
   161     }
   163     needed -= spaces;
   164     fprintf( f, "%*c", needed, ' ' );
   165     for( i=0; text[i] != '\0'; i++ ) {
   166         fputc( text[i], f );
   167         if( text[i] == '\n' && text[i+1] != '\0' ) {
   168             fprintf( f, "%*c", needed, ' ' );
   169         }
   170     }
   171     if( text[i-1] != '\n' ) {
   172         fprintf( f, "\n" );
   173     }
   174 }
   176 static void fprint_action( struct rule *rule, const struct action *action, int depth, FILE *f ) 
   177 {
   178     int i;
   179     if( action == NULL || action->text == NULL ) {
   180         fprintf( f, "%*cUNIMP(ir); /* %s */\n", depth*8, ' ', rule->format );
   181     } else {
   182         fprintf( f, "%*c{ /* %s */", depth*8, ' ', rule->format );
   183         if( rule->operand_count != 0 ) {
   184             fprintf( f, "\n%*c", depth*8, ' ' );
   185             for( i=0; i<rule->operand_count; i++ ) {
   186                 if( rule->operands[i].is_signed ) {
   187                     fprintf( f, "int32_t %s = SIGNEXT%d", rule->operands[i].name, rule->operands[i].bit_count );
   188                 } else {
   189                     fprintf( f, "uint32_t %s = ", rule->operands[i].name );
   190                 }
   191                 if( rule->operands[i].bit_shift == 0 ) {
   192                     fprintf( f, "(ir&0x%X)", (1<<(rule->operands[i].bit_count))-1 );
   193                 } else {
   194                     fprintf( f, "((ir>>%d)&0x%X)", rule->operands[i].bit_shift,
   195                             (1<<(rule->operands[i].bit_count))-1 );
   196                 }
   197                 if( rule->operands[i].left_shift != 0 ) {
   198                     fprintf( f, "<<%d", rule->operands[i].left_shift );
   199                 }
   200                 fprintf( f, "; " );
   201             }
   202         }
   203         fputs( "\n", f );
   204         if( action->text && action->text[0] != '\0' ) {
   205             fprintf( f, "#line %d \"%s\"\n", action->lineno, action->filename );
   206             fprint_indent( action->text, depth, f );
   207         }
   208         fprintf( f, "%*c}\n", depth*8, ' ' );
   209     }
   210 }
   212 static void split_and_generate( struct ruleset *rules, const struct action *actions, 
   213                          int ruleidx[], int rule_count, int input_mask, 
   214                          int depth, FILE *f ) {
   215     uint32_t mask;
   216     int i,j;
   218     if( rule_count == 0 ) {
   219         fprintf( f, "%*cUNDEF(ir);\n", depth*8, ' ' );
   220     } else if( rule_count == 1 ) {
   221         fprint_action( rules->rules[ruleidx[0]], &actions[ruleidx[0]], depth, f );
   222     } else {
   224         mask = find_mask(rules, ruleidx, rule_count, input_mask);
   225         if( mask == 0 ) { /* No matching mask? */
   226             fprintf( stderr, "Error: unable to find a valid bitmask (%d rules, %08X input mask)\n", rule_count, input_mask );
   227             dump_rulesubset( rules, ruleidx, rule_count, stderr );
   228             return;
   229         }
   231         /* break up the rules into sub-sets, and process each sub-set.
   232          * NB: We could do this in one pass at the cost of more complex
   233          * data structures. For now though, this keeps it simple
   234          */
   235         int option_count = get_option_count_for_mask( mask );
   236         uint32_t options[option_count];
   237         int subruleidx[rule_count];
   238         int subrule_count;
   239         int mask_shift = get_bitshift_for_mask( mask );
   240         int has_empty_options = 0;
   241         get_option_values_for_mask( options, mask );
   243         if( mask_shift == 0 ) {
   244             fprintf( f, "%*cswitch( ir&0x%X ) {\n", depth*8, ' ', mask );
   245         } else {
   246             fprintf( f, "%*cswitch( (ir&0x%X) >> %d ) {\n", depth*8, ' ',
   247                     mask, mask_shift);
   248         }
   249         for( i=0; i<option_count; i++ ) {
   250             subrule_count = 0;
   251             for( j=0; j<rule_count; j++ ) {
   252                 int match = rules->rules[ruleidx[j]]->bits & mask;
   253                 if( match == options[i] ) {
   254                     subruleidx[subrule_count++] = ruleidx[j];
   255                 }
   256             }
   257             if( subrule_count == 0 ) {
   258                 has_empty_options = 1;
   259             } else {
   260                 fprintf( f, "%*ccase 0x%X:\n", depth*8+4, ' ', options[i]>>mask_shift );
   261                 split_and_generate( rules, actions, subruleidx, subrule_count,
   262                                     mask|input_mask, depth+1, f );
   263                 fprintf( f, "%*cbreak;\n", depth*8+8, ' ' );
   264             }
   265         }
   266         if( has_empty_options ) {
   267             fprintf( f, "%*cdefault:\n%*cUNDEF(ir);\n%*cbreak;\n",
   268                     depth*8+4, ' ', depth*8+8, ' ', depth*8 + 8, ' ' );
   269         }
   270         fprintf( f, "%*c}\n", depth*8, ' ' );
   271     }
   272 }
   274 static int generate_decoder( struct ruleset *rules, actionfile_t af, FILE *out )
   275 {
   276     int ruleidx[rules->rule_count];
   277     int i;
   279     for( i=0; i<rules->rule_count; i++ ) {
   280         ruleidx[i] = i;
   281     }
   283     actiontoken_t token = action_file_next(af);
   284     while( token->symbol != END ) {
   285         if( token->symbol == TEXT ) {
   286             fprintf( out, "#line %d \"%s\"\n", token->lineno, token->filename );
   287             fputs( token->text, out );
   288         } else if( token->symbol == ERROR ) {
   289             fprintf( stderr, "Error parsing action file" );
   290             return -1;
   291         } else {
   292             if( emit_warnings ) {
   293                 check_actions( rules, token );
   294             }
   295             fprintf( out, "#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-variable\"\n" );
   296             split_and_generate( rules, token->actions, ruleidx, rules->rule_count, 0, 1, out );
   297             fprintf( out, "#pragma clang diagnostic pop\n" );
   298         }
   299         token = action_file_next(af);
   300     }
   301     return 0;
   302 }
   304 static int generate_template( struct ruleset *rules, actionfile_t af, FILE *out )
   305 {
   306     int i;
   308     actiontoken_t token = action_file_next(af);
   309     while( token->symbol != END ) {
   310         if( token->symbol == TEXT ) {
   311             fputs( token->text, out );
   312         } else if( token->symbol == ERROR ) {
   313             fprintf( stderr, "Error parsing action file" );
   314             return -1;
   315         } else {
   316             fputs( "%%\n", out );
   317             for( i=0; i<rules->rule_count; i++ ) {
   318                 fprintf( out, "%s {: %s :}\n", rules->rules[i]->format,
   319                         token->actions[i].text == NULL ? "" : token->actions[i].text );
   320             }
   321             fputs( "%%\n", out );
   322         }
   323         token = action_file_next(af);
   324     }
   326     return 0;
   327 }
   330 int main( int argc, char *argv[] )
   331 {
   332     int opt;
   334     /* Parse the command line */
   335     while( (opt = getopt_long( argc, argv, option_list, longopts, NULL )) != -1 ) {
   336         switch( opt ) {
   337         case 't':
   338             gen_mode = GEN_TEMPLATE;
   339             break;
   340         case 'o':
   341             out_filename = optarg;
   342             break;
   343         case 'w':
   344             emit_warnings = 1;
   345             break;
   346         case 'h':
   347             usage();
   348             exit(0);
   349         }
   350     }
   351     if( optind < argc ) {
   352         ins_filename = argv[optind++];
   353     }
   354     if( optind < argc ) {
   355         act_filename = argv[optind++];
   356     }
   358     if( optind < argc || ins_filename == NULL || act_filename == NULL ) {
   359         usage();
   360         exit(1);
   361     }
   363     if( out_filename == NULL ) {
   364         if( gen_mode == GEN_TEMPLATE ) {
   365             out_filename = act_filename;
   366         } else {
   367             char tmp[strlen(act_filename)+1];
   368             strcpy( tmp, act_filename);
   369             char *c = strrchr( tmp, '.' );
   370             if( c != NULL ) {
   371                 *c = '\0';
   372             }
   373             out_filename = g_strconcat( tmp, DEFAULT_OUT_EXT, NULL );
   374         }
   375     }
   377     /* Open the files */
   378     ins_file = fopen( ins_filename, "ro" );
   379     if( ins_file == NULL ) {
   380         fprintf( stderr, "Unable to open '%s' for reading (%s)\n", ins_filename, strerror(errno) );
   381         exit(2);
   382     }
   384     /* Parse the input */
   385     struct ruleset *rules = parse_ruleset_file( ins_file );
   386     fclose( ins_file );
   387     if( rules == NULL ) {
   388         exit(5);
   389     }
   391     actionfile_t af = action_file_open( act_filename, rules );
   392     if( af == NULL ) {
   393         fprintf( stderr, "Unable to open '%s' for reading (%s)\n", act_filename, strerror(errno) );
   394         exit(3);
   395     }
   398     /* Open the output file */
   399     out_file = fopen( out_filename, "wo" );
   400     if( out_file == NULL ) {
   401         fprintf( stderr, "Unable to open '%s' for writing (%s)\n", out_filename, strerror(errno) );
   402         exit(4);
   403     }
   405     switch( gen_mode ) {
   406     case GEN_SOURCE:
   407         if( generate_decoder( rules, af, out_file ) != 0 ) {
   408             exit(7);
   409         }
   410         break;
   411     case GEN_TEMPLATE:
   412         if( generate_template( rules, af, out_file ) != 0 ) {
   413             exit(7);
   414         }
   415         break;
   416     }
   418     action_file_close(af);
   419     fclose( out_file );
   420     return 0;
   421 }
.