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