#!/s/std/bin/perl
if (@ARGV != 2) {&ERROR();}

# open def file for input
$defin = $ARGV[0];
open(DEFIN, $defin) || die "Cannot open def input file: $defin\n";

# open the def output
$defout = $ARGV[1];
open(DEFOUT, ">$defout") || die "Cannot open def output: $defout\n";

$print_on = 0;
$cmov = 0;
$fcmov = 0;
$if = 0;

#print DEFOUT "#define ARGS sequencer *seq, static_inst_t *s, dynamic_isnt_t *d\n";
#print DEFOUT "#define LINK\n";
#print DEFOUT "#define OFFSET\n";

while (<DEFIN>)
{
    if (/^DEFINST/) {
	$print_on = 0;
	print DEFOUT "  break;\n\n";
	$fcmov = 0;
	$cmov = 0;
	$store = 0;
    }

    if (/#if/ || /#else/ || /#endif/) {
	print DEFOUT;
	next;
    }

    if (/#define\s+(\w+)_IMPL/) {
	$if = 0;
	$print_on = 1;
#	print DEFOUT "void ",$1,"_EXECUTE(ARGS) ";
	print DEFOUT "case ",$1,": ";
	if (/FCMOV/) { $fcmov = 1;
	} else {
	    if (/CMOV/) { $cmov = 1; } 
	}
	if (/ ST/) { $store = 1; }
    } else {
	if ($print_on) {
#	    s/^  //g;
	    s/\s*\\//g;
	    if ($store) { 
		s/GPR\(RA\)/SOURCE2/g; 
		s/FPR_Q\(RA\)/SOURCE2/g;
	    }
	    else { 
		s/GPR\(RA\)/SOURCE1/g; 
		s/FPR_Q\(RA\)/SOURCE1/g;
	    }
#	    s/.*SPECIAL_MEMORY_READ.*/  WRITE_DEST\(SPECIAL_RD\(SOURCE1\)\);/g;
#           s/.*SPECIAL_MEMORY_WRITE.*/  SPECIAL_WR\(SOURCE1, SOURCE2\);/g;
	    s/FPR\(RA\)/SOURCE1_F/g;
	    s/GPR\(RB\)/SOURCE2/g;
	    s/FPR_Q\(RB\)/SOURCE2/g;
	    s/FPR\(RB\)/SOURCE2_F/g;
	    s/READ.*\)/MEMORY_READ/g;
	    s/WRITE.*\((\w+),.*\)/MEMORY_WRITE\($1\)/g;
	    s/WRITE.*\(\(\w+\)(\w+),.*\)/MEMORY_WRITE\($1\)/g;
	    s/DECLARE_FAULT/ASSERT_FAULT/g;
	    s/SET_GPR\(RA, CPC \+ 4\)\;//g;
	    s/SET_GPR\(R[AC], /WRITE_DEST\(/g;
	    s/SET_FPCR\(/WRITE_DEST\(/g;
	    s/SET_FPR\(R[AC], /WRITE_DEST_F\(/g;
	    s/SET_FPR_Q\(R[AC], /WRITE_DEST\(/g;
	    s/CPC .* 4/OFFSET/g;
	    s/IMM/OFFSET/g;
	    s/SEXT\(OFS\)/OFFSET/g;
	    s/SEXT32\(65536 \* OFS\)/OFFSET/g;
	    s/OFS/OFFSET/g;
	    s/.*UNIQ.*/  WRITE_DEST\(SOURCE1\);/g;
	    s/SYSCALL.*\;/_SYSCALL_/g;
	    s/FPCR/SOURCE1/g;

	    if (/if/) { $if = 1; }		

	    if (($if == 0) && (/NPC/) && !(/MFPR/)) {
		print DEFOUT "    LINK;\n";
	    }

	    if ($cmov && /}/) {
	        print DEFOUT "  else\n    WRITE_DEST(OLD_DEST);\n";
	    }
					  
	    if ($fcmov && /}/) {
	        print DEFOUT "  else\n    WRITE_DEST_F(OLD_DEST_F);\n";
	    }
					  
	    if ((/TPC/) || (/WRITE_DEST\(0x/) ||
		((/_fault/) && !((/md_fault_unimpl/) || (/md_fault_div/)|| 
				 (/md_fault_invalid/)))) {
		# do nothing
	    } else {
		if (/\S/) {	# don't print empty lines in functions
		    print DEFOUT;
		}
	    }
	}
    }
}

close(DEFOUT);
close(DEFIN);


# if the arguments aren't correctly formatted, print an error
# indicating how to use this program
sub ERROR {
    print STDERR 
	"Usage: machine_munge.pl <def input> <def output>\n";

  exit -1; 
}
