Search
lxdream.org :: lxdream/src/tools/gendec.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/tools/gendec.c
changeset 359:c588dce7ebde
next420:e6f43dec3cf0
author nkeynes
date Thu Aug 23 12:33:27 2007 +0000 (12 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 +0000
1.2 +++ b/src/tools/gendec.c Thu Aug 23 12:33:27 2007 +0000
1.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 appropriate
1.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 modify
1.13 + * it under the terms of the GNU General Public License as published by
1.14 + * the Free Software Foundation; either version 2 of the License, or
1.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 of
1.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.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 1
1.40 +#define GEN_TEMPLATE 2
1.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 rules
1.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 complex
1.283 + * data structures. For now though, this keeps it simple
1.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 +}
.