filename | src/tools/gendec.c |
changeset | 979:2cc7b486ea6c |
prev | 969:3f178ca1398c |
next | 1084:852412cf56e0 |
author | nkeynes |
date | Wed Feb 25 09:00:05 2009 +0000 (15 years ago) |
permissions | -rw-r--r-- |
last change | Argh. Apparently we still do really need _BSD_SOURCE and _GNU_SOURCE I think that's everything now... |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * Parse the instruction and action files and generate an appropriate
5 * instruction decoder.
6 *
7 * Copyright (c) 2005 Nathan Keynes.
8 *
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.
13 *
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.
18 */
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <getopt.h>
24 #include <errno.h>
25 #include <ctype.h>
26 #include <glib/gstrfuncs.h>
27 #include <assert.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;
36 #define GEN_SOURCE 1
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 } };
45 static void usage() {
46 printf( "gendec <instruction-file> <action-file> [ -o <output-file> ]\n" );
47 }
49 /**
50 * Find a mask that can be used to split up the given rules
51 */
52 static uint32_t find_mask( struct ruleset *rules, int ruleidx[], int rule_count,
53 uint32_t input_mask )
54 {
55 int i;
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;
60 }
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 */
65 }
67 static int get_option_count_for_mask( uint32_t mask ) {
68 int count = 0;
70 while( mask ) {
71 if( mask&1 )
72 count++;
73 mask >>= 1;
74 }
75 return 1<<count;
76 }
78 int get_bitshift_for_mask( uint32_t mask ) {
79 int shift = 0;
80 while( mask && !(mask&1) ) {
81 shift++;
82 mask >>= 1;
83 }
84 return shift;
85 }
87 static void get_option_values_for_mask( uint32_t *options,
88 uint32_t mask )
89 {
90 /* This could be a lot smarter. But it's not */
91 int i;
92 *options = 0;
93 for( i=1; i<=mask; i++ ) {
94 if( (i & mask) > *options ) {
95 options++;
96 *options = (i&mask);
97 }
98 }
99 }
101 static void fprint_indent( const char *action, int depth, FILE *f )
102 {
103 int spaces = 0, needed = depth*8, i;
104 const char *text = action;
106 /* Determine number of spaces in first line of input */
107 for( i=0; isspace(action[i]); i++ ) {
108 if( action[i] == '\n' ) {
109 spaces = 0;
110 text = &action[i+1];
111 } else {
112 spaces++;
113 }
114 }
116 needed -= spaces;
117 fprintf( f, "%*c", needed, ' ' );
118 for( i=0; text[i] != '\0'; i++ ) {
119 fputc( text[i], f );
120 if( text[i] == '\n' && text[i+1] != '\0' ) {
121 fprintf( f, "%*c", needed, ' ' );
122 }
123 }
124 if( text[i-1] != '\n' ) {
125 fprintf( f, "\n" );
126 }
127 }
129 static void fprint_action( struct rule *rule, const struct action *action, int depth, FILE *f )
130 {
131 int i;
132 if( action == NULL ) {
133 fprintf( f, "%*cUNIMP(ir); /* %s */\n", depth*8, ' ', rule->format );
134 } else {
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 );
141 } else {
142 fprintf( f, "uint32_t %s = ", rule->operands[i].name );
143 }
144 if( rule->operands[i].bit_shift == 0 ) {
145 fprintf( f, "(ir&0x%X)", (1<<(rule->operands[i].bit_count))-1 );
146 } else {
147 fprintf( f, "((ir>>%d)&0x%X)", rule->operands[i].bit_shift,
148 (1<<(rule->operands[i].bit_count))-1 );
149 }
150 if( rule->operands[i].left_shift != 0 ) {
151 fprintf( f, "<<%d", rule->operands[i].left_shift );
152 }
153 fprintf( f, "; " );
154 }
155 }
156 fputs( "\n", f );
157 if( action->text && action->text[0] != '\0' ) {
158 fprintf( f, "#line %d \"%s\"\n", action->lineno, action->filename );
159 fprint_indent( action->text, depth, f );
160 }
161 fprintf( f, "%*c}\n", depth*8, ' ' );
162 }
163 }
165 static void split_and_generate( struct ruleset *rules, const struct action *actions,
166 int ruleidx[], int rule_count, int input_mask,
167 int depth, FILE *f ) {
168 uint32_t mask;
169 int i,j;
171 if( rule_count == 0 ) {
172 fprintf( f, "%*cUNDEF(ir);\n", depth*8, ' ' );
173 } else if( rule_count == 1 ) {
174 fprint_action( rules->rules[ruleidx[0]], &actions[ruleidx[0]], depth, f );
175 } else {
177 mask = find_mask(rules, ruleidx, rule_count, input_mask);
178 if( mask == 0 ) { /* No matching mask? */
179 fprintf( stderr, "Error: unable to find a valid bitmask (%d rules, %08X input mask)\n", rule_count, input_mask );
180 dump_rulesubset( rules, ruleidx, rule_count, stderr );
181 return;
182 }
184 /* break up the rules into sub-sets, and process each sub-set.
185 * NB: We could do this in one pass at the cost of more complex
186 * data structures. For now though, this keeps it simple
187 */
188 int option_count = get_option_count_for_mask( mask );
189 uint32_t options[option_count];
190 int subruleidx[rule_count];
191 int subrule_count;
192 int mask_shift = get_bitshift_for_mask( mask );
193 int has_empty_options = 0;
194 get_option_values_for_mask( options, mask );
196 if( mask_shift == 0 ) {
197 fprintf( f, "%*cswitch( ir&0x%X ) {\n", depth*8, ' ', mask );
198 } else {
199 fprintf( f, "%*cswitch( (ir&0x%X) >> %d ) {\n", depth*8, ' ',
200 mask, mask_shift);
201 }
202 for( i=0; i<option_count; i++ ) {
203 subrule_count = 0;
204 for( j=0; j<rule_count; j++ ) {
205 int match = rules->rules[ruleidx[j]]->bits & mask;
206 if( match == options[i] ) {
207 subruleidx[subrule_count++] = ruleidx[j];
208 }
209 }
210 if( subrule_count == 0 ) {
211 has_empty_options = 1;
212 } else {
213 fprintf( f, "%*ccase 0x%X:\n", depth*8+4, ' ', options[i]>>mask_shift );
214 split_and_generate( rules, actions, subruleidx, subrule_count,
215 mask|input_mask, depth+1, f );
216 fprintf( f, "%*cbreak;\n", depth*8+8, ' ' );
217 }
218 }
219 if( has_empty_options ) {
220 fprintf( f, "%*cdefault:\n%*cUNDEF(ir);\n%*cbreak;\n",
221 depth*8+4, ' ', depth*8+8, ' ', depth*8 + 8, ' ' );
222 }
223 fprintf( f, "%*c}\n", depth*8, ' ' );
224 }
225 }
227 static int generate_decoder( struct ruleset *rules, actionfile_t af, FILE *out )
228 {
229 int ruleidx[rules->rule_count];
230 int i;
232 for( i=0; i<rules->rule_count; i++ ) {
233 ruleidx[i] = i;
234 }
236 actiontoken_t token = action_file_next(af);
237 while( token->symbol != END ) {
238 if( token->symbol == TEXT ) {
239 fprintf( out, "#line %d \"%s\"\n", token->lineno, token->filename );
240 fputs( token->text, out );
241 } else if( token->symbol == ERROR ) {
242 fprintf( stderr, "Error parsing action file" );
243 return -1;
244 } else {
245 split_and_generate( rules, token->actions, ruleidx, rules->rule_count, 0, 1, out );
246 }
247 token = action_file_next(af);
248 }
249 return 0;
250 }
252 static int generate_template( struct ruleset *rules, actionfile_t af, FILE *out )
253 {
254 int i;
256 actiontoken_t token = action_file_next(af);
257 while( token->symbol != END ) {
258 if( token->symbol == TEXT ) {
259 fputs( token->text, out );
260 } else if( token->symbol == ERROR ) {
261 fprintf( stderr, "Error parsing action file" );
262 return -1;
263 } else {
264 fputs( "%%\n", out );
265 for( i=0; i<rules->rule_count; i++ ) {
266 fprintf( out, "%s {: %s :}\n", rules->rules[i]->format,
267 token->actions[i].text == NULL ? "" : token->actions[i].text );
268 }
269 fputs( "%%\n", out );
270 }
271 token = action_file_next(af);
272 }
274 return 0;
275 }
278 int main( int argc, char *argv[] )
279 {
280 int opt;
282 /* Parse the command line */
283 while( (opt = getopt_long( argc, argv, option_list, longopts, NULL )) != -1 ) {
284 switch( opt ) {
285 case 't':
286 gen_mode = GEN_TEMPLATE;
287 break;
288 case 'o':
289 out_filename = optarg;
290 break;
291 case 'h':
292 usage();
293 exit(0);
294 }
295 }
296 if( optind < argc ) {
297 ins_filename = argv[optind++];
298 }
299 if( optind < argc ) {
300 act_filename = argv[optind++];
301 }
303 if( optind < argc || ins_filename == NULL || act_filename == NULL ) {
304 usage();
305 exit(1);
306 }
308 if( out_filename == NULL ) {
309 if( gen_mode == GEN_TEMPLATE ) {
310 out_filename = act_filename;
311 } else {
312 char tmp[strlen(act_filename)+1];
313 strcpy( tmp, act_filename);
314 char *c = strrchr( tmp, '.' );
315 if( c != NULL ) {
316 *c = '\0';
317 }
318 out_filename = g_strconcat( tmp, DEFAULT_OUT_EXT, NULL );
319 }
320 }
322 /* Open the files */
323 ins_file = fopen( ins_filename, "ro" );
324 if( ins_file == NULL ) {
325 fprintf( stderr, "Unable to open '%s' for reading (%s)\n", ins_filename, strerror(errno) );
326 exit(2);
327 }
329 /* Parse the input */
330 struct ruleset *rules = parse_ruleset_file( ins_file );
331 fclose( ins_file );
332 if( rules == NULL ) {
333 exit(5);
334 }
336 actionfile_t af = action_file_open( act_filename, rules );
337 if( af == NULL ) {
338 fprintf( stderr, "Unable to open '%s' for reading (%s)\n", act_filename, strerror(errno) );
339 exit(3);
340 }
343 /* Open the output file */
344 out_file = fopen( out_filename, "wo" );
345 if( out_file == NULL ) {
346 fprintf( stderr, "Unable to open '%s' for writing (%s)\n", out_filename, strerror(errno) );
347 exit(4);
348 }
350 switch( gen_mode ) {
351 case GEN_SOURCE:
352 if( generate_decoder( rules, af, out_file ) != 0 ) {
353 exit(7);
354 }
355 break;
356 case GEN_TEMPLATE:
357 if( generate_template( rules, af, out_file ) != 0 ) {
358 exit(7);
359 }
360 break;
361 }
363 action_file_close(af);
364 fclose( out_file );
365 return 0;
366 }
.