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