#!/usr/bin/perl -w # perl replacement of genmdesc.c for use when cross-compiling use strict; no locale; # must keep in sync with mini.h my @spec_names = qw(dest src1 src2 len clob); sub INST_DEST () {return 0;} sub INST_SRC1 () {return 1;} sub INST_SRC2 () {return 2;} sub INST_LEN () {return 3;} sub INST_CLOB () {return 4;} sub INST_MAX () {return 5;} # this must include all the #defines used in mini-ops.h my @defines = qw (__i386__ __x86_64__ __ppc__ __powerpc__ __arm__ __sparc__ sparc __s390__ s390 __ia64__ __alpha__ __mips__); my %table =(); my @opcodes = (); sub load_opcodes { my ($srcdir, $arch) = @_; my $opcodes_def = "$srcdir/../cil/opcode.def"; my $i = 0; my $arch_found = 0; open (OPS, "$opcodes_def") || die "Cannot open $opcodes_def: $!"; while () { next unless /OPDEF\s*\(\s*(\S+?)\s*,\s*"(.*?)"/; my ($sym, $name) = ($1, $2); push @opcodes, [$sym, $name]; $table{$name} = {num => $i, name => $name}; $i++; } close (OPS); my $cpp = "cpp -undef "; foreach (@defines) { $cpp .= " -U$_"; $arch_found = 1 if $arch eq $_; } die "$arch arch is not supported.\n" unless $arch_found; $cpp .= " -D$arch $srcdir/mini-ops.h|"; #print "Running: $cpp\n"; open (OPS, $cpp) || die "Cannot execute cpp: $!"; while () { next unless /MINI_OP\s*\(\s*(\S+?)\s*,\s*"(.*?)"/; my ($sym, $name) = ($1, $2); push @opcodes, [$sym, $name]; $table{$name} = {num => $i, name => $name}; $i++; } close (OPS); } sub load_file { my ($name) = @_; my $line = 0; my $comment = ""; open (DESC, $name) || die "Cannot open $name: $!"; while () { $line++; next if /^\s*$/; if (/^\s*(#.*)?$/) { $comment .= "$1\n"; next; } my @values = split (/\s+/); next unless ($values [0] =~ /(\S+?):/); my $name = $1; my $desc = $table {$name}; shift @values; die "Invalid opcode $name at line $line\n" unless defined $desc; die "Duplicated opcode $name at line $line\n" if $desc->{"desc"}; $desc->{"desc"} = $_; $desc->{"comment"} = $comment; $desc->{"spec"} = {}; $comment = ""; #print "values for $name: " . join (' ', @values) . " num: " . int(@values), "\n"; for my $val (@values) { if ($val =~ /(\S+):(.*)/) { $desc->{"spec"}->{$1} = $2; } } } close (DESC); } sub build_spec { my ($spec) = shift; my %spec = %{$spec}; my @vals = (); foreach (@spec_names) { my $val = $spec->{$_}; if (defined $val) { push @vals, $val; } else { push @vals, undef; } } #print "vals: " . join (' ', @vals) . "\n"; my $res = ""; for (my $i = 0; $i < @vals; ++$i) { if (defined $vals [$i]) { if ($i == INST_LEN) { $res .= sprintf ("\\x%x\" \"", +$vals [$i]); } else { if ($vals [$i] =~ /^[a-zA-Z0-9]$/) { $res .= $vals [$i]; } else { $res .= sprintf ("\\x%x\" \"", $vals [$i]); } } } else { $res .= "\\x0\" \""; } } return $res; } sub build_table { my ($fname, $name) = @_; my $i; open (OUT, ">$fname") || die "Cannot open file $fname: $!"; print OUT "/* File automatically generated by genmdesc, don't change */\n\n"; print OUT "const char * const $name [OP_LAST] = {\n"; for ($i = 0; $i < @opcodes; ++$i) { my $name = $opcodes [$i]->[1]; my $desc = $table {$name}; my $spec = $desc->{"spec"}; if (defined $spec) { print OUT "\t\""; print OUT build_spec ($spec); print OUT "\",\t/* $name */\n"; } else { print OUT "\tNULL,\t/* $name */\n"; } } print OUT "};\n\n"; close (OUT); } sub usage { die "genmdesc.pl arch srcdir desc output name\n"; } my $arch = shift || usage (); my $srcdir = shift || usage (); my $file = shift || usage (); my $output = shift || usage (); my $name = shift || usage (); load_opcodes ($srcdir, $arch); load_file ($file); build_table ($output, $name);