Search
lxdream.org :: lxdream/src/tools/gendec.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/tools/gendec.c
changeset 824:016cda9d0518
prev736:a02d1475ccfd
next948:545c85cc56f1
author nkeynes
date Sun Aug 24 01:43:17 2008 +0000 (11 years ago)
permissions -rw-r--r--
last change Correct generated UNDEF() => UNDEF(ir) for consistency with UNIMP(ir)
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@359
    45
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@359
    52
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@359
    67
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@359
    87
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@420
   101
void fprint_indent( char *action, int depth, FILE *f )
nkeynes@359
   102
{
nkeynes@359
   103
    int spaces = 0, needed = depth*8, i;
nkeynes@359
   104
    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@420
   129
void fprint_action( struct rule *rule, char *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@736
   157
        if( action[0] != '\0' ) {
nkeynes@736
   158
            fprint_indent( action, depth, f );
nkeynes@736
   159
        }
nkeynes@736
   160
        fprintf( f, "%*c}\n", depth*8, ' ' );
nkeynes@359
   161
    }
nkeynes@359
   162
}
nkeynes@359
   163
nkeynes@420
   164
void split_and_generate( struct ruleset *rules, struct actionset *actions, 
nkeynes@736
   165
                         int ruleidx[], int rule_count, int input_mask, 
nkeynes@736
   166
                         int depth, FILE *f ) {
nkeynes@359
   167
    uint32_t mask;
nkeynes@359
   168
    int i,j;
nkeynes@359
   169
nkeynes@359
   170
    if( rule_count == 0 ) {
nkeynes@736
   171
        fprintf( f, "%*cUNDEF(ir);\n", depth*8, ' ' );
nkeynes@359
   172
    } else if( rule_count == 1 ) {
nkeynes@736
   173
        fprint_action( rules->rules[ruleidx[0]], actions->actions[ruleidx[0]], depth, f );
nkeynes@359
   174
    } else {
nkeynes@359
   175
nkeynes@736
   176
        mask = find_mask(rules, ruleidx, rule_count, input_mask);
nkeynes@736
   177
        if( mask == 0 ) { /* No matching mask? */
nkeynes@736
   178
            fprintf( stderr, "Error: unable to find a valid bitmask (%d rules, %08X input mask)\n", rule_count, input_mask );
nkeynes@736
   179
            dump_rulesubset( rules, ruleidx, rule_count, stderr );
nkeynes@736
   180
            return;
nkeynes@736
   181
        }
nkeynes@736
   182
nkeynes@736
   183
        /* break up the rules into sub-sets, and process each sub-set.
nkeynes@736
   184
         * NB: We could do this in one pass at the cost of more complex
nkeynes@736
   185
         * data structures. For now though, this keeps it simple
nkeynes@736
   186
         */
nkeynes@736
   187
        int option_count = get_option_count_for_mask( mask );
nkeynes@736
   188
        uint32_t options[option_count];
nkeynes@736
   189
        int subruleidx[rule_count];
nkeynes@736
   190
        int subrule_count;
nkeynes@736
   191
        int mask_shift = get_bitshift_for_mask( mask );
nkeynes@736
   192
        int has_empty_options = 0;
nkeynes@736
   193
        get_option_values_for_mask( options, mask );
nkeynes@736
   194
nkeynes@736
   195
        if( mask_shift == 0 ) {
nkeynes@736
   196
            fprintf( f, "%*cswitch( ir&0x%X ) {\n", depth*8, ' ', mask );
nkeynes@736
   197
        } else {
nkeynes@736
   198
            fprintf( f, "%*cswitch( (ir&0x%X) >> %d ) {\n", depth*8, ' ',
nkeynes@736
   199
                    mask, mask_shift);
nkeynes@736
   200
        }
nkeynes@736
   201
        for( i=0; i<option_count; i++ ) {
nkeynes@736
   202
            subrule_count = 0;
nkeynes@736
   203
            for( j=0; j<rule_count; j++ ) {
nkeynes@736
   204
                int match = rules->rules[ruleidx[j]]->bits & mask;
nkeynes@736
   205
                if( match == options[i] ) {
nkeynes@736
   206
                    subruleidx[subrule_count++] = ruleidx[j];
nkeynes@736
   207
                }
nkeynes@736
   208
            }
nkeynes@736
   209
            if( subrule_count == 0 ) {
nkeynes@736
   210
                has_empty_options = 1;
nkeynes@736
   211
            } else {
nkeynes@736
   212
                fprintf( f, "%*ccase 0x%X:\n", depth*8+4, ' ', options[i]>>mask_shift );
nkeynes@736
   213
                split_and_generate( rules, actions, subruleidx, subrule_count,
nkeynes@736
   214
                                    mask|input_mask, depth+1, f );
nkeynes@736
   215
                fprintf( f, "%*cbreak;\n", depth*8+8, ' ' );
nkeynes@736
   216
            }
nkeynes@736
   217
        }
nkeynes@736
   218
        if( has_empty_options ) {
nkeynes@824
   219
            fprintf( f, "%*cdefault:\n%*cUNDEF(ir);\n%*cbreak;\n",
nkeynes@736
   220
                    depth*8+4, ' ', depth*8+8, ' ', depth*8 + 8, ' ' );
nkeynes@736
   221
        }
nkeynes@736
   222
        fprintf( f, "%*c}\n", depth*8, ' ' );
nkeynes@359
   223
    }
nkeynes@359
   224
}
nkeynes@359
   225
nkeynes@359
   226
int generate_decoder( struct ruleset *rules, struct actionset *actions, FILE *f )
nkeynes@359
   227
{
nkeynes@359
   228
    int ruleidx[rules->rule_count];
nkeynes@359
   229
    int i;
nkeynes@359
   230
nkeynes@359
   231
    for( i=0; i<rules->rule_count; i++ ) {
nkeynes@736
   232
        ruleidx[i] = i;
nkeynes@359
   233
    }
nkeynes@359
   234
nkeynes@359
   235
    fputs( actions->pretext, f );
nkeynes@736
   236
nkeynes@359
   237
    split_and_generate( rules, actions, ruleidx, rules->rule_count, 0, 1, f );
nkeynes@359
   238
nkeynes@359
   239
    fputs( actions->posttext, f );
nkeynes@736
   240
nkeynes@359
   241
    return 0;
nkeynes@359
   242
}
nkeynes@359
   243
nkeynes@359
   244
int generate_template( struct ruleset *rules, struct actionset *actions, FILE *f )
nkeynes@359
   245
{
nkeynes@359
   246
    int i;
nkeynes@359
   247
    fputs( actions->pretext, f );
nkeynes@359
   248
    fputs( "%%\n", f );
nkeynes@359
   249
nkeynes@359
   250
    for( i=0; i<rules->rule_count; i++ ) {
nkeynes@736
   251
        fprintf( f, "%s {: %s :}\n", rules->rules[i]->format, 
nkeynes@736
   252
                actions->actions[i] == NULL ? "" : actions->actions[i] );
nkeynes@359
   253
    }
nkeynes@359
   254
    fputs( "%%\n", f );
nkeynes@359
   255
    fputs( actions->posttext, f );
nkeynes@736
   256
nkeynes@359
   257
    return 0;
nkeynes@359
   258
}
nkeynes@420
   259
nkeynes@420
   260
nkeynes@420
   261
int main( int argc, char *argv[] )
nkeynes@420
   262
{
nkeynes@420
   263
    int opt;
nkeynes@420
   264
nkeynes@420
   265
    /* Parse the command line */
nkeynes@420
   266
    while( (opt = getopt_long( argc, argv, option_list, longopts, NULL )) != -1 ) {
nkeynes@420
   267
        switch( opt ) {
nkeynes@736
   268
        case 't':
nkeynes@736
   269
            gen_mode = GEN_TEMPLATE;
nkeynes@736
   270
            break;
nkeynes@736
   271
        case 'o':
nkeynes@736
   272
            out_filename = optarg;
nkeynes@736
   273
            break;
nkeynes@736
   274
        case 'h':
nkeynes@736
   275
            usage();
nkeynes@736
   276
            exit(0);
nkeynes@736
   277
        }
nkeynes@420
   278
    }
nkeynes@420
   279
    if( optind < argc ) {
nkeynes@736
   280
        ins_filename = argv[optind++];
nkeynes@420
   281
    }
nkeynes@420
   282
    if( optind < argc ) {
nkeynes@736
   283
        act_filename = argv[optind++];
nkeynes@420
   284
    }
nkeynes@420
   285
nkeynes@420
   286
    if( optind < argc || ins_filename == NULL || act_filename == NULL ) {
nkeynes@736
   287
        usage();
nkeynes@736
   288
        exit(1);
nkeynes@420
   289
    }
nkeynes@736
   290
nkeynes@420
   291
    if( out_filename == NULL ) {
nkeynes@736
   292
        if( gen_mode == GEN_TEMPLATE ) {
nkeynes@736
   293
            out_filename = act_filename;
nkeynes@736
   294
        } else {
nkeynes@736
   295
            char tmp[strlen(act_filename)+1];
nkeynes@736
   296
            strcpy( tmp, act_filename);
nkeynes@736
   297
            char *c = strrchr( tmp, '.' );
nkeynes@736
   298
            if( c != NULL ) {
nkeynes@736
   299
                *c = '\0';
nkeynes@736
   300
            }
nkeynes@736
   301
            out_filename = g_strconcat( tmp, DEFAULT_OUT_EXT, NULL );
nkeynes@736
   302
        }
nkeynes@420
   303
    }
nkeynes@420
   304
nkeynes@420
   305
    /* Open the files */
nkeynes@420
   306
    ins_file = fopen( ins_filename, "ro" );
nkeynes@420
   307
    if( ins_file == NULL ) {
nkeynes@420
   308
        fprintf( stderr, "Unable to open '%s' for reading (%s)\n", ins_filename, strerror(errno) );
nkeynes@736
   309
        exit(2);
nkeynes@420
   310
    }
nkeynes@420
   311
nkeynes@420
   312
    act_file = fopen( act_filename, "ro" );
nkeynes@420
   313
    if( act_file == NULL ) {
nkeynes@420
   314
        fprintf( stderr, "Unable to open '%s' for reading (%s)\n", act_filename, strerror(errno) );
nkeynes@736
   315
        exit(3);
nkeynes@420
   316
    }
nkeynes@736
   317
nkeynes@420
   318
    /* Parse the input */
nkeynes@420
   319
    struct ruleset *rules = parse_ruleset_file( ins_file );
nkeynes@420
   320
    fclose( ins_file );
nkeynes@420
   321
    if( rules == NULL ) {
nkeynes@736
   322
        exit(5);
nkeynes@420
   323
    }
nkeynes@420
   324
nkeynes@420
   325
    struct actionset *actions = parse_action_file( rules, act_file );
nkeynes@420
   326
    fclose( act_file );
nkeynes@420
   327
    if( actions == NULL ) {
nkeynes@736
   328
        exit(6);
nkeynes@420
   329
    }
nkeynes@420
   330
nkeynes@420
   331
    /* Finally write out the results */
nkeynes@420
   332
    out_file = fopen( out_filename, "wo" );
nkeynes@420
   333
    if( out_file == NULL ) {
nkeynes@420
   334
        fprintf( stderr, "Unable to open '%s' for writing (%s)\n", out_filename, strerror(errno) );
nkeynes@736
   335
        exit(4);
nkeynes@420
   336
    }
nkeynes@736
   337
nkeynes@420
   338
    switch( gen_mode ) {
nkeynes@420
   339
    case GEN_SOURCE:
nkeynes@736
   340
        if( generate_decoder( rules, actions, out_file ) != 0 ) {
nkeynes@736
   341
            exit(7);
nkeynes@736
   342
        }
nkeynes@736
   343
        break;
nkeynes@420
   344
    case GEN_TEMPLATE:
nkeynes@736
   345
        if( generate_template( rules, actions, out_file ) != 0 ) {
nkeynes@736
   346
            exit(7);
nkeynes@736
   347
        }
nkeynes@736
   348
        break;
nkeynes@420
   349
    }
nkeynes@420
   350
    fclose( out_file );
nkeynes@420
   351
    return 0;
nkeynes@420
   352
}
.