filename | src/tools/gendec.c |
changeset | 359:c588dce7ebde |
next | 420:e6f43dec3cf0 |
author | nkeynes |
date | Thu Aug 23 12:33:27 2007 +0000 (14 years ago) |
permissions | -rw-r--r-- |
last change | Commit decoder generator Translator work in progress Fix mac.l, mac.w in emu core |
file | annotate | diff | log | raw |
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +00001.2 +++ b/src/tools/gendec.c Thu Aug 23 12:33:27 2007 +00001.3 @@ -0,0 +1,353 @@1.4 +/**1.5 + * $Id: gendec.c,v 1.1 2007-08-23 12:33:27 nkeynes Exp $1.6 + *1.7 + * Parse the instruction and action files and generate an appropriate1.8 + * instruction decoder.1.9 + *1.10 + * Copyright (c) 2005 Nathan Keynes.1.11 + *1.12 + * This program is free software; you can redistribute it and/or modify1.13 + * it under the terms of the GNU General Public License as published by1.14 + * the Free Software Foundation; either version 2 of the License, or1.15 + * (at your option) any later version.1.16 + *1.17 + * This program is distributed in the hope that it will be useful,1.18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of1.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1.20 + * GNU General Public License for more details.1.21 + */1.22 +1.23 +#include <stdio.h>1.24 +#include <stdlib.h>1.25 +#include <string.h>1.26 +#include <getopt.h>1.27 +#include <errno.h>1.28 +#include <ctype.h>1.29 +#include <glib/gstrfuncs.h>1.30 +#include <assert.h>1.31 +#include "tools/gendec.h"1.32 +1.33 +#define DEFAULT_OUT_EXT ".c"1.34 +1.35 +const char *ins_filename = NULL;1.36 +const char *act_filename = NULL;1.37 +const char *out_filename = NULL;1.38 +1.39 +#define GEN_SOURCE 11.40 +#define GEN_TEMPLATE 21.41 +1.42 +FILE *ins_file, *act_file, *out_file;1.43 +1.44 +char *option_list = "tmho:";1.45 +int gen_mode = GEN_SOURCE;1.46 +struct option longopts[1] = { { NULL, 0, 0, 0 } };1.47 +1.48 +void usage() {1.49 + printf( "gendec <instruction-file> <action-file> [ -o <output-file> ]\n" );1.50 +}1.51 +1.52 +int main( int argc, char *argv[] )1.53 +{1.54 + int opt, i;1.55 +1.56 + /* Parse the command line */1.57 + while( (opt = getopt_long( argc, argv, option_list, longopts, NULL )) != -1 ) {1.58 + switch( opt ) {1.59 + case 't':1.60 + gen_mode = GEN_TEMPLATE;1.61 + break;1.62 + case 'o':1.63 + out_filename = optarg;1.64 + break;1.65 + case 'h':1.66 + usage();1.67 + exit(0);1.68 + }1.69 + }1.70 + if( optind < argc ) {1.71 + ins_filename = argv[optind++];1.72 + }1.73 + if( optind < argc ) {1.74 + act_filename = argv[optind++];1.75 + }1.76 +1.77 + if( optind < argc || ins_filename == NULL || act_filename == NULL ) {1.78 + usage();1.79 + exit(1);1.80 + }1.81 +1.82 + if( out_filename == NULL ) {1.83 + if( gen_mode == GEN_TEMPLATE ) {1.84 + out_filename = act_filename;1.85 + } else {1.86 + char tmp[strlen(act_filename)+1];1.87 + strcpy( tmp, act_filename);1.88 + char *c = strrchr( tmp, '.' );1.89 + if( c != NULL ) {1.90 + *c = '\0';1.91 + }1.92 + out_filename = g_strconcat( tmp, DEFAULT_OUT_EXT );1.93 + }1.94 + }1.95 +1.96 + /* Open the files */1.97 + ins_file = fopen( ins_filename, "ro" );1.98 + if( ins_file == NULL ) {1.99 + fprintf( stderr, "Unable to open '%s' for reading (%s)\n", ins_filename, strerror(errno) );1.100 + exit(2);1.101 + }1.102 +1.103 + act_file = fopen( act_filename, "ro" );1.104 + if( act_file == NULL ) {1.105 + fprintf( stderr, "Unable to open '%s' for reading (%s)\n", act_filename, strerror(errno) );1.106 + exit(3);1.107 + }1.108 +1.109 + /* Parse the input */1.110 + struct ruleset *rules = parse_ruleset_file( ins_file );1.111 + fclose( ins_file );1.112 + if( rules == NULL ) {1.113 + exit(5);1.114 + }1.115 +1.116 + struct actionset *actions = parse_action_file( rules, act_file );1.117 + fclose( act_file );1.118 + if( actions == NULL ) {1.119 + exit(6);1.120 + }1.121 +1.122 + /* Finally write out the results */1.123 + out_file = fopen( out_filename, "wo" );1.124 + if( out_file == NULL ) {1.125 + fprintf( stderr, "Unable to open '%s' for writing (%s)\n", out_filename, strerror(errno) );1.126 + exit(4);1.127 + }1.128 +1.129 + switch( gen_mode ) {1.130 + case GEN_SOURCE:1.131 + if( generate_decoder( rules, actions, out_file ) != 0 ) {1.132 + exit(7);1.133 + }1.134 + break;1.135 + case GEN_TEMPLATE:1.136 + if( generate_template( rules, actions, out_file ) != 0 ) {1.137 + exit(7);1.138 + }1.139 + break;1.140 + }1.141 + fclose( out_file );1.142 + return 0;1.143 +}1.144 +1.145 +/**1.146 + * Find a mask that can be used to split up the given rules1.147 + */1.148 +uint32_t find_mask( struct ruleset *rules, int ruleidx[], int rule_count,1.149 + uint32_t input_mask )1.150 +{1.151 + int i;1.152 + uint32_t mask = rules->rules[ruleidx[0]]->mask;1.153 +1.154 + for( i=1; i<rule_count; i++ ) {1.155 + mask = mask & rules->rules[ruleidx[i]]->mask;1.156 + }1.157 +1.158 + assert( (mask & input_mask) == input_mask ); /* input_mask should always be included in the mask */1.159 +1.160 + return mask & (~input_mask); /* but we don't want to see the input mask again */1.161 +}1.162 +1.163 +int get_option_count_for_mask( uint32_t mask ) {1.164 + int count = 0;1.165 +1.166 + while( mask ) {1.167 + if( mask&1 )1.168 + count++;1.169 + mask >>= 1;1.170 + }1.171 + return 1<<count;1.172 +}1.173 +1.174 +int get_bitshift_for_mask( uint32_t mask ) {1.175 + int shift = 0;1.176 + while( mask && !(mask&1) ) {1.177 + shift++;1.178 + mask >>= 1;1.179 + }1.180 + return shift;1.181 +}1.182 +1.183 +void get_option_values_for_mask( uint32_t *options,1.184 + uint32_t mask )1.185 +{1.186 + /* This could be a lot smarter. But it's not */1.187 + int i;1.188 + *options = 0;1.189 + for( i=1; i<=mask; i++ ) {1.190 + if( (i & mask) > *options ) {1.191 + options++;1.192 + *options = (i&mask);1.193 + }1.194 + }1.195 +}1.196 +1.197 +fprint_indent( char *action, int depth, FILE *f )1.198 +{1.199 + int spaces = 0, needed = depth*8, i;1.200 + char *text = action;1.201 +1.202 + /* Determine number of spaces in first line of input */1.203 + for( i=0; isspace(action[i]); i++ ) {1.204 + if( action[i] == '\n' ) {1.205 + spaces = 0;1.206 + text = &action[i+1];1.207 + } else {1.208 + spaces++;1.209 + }1.210 + }1.211 +1.212 + needed -= spaces;1.213 + fprintf( f, "%*c", needed, ' ' );1.214 + for( i=0; text[i] != '\0'; i++ ) {1.215 + fputc( text[i], f );1.216 + if( text[i] == '\n' && text[i+1] != '\0' ) {1.217 + fprintf( f, "%*c", needed, ' ' );1.218 + }1.219 + }1.220 + if( text[i-1] != '\n' ) {1.221 + fprintf( f, "\n" );1.222 + }1.223 +}1.224 +1.225 +fprint_action( struct rule *rule, char *action, int depth, FILE *f )1.226 +{1.227 + int i;1.228 + char tmp[64];1.229 + if( action == NULL ) {1.230 + fprintf( f, "%*cUNIMP(ir); /* %s */\n", depth*8, ' ', rule->format );1.231 + } else {1.232 + fprintf( f, "%*c{ /* %s */", depth*8, ' ', rule->format );1.233 + if( rule->operand_count != 0 ) {1.234 + fprintf( f, "\n%*c", depth*8, ' ' );1.235 + for( i=0; i<rule->operand_count; i++ ) {1.236 + if( rule->operands[i].is_signed ) {1.237 + fprintf( f, "int32_t %s = SIGNEXT%d", rule->operands[i].name, rule->operands[i].bit_count );1.238 + } else {1.239 + fprintf( f, "uint32_t %s = ", rule->operands[i].name );1.240 + }1.241 + if( rule->operands[i].bit_shift == 0 ) {1.242 + fprintf( f, "(ir&0x%X)", (1<<(rule->operands[i].bit_count))-1 );1.243 + } else {1.244 + fprintf( f, "((ir>>%d)&0x%X)", rule->operands[i].bit_shift,1.245 + (1<<(rule->operands[i].bit_count))-1 );1.246 + }1.247 + if( rule->operands[i].left_shift != 0 ) {1.248 + fprintf( f, "<<%d", rule->operands[i].left_shift );1.249 + }1.250 + fprintf( f, "; " );1.251 + }1.252 + }1.253 + fputs( "\n", f );1.254 + if( action[0] != '\0' ) {1.255 + fprint_indent( action, depth, f );1.256 + }1.257 + fprintf( f, "%*c}\n", depth*8, ' ' );1.258 + }1.259 +}1.260 +1.261 +int split_and_generate( struct ruleset *rules, struct actionset *actions,1.262 + int ruleidx[], int rule_count, int input_mask,1.263 + int depth, FILE *f ) {1.264 + char tmp[64];1.265 + uint32_t mask;1.266 + int i,j;1.267 +1.268 + if( rule_count == 0 ) {1.269 + fprintf( f, "%*cUNDEF(ir);\n", depth*8, ' ' );1.270 + } else if( rule_count == 1 ) {1.271 + fprint_action( rules->rules[ruleidx[0]], actions->actions[ruleidx[0]], depth, f );1.272 + } else {1.273 +1.274 + mask = find_mask(rules, ruleidx, rule_count, input_mask);1.275 + if( mask == 0 ) { /* No matching mask? */1.276 + fprintf( stderr, "Error: unable to find a valid bitmask (%d rules, %08X input mask)\n", rule_count, input_mask );1.277 + dump_rulesubset( rules, ruleidx, rule_count, stderr );1.278 + return -1;1.279 + }1.280 +1.281 + /* break up the rules into sub-sets, and process each sub-set.1.282 + * NB: We could do this in one pass at the cost of more complex1.283 + * data structures. For now though, this keeps it simple1.284 + */1.285 + int option_count = get_option_count_for_mask( mask );1.286 + uint32_t options[option_count];1.287 + int subruleidx[rule_count];1.288 + int subrule_count;1.289 + int mask_shift = get_bitshift_for_mask( mask );1.290 + int has_empty_options = 0;1.291 + get_option_values_for_mask( options, mask );1.292 +1.293 + if( mask_shift == 0 ) {1.294 + fprintf( f, "%*cswitch( ir&0x%X ) {\n", depth*8, ' ', mask );1.295 + } else {1.296 + fprintf( f, "%*cswitch( (ir&0x%X) >> %d ) {\n", depth*8, ' ',1.297 + mask, mask_shift);1.298 + }1.299 + for( i=0; i<option_count; i++ ) {1.300 + subrule_count = 0;1.301 + for( j=0; j<rule_count; j++ ) {1.302 + int match = rules->rules[ruleidx[j]]->bits & mask;1.303 + if( match == options[i] ) {1.304 + subruleidx[subrule_count++] = ruleidx[j];1.305 + }1.306 + }1.307 + if( subrule_count == 0 ) {1.308 + has_empty_options = 1;1.309 + } else {1.310 + fprintf( f, "%*ccase 0x%X:\n", depth*8+4, ' ', options[i]>>mask_shift );1.311 + split_and_generate( rules, actions, subruleidx, subrule_count,1.312 + mask|input_mask, depth+1, f );1.313 + fprintf( f, "%*cbreak;\n", depth*8+8, ' ' );1.314 + }1.315 + }1.316 + if( has_empty_options ) {1.317 + fprintf( f, "%*cdefault:\n%*cUNDEF();\n%*cbreak;\n",1.318 + depth*8+4, ' ', depth*8+8, ' ', depth*8 + 8, ' ' );1.319 + }1.320 + fprintf( f, "%*c}\n", depth*8, ' ' );1.321 + }1.322 +}1.323 +1.324 +int generate_decoder( struct ruleset *rules, struct actionset *actions, FILE *f )1.325 +{1.326 + int ruleidx[rules->rule_count];1.327 + int i;1.328 +1.329 + for( i=0; i<rules->rule_count; i++ ) {1.330 + ruleidx[i] = i;1.331 + }1.332 +1.333 + fputs( actions->pretext, f );1.334 +1.335 + split_and_generate( rules, actions, ruleidx, rules->rule_count, 0, 1, f );1.336 +1.337 + fputs( actions->posttext, f );1.338 +1.339 + return 0;1.340 +}1.341 +1.342 +int generate_template( struct ruleset *rules, struct actionset *actions, FILE *f )1.343 +{1.344 + int i;1.345 + fputs( actions->pretext, f );1.346 + fputs( "%%\n", f );1.347 +1.348 + for( i=0; i<rules->rule_count; i++ ) {1.349 + fprintf( f, "%s {: %s :}\n", rules->rules[i]->format,1.350 + actions->actions[i] == NULL ? "" : actions->actions[i] );1.351 + }1.352 + fputs( "%%\n", f );1.353 + fputs( actions->posttext, f );1.354 +1.355 + return 0;1.356 +}
.