2 * $Id: gendec.c,v 1.2 2007-10-06 08:48:47 nkeynes Exp $
4 * Parse the instruction and action files and generate an appropriate
7 * Copyright (c) 2005 Nathan Keynes.
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.
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.
26 #include <glib/gstrfuncs.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;
37 #define GEN_TEMPLATE 2
39 FILE *ins_file, *act_file, *out_file;
41 char *option_list = "tmho:";
42 int gen_mode = GEN_SOURCE;
43 struct option longopts[1] = { { NULL, 0, 0, 0 } };
46 printf( "gendec <instruction-file> <action-file> [ -o <output-file> ]\n" );
50 * Find a mask that can be used to split up the given rules
52 uint32_t find_mask( struct ruleset *rules, int ruleidx[], int rule_count,
56 uint32_t mask = rules->rules[ruleidx[0]]->mask;
58 for( i=1; i<rule_count; i++ ) {
59 mask = mask & rules->rules[ruleidx[i]]->mask;
62 assert( (mask & input_mask) == input_mask ); /* input_mask should always be included in the mask */
64 return mask & (~input_mask); /* but we don't want to see the input mask again */
67 int get_option_count_for_mask( uint32_t mask ) {
78 int get_bitshift_for_mask( uint32_t mask ) {
80 while( mask && !(mask&1) ) {
87 void get_option_values_for_mask( uint32_t *options,
90 /* This could be a lot smarter. But it's not */
93 for( i=1; i<=mask; i++ ) {
94 if( (i & mask) > *options ) {
101 void fprint_indent( char *action, int depth, FILE *f )
103 int spaces = 0, needed = depth*8, i;
106 /* Determine number of spaces in first line of input */
107 for( i=0; isspace(action[i]); i++ ) {
108 if( action[i] == '\n' ) {
117 fprintf( f, "%*c", needed, ' ' );
118 for( i=0; text[i] != '\0'; i++ ) {
120 if( text[i] == '\n' && text[i+1] != '\0' ) {
121 fprintf( f, "%*c", needed, ' ' );
124 if( text[i-1] != '\n' ) {
129 void fprint_action( struct rule *rule, char *action, int depth, FILE *f )
132 if( action == NULL ) {
133 fprintf( f, "%*cUNIMP(ir); /* %s */\n", depth*8, ' ', rule->format );
135 fprintf( f, "%*c{ /* %s */", depth*8, ' ', rule->format );
136 if( rule->operand_count != 0 ) {
137 fprintf( f, "\n%*c", depth*8, ' ' );
138 for( i=0; i<rule->operand_count; i++ ) {
139 if( rule->operands[i].is_signed ) {
140 fprintf( f, "int32_t %s = SIGNEXT%d", rule->operands[i].name, rule->operands[i].bit_count );
142 fprintf( f, "uint32_t %s = ", rule->operands[i].name );
144 if( rule->operands[i].bit_shift == 0 ) {
145 fprintf( f, "(ir&0x%X)", (1<<(rule->operands[i].bit_count))-1 );
147 fprintf( f, "((ir>>%d)&0x%X)", rule->operands[i].bit_shift,
148 (1<<(rule->operands[i].bit_count))-1 );
150 if( rule->operands[i].left_shift != 0 ) {
151 fprintf( f, "<<%d", rule->operands[i].left_shift );
157 if( action[0] != '\0' ) {
158 fprint_indent( action, depth, f );
160 fprintf( f, "%*c}\n", depth*8, ' ' );
164 void split_and_generate( struct ruleset *rules, struct actionset *actions,
165 int ruleidx[], int rule_count, int input_mask,
166 int depth, FILE *f ) {
170 if( rule_count == 0 ) {
171 fprintf( f, "%*cUNDEF(ir);\n", depth*8, ' ' );
172 } else if( rule_count == 1 ) {
173 fprint_action( rules->rules[ruleidx[0]], actions->actions[ruleidx[0]], depth, f );
176 mask = find_mask(rules, ruleidx, rule_count, input_mask);
177 if( mask == 0 ) { /* No matching mask? */
178 fprintf( stderr, "Error: unable to find a valid bitmask (%d rules, %08X input mask)\n", rule_count, input_mask );
179 dump_rulesubset( rules, ruleidx, rule_count, stderr );
183 /* break up the rules into sub-sets, and process each sub-set.
184 * NB: We could do this in one pass at the cost of more complex
185 * data structures. For now though, this keeps it simple
187 int option_count = get_option_count_for_mask( mask );
188 uint32_t options[option_count];
189 int subruleidx[rule_count];
191 int mask_shift = get_bitshift_for_mask( mask );
192 int has_empty_options = 0;
193 get_option_values_for_mask( options, mask );
195 if( mask_shift == 0 ) {
196 fprintf( f, "%*cswitch( ir&0x%X ) {\n", depth*8, ' ', mask );
198 fprintf( f, "%*cswitch( (ir&0x%X) >> %d ) {\n", depth*8, ' ',
201 for( i=0; i<option_count; i++ ) {
203 for( j=0; j<rule_count; j++ ) {
204 int match = rules->rules[ruleidx[j]]->bits & mask;
205 if( match == options[i] ) {
206 subruleidx[subrule_count++] = ruleidx[j];
209 if( subrule_count == 0 ) {
210 has_empty_options = 1;
212 fprintf( f, "%*ccase 0x%X:\n", depth*8+4, ' ', options[i]>>mask_shift );
213 split_and_generate( rules, actions, subruleidx, subrule_count,
214 mask|input_mask, depth+1, f );
215 fprintf( f, "%*cbreak;\n", depth*8+8, ' ' );
218 if( has_empty_options ) {
219 fprintf( f, "%*cdefault:\n%*cUNDEF();\n%*cbreak;\n",
220 depth*8+4, ' ', depth*8+8, ' ', depth*8 + 8, ' ' );
222 fprintf( f, "%*c}\n", depth*8, ' ' );
226 int generate_decoder( struct ruleset *rules, struct actionset *actions, FILE *f )
228 int ruleidx[rules->rule_count];
231 for( i=0; i<rules->rule_count; i++ ) {
235 fputs( actions->pretext, f );
237 split_and_generate( rules, actions, ruleidx, rules->rule_count, 0, 1, f );
239 fputs( actions->posttext, f );
244 int generate_template( struct ruleset *rules, struct actionset *actions, FILE *f )
247 fputs( actions->pretext, f );
250 for( i=0; i<rules->rule_count; i++ ) {
251 fprintf( f, "%s {: %s :}\n", rules->rules[i]->format,
252 actions->actions[i] == NULL ? "" : actions->actions[i] );
255 fputs( actions->posttext, f );
261 int main( int argc, char *argv[] )
265 /* Parse the command line */
266 while( (opt = getopt_long( argc, argv, option_list, longopts, NULL )) != -1 ) {
269 gen_mode = GEN_TEMPLATE;
272 out_filename = optarg;
279 if( optind < argc ) {
280 ins_filename = argv[optind++];
282 if( optind < argc ) {
283 act_filename = argv[optind++];
286 if( optind < argc || ins_filename == NULL || act_filename == NULL ) {
291 if( out_filename == NULL ) {
292 if( gen_mode == GEN_TEMPLATE ) {
293 out_filename = act_filename;
295 char tmp[strlen(act_filename)+1];
296 strcpy( tmp, act_filename);
297 char *c = strrchr( tmp, '.' );
301 out_filename = g_strconcat( tmp, DEFAULT_OUT_EXT, NULL );
306 ins_file = fopen( ins_filename, "ro" );
307 if( ins_file == NULL ) {
308 fprintf( stderr, "Unable to open '%s' for reading (%s)\n", ins_filename, strerror(errno) );
312 act_file = fopen( act_filename, "ro" );
313 if( act_file == NULL ) {
314 fprintf( stderr, "Unable to open '%s' for reading (%s)\n", act_filename, strerror(errno) );
318 /* Parse the input */
319 struct ruleset *rules = parse_ruleset_file( ins_file );
321 if( rules == NULL ) {
325 struct actionset *actions = parse_action_file( rules, act_file );
327 if( actions == NULL ) {
331 /* Finally write out the results */
332 out_file = fopen( out_filename, "wo" );
333 if( out_file == NULL ) {
334 fprintf( stderr, "Unable to open '%s' for writing (%s)\n", out_filename, strerror(errno) );
340 if( generate_decoder( rules, actions, out_file ) != 0 ) {
345 if( generate_template( rules, actions, out_file ) != 0 ) {
.