Search
lxdream.org :: lxdream/src/tools/gendec.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/tools/gendec.c
changeset 561:533f6b478071
prev420:e6f43dec3cf0
next736:a02d1475ccfd
author nkeynes
date Tue Jan 01 05:08:38 2008 +0000 (16 years ago)
branchlxdream-mmu
permissions -rw-r--r--
last change Enable Id keyword on all source files
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@359
    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@359
    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@359
    71
	if( mask&1 ) 
nkeynes@359
    72
	    count++;
nkeynes@359
    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@359
    81
	shift++;
nkeynes@359
    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@359
    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@359
    94
	if( (i & mask) > *options ) {
nkeynes@359
    95
	    options++;
nkeynes@359
    96
	    *options = (i&mask);
nkeynes@359
    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@359
   108
	if( action[i] == '\n' ) {
nkeynes@359
   109
	    spaces = 0;
nkeynes@359
   110
	    text = &action[i+1];
nkeynes@359
   111
	} else {
nkeynes@359
   112
	    spaces++;
nkeynes@359
   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@359
   119
	fputc( text[i], f );
nkeynes@359
   120
	if( text[i] == '\n' && text[i+1] != '\0' ) {
nkeynes@359
   121
	    fprintf( f, "%*c", needed, ' ' );
nkeynes@359
   122
	}
nkeynes@359
   123
    }
nkeynes@359
   124
    if( text[i-1] != '\n' ) {
nkeynes@359
   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@359
   133
	fprintf( f, "%*cUNIMP(ir); /* %s */\n", depth*8, ' ', rule->format );
nkeynes@359
   134
    } else {
nkeynes@359
   135
	fprintf( f, "%*c{ /* %s */", depth*8, ' ', rule->format );
nkeynes@359
   136
	if( rule->operand_count != 0 ) {
nkeynes@359
   137
	    fprintf( f, "\n%*c", depth*8, ' ' );
nkeynes@359
   138
	    for( i=0; i<rule->operand_count; i++ ) {
nkeynes@359
   139
		if( rule->operands[i].is_signed ) {
nkeynes@359
   140
		    fprintf( f, "int32_t %s = SIGNEXT%d", rule->operands[i].name, rule->operands[i].bit_count );
nkeynes@359
   141
		} else {
nkeynes@359
   142
		    fprintf( f, "uint32_t %s = ", rule->operands[i].name );
nkeynes@359
   143
		}
nkeynes@359
   144
		if( rule->operands[i].bit_shift == 0 ) {
nkeynes@359
   145
		    fprintf( f, "(ir&0x%X)", (1<<(rule->operands[i].bit_count))-1 );
nkeynes@359
   146
		} else {
nkeynes@359
   147
		    fprintf( f, "((ir>>%d)&0x%X)", rule->operands[i].bit_shift,
nkeynes@359
   148
			     (1<<(rule->operands[i].bit_count))-1 );
nkeynes@359
   149
		}
nkeynes@359
   150
		if( rule->operands[i].left_shift != 0 ) {
nkeynes@359
   151
		    fprintf( f, "<<%d", rule->operands[i].left_shift );
nkeynes@359
   152
		}
nkeynes@359
   153
		fprintf( f, "; " );
nkeynes@359
   154
	    }
nkeynes@359
   155
	}
nkeynes@359
   156
	fputs( "\n", f );
nkeynes@359
   157
	if( action[0] != '\0' ) {
nkeynes@359
   158
	    fprint_indent( action, depth, f );
nkeynes@359
   159
	}
nkeynes@359
   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@359
   165
			int ruleidx[], int rule_count, int input_mask, 
nkeynes@359
   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@359
   171
	fprintf( f, "%*cUNDEF(ir);\n", depth*8, ' ' );
nkeynes@359
   172
    } else if( rule_count == 1 ) {
nkeynes@359
   173
	fprint_action( rules->rules[ruleidx[0]], actions->actions[ruleidx[0]], depth, f );
nkeynes@359
   174
    } else {
nkeynes@359
   175
nkeynes@359
   176
	mask = find_mask(rules, ruleidx, rule_count, input_mask);
nkeynes@359
   177
	if( mask == 0 ) { /* No matching mask? */
nkeynes@359
   178
	    fprintf( stderr, "Error: unable to find a valid bitmask (%d rules, %08X input mask)\n", rule_count, input_mask );
nkeynes@359
   179
	    dump_rulesubset( rules, ruleidx, rule_count, stderr );
nkeynes@420
   180
	    return;
nkeynes@359
   181
	}
nkeynes@359
   182
	
nkeynes@359
   183
	/* break up the rules into sub-sets, and process each sub-set.
nkeynes@359
   184
	 * NB: We could do this in one pass at the cost of more complex
nkeynes@359
   185
	 * data structures. For now though, this keeps it simple
nkeynes@359
   186
	 */
nkeynes@359
   187
	int option_count = get_option_count_for_mask( mask );
nkeynes@359
   188
	uint32_t options[option_count];
nkeynes@359
   189
	int subruleidx[rule_count];
nkeynes@359
   190
	int subrule_count;
nkeynes@359
   191
	int mask_shift = get_bitshift_for_mask( mask );
nkeynes@359
   192
	int has_empty_options = 0;
nkeynes@359
   193
	get_option_values_for_mask( options, mask );
nkeynes@359
   194
	
nkeynes@359
   195
	if( mask_shift == 0 ) {
nkeynes@359
   196
	    fprintf( f, "%*cswitch( ir&0x%X ) {\n", depth*8, ' ', mask );
nkeynes@359
   197
	} else {
nkeynes@359
   198
	    fprintf( f, "%*cswitch( (ir&0x%X) >> %d ) {\n", depth*8, ' ',
nkeynes@359
   199
		     mask, mask_shift);
nkeynes@359
   200
	}
nkeynes@359
   201
	for( i=0; i<option_count; i++ ) {
nkeynes@359
   202
	    subrule_count = 0;
nkeynes@359
   203
	    for( j=0; j<rule_count; j++ ) {
nkeynes@359
   204
		int match = rules->rules[ruleidx[j]]->bits & mask;
nkeynes@359
   205
		if( match == options[i] ) {
nkeynes@359
   206
		    subruleidx[subrule_count++] = ruleidx[j];
nkeynes@359
   207
		}
nkeynes@359
   208
	    }
nkeynes@359
   209
	    if( subrule_count == 0 ) {
nkeynes@359
   210
		has_empty_options = 1;
nkeynes@359
   211
	    } else {
nkeynes@359
   212
		fprintf( f, "%*ccase 0x%X:\n", depth*8+4, ' ', options[i]>>mask_shift );
nkeynes@359
   213
		split_and_generate( rules, actions, subruleidx, subrule_count,
nkeynes@359
   214
				    mask|input_mask, depth+1, f );
nkeynes@359
   215
		fprintf( f, "%*cbreak;\n", depth*8+8, ' ' );
nkeynes@359
   216
	    }
nkeynes@359
   217
	}
nkeynes@359
   218
	if( has_empty_options ) {
nkeynes@359
   219
	    fprintf( f, "%*cdefault:\n%*cUNDEF();\n%*cbreak;\n",
nkeynes@359
   220
		     depth*8+4, ' ', depth*8+8, ' ', depth*8 + 8, ' ' );
nkeynes@359
   221
	}
nkeynes@359
   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@359
   232
	ruleidx[i] = i;
nkeynes@359
   233
    }
nkeynes@359
   234
nkeynes@359
   235
    fputs( actions->pretext, f );
nkeynes@359
   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@359
   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@359
   251
	fprintf( f, "%s {: %s :}\n", rules->rules[i]->format, 
nkeynes@359
   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@359
   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@420
   268
	case 't':
nkeynes@420
   269
	    gen_mode = GEN_TEMPLATE;
nkeynes@420
   270
	    break;
nkeynes@420
   271
	case 'o':
nkeynes@420
   272
	    out_filename = optarg;
nkeynes@420
   273
	    break;
nkeynes@420
   274
	case 'h':
nkeynes@420
   275
	    usage();
nkeynes@420
   276
	    exit(0);
nkeynes@420
   277
	}
nkeynes@420
   278
    }
nkeynes@420
   279
    if( optind < argc ) {
nkeynes@420
   280
	ins_filename = argv[optind++];
nkeynes@420
   281
    }
nkeynes@420
   282
    if( optind < argc ) {
nkeynes@420
   283
	act_filename = argv[optind++];
nkeynes@420
   284
    }
nkeynes@420
   285
nkeynes@420
   286
    if( optind < argc || ins_filename == NULL || act_filename == NULL ) {
nkeynes@420
   287
	usage();
nkeynes@420
   288
	exit(1);
nkeynes@420
   289
    }
nkeynes@420
   290
    
nkeynes@420
   291
    if( out_filename == NULL ) {
nkeynes@420
   292
	if( gen_mode == GEN_TEMPLATE ) {
nkeynes@420
   293
	    out_filename = act_filename;
nkeynes@420
   294
	} else {
nkeynes@420
   295
	    char tmp[strlen(act_filename)+1];
nkeynes@420
   296
	    strcpy( tmp, act_filename);
nkeynes@420
   297
	    char *c = strrchr( tmp, '.' );
nkeynes@420
   298
	    if( c != NULL ) {
nkeynes@420
   299
		*c = '\0';
nkeynes@420
   300
	    }
nkeynes@420
   301
	    out_filename = g_strconcat( tmp, DEFAULT_OUT_EXT, NULL );
nkeynes@420
   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@420
   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@420
   315
	exit(3);
nkeynes@420
   316
    }
nkeynes@420
   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@420
   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@420
   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@420
   335
	exit(4);
nkeynes@420
   336
    }
nkeynes@420
   337
    
nkeynes@420
   338
    switch( gen_mode ) {
nkeynes@420
   339
    case GEN_SOURCE:
nkeynes@420
   340
	if( generate_decoder( rules, actions, out_file ) != 0 ) {
nkeynes@420
   341
	    exit(7);
nkeynes@420
   342
	}
nkeynes@420
   343
	break;
nkeynes@420
   344
    case GEN_TEMPLATE:
nkeynes@420
   345
	if( generate_template( rules, actions, out_file ) != 0 ) {
nkeynes@420
   346
	    exit(7);
nkeynes@420
   347
	}
nkeynes@420
   348
	break;
nkeynes@420
   349
    }
nkeynes@420
   350
    fclose( out_file );
nkeynes@420
   351
    return 0;
nkeynes@420
   352
}
.