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