#!/usr/bin/perl
$stem = "$ARGV[0]";
die "${stem}prts.txt is missing" unless -f "${stem}prts.txt";
die "${stem}pins.txt is missing" unless -f "${stem}pins.txt";
#$oldway = 1;
#
# Map a signal name from Eagle to something legal
# in CUPL.
#
$renamed = 0;
%eagle2pld = ();
sub eagle2pld {
local($eagle) = @_;
return $eagle2pld{$eagle} if defined $eagle2pld{$eagle};
local($signal) = $eagle;
# Fix up signal name.
$signal =~ s/^[\+]//;
$signal =~ s/_$/_low/ if $oldway;
$signal =~ s/_$/_l/;
$signal =~ s/_low$/_l/ unless $oldway;
$signal =~ s/[.]/_/;
$signal =~ s/[\(]/_lp_/g;
$signal =~ s/[\)]/_rp_/g;
$signal =~ s/[\[]/_lb_/g;
$signal =~ s/[\]]/_rb_/g;
$signal =~ s/[\\]/_low/g if $oldway;
$signal =~ s/_$/_low/ if $oldway; # BUGBUG
$signal =~ s/[\\]/_l/g;
$signal =~ s/!([^!]*)/\1_l/g if $stem eq 'tc08';
$signal =~ s/^!([^!]*)/\1_low/g if $oldway;
$signal =~ s/^!(.*)/\1_l/g;
$signal =~ s/[\+]/_or_/g;
$signal =~ s/[\*]/_and_/g unless $signal =~ /^[*]/;
$signal =~ s/[\-@\/]/_/g;
$signal =~ s/[\$]/_t_/;
$signal =~ s/^(n_t_\d+)$/\1x/;
# redundant?
$signal =~ s/\\$/_l/;
$signal =~ s/__+/_/g;
$signal =~ s/^_//;
$signal =~ s/_$//;
$signal = 'and_h' if $signal eq 'and';
$signal = 'break_h' if $signal eq 'break';
$signal = 'end_h' if $signal eq 'end';
$signal =~ s/^/n/ if $signal =~ /^\d/;
$signal = "1'b1" if $signal eq "vcc";
$signal = "1'b0" if $signal eq "gnd";
# CUPL symbol names are limited to about 60 characters.
if (length($signal) > 60) {
&qcode("/* Converted name $signal is too long. */\n");
$signal = "renamed" . $renamed++;
&qcode("/* ... using name $signal instead. */\n");
}
$eagle2pld{$eagle} = $signal;
#die $signal if $signal =~ /_l$/;
return $signal;
}
#
# Parts to kludge the master clock into.
%clocked = (
"g888", 1,
"m206", 1,
"m207", 1,
"m216", 1,
"m220", 1,
"m228", 1,
"m302", 1,
"m307", 1,
"m310", 1,
"m401", 1,
"m452", 1,
"m602", 1,
"m700", 1,
"m706", 1,
"m707", 1,
);
#
# Instantiation names must not equal a signal name.
# Instatiation names range from "a01" to "f32", etc.
# Most don't look like signals, but "d00"-"d11" do.
%hat = (
"c01", "_",
"d00", "_",
"d01", "_",
"d02", "_",
"d03", "_",
"d04", "_",
"d05", "_",
"d06", "_",
"d07", "_",
"d08", "_",
"d09", "_",
"d10", "_",
"d11", "_",
);
#
# Don't instantiate difficult but not interesting parts of the model.
%elide = (
"a607", 1,
"g821", 1,
"g826", 1,
"g792", 1,
# "m040", 1,
"m401/m405/m501", 1,
"m701", 1,
"m703", 1,
"m704", 1,
"m705", 1,
"m708", 1,
"m709", 1,
"m710", 1,
"m714", 1,
"m715", 1,
"m716", 1,
"m720", 1,
# "m903", 1, # Should probably be a connector
);
#
# Read the Part List. Remember the part's device/value,
# and whether it is a connector.
# Also assemble a list of devices used.
#
%partlist = %connector = ();
%used = ();
open(INPUT, "${stem}prts.txt") || die "${stem}prts.txt (partlist): $!";
while () {
last if /^Part\s/;
}
while () {
y/A-Z/a-z/;
if (/^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/) {
($part, $value, $device, $pack, $lib, $foo) = ($1, $2, $3, $4, $5, $6);
($device, $pack, $lib) = ($pack, $lib, $foo) if $device =~ /[%]/;
} else {
next unless /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/;
($part, $value, $device, $pack, $lib) = ($1, $2, $3, $4, $5);
}
if (($lib eq "rcl") || $device eq "c-us") {
# Value is set, but not needed. Also, numeric part of the
# device name encodes the package size, which is not needed.
$device =~ s/\d.*//;
$value = $device;
}
$part =~ s/-/_/g;
$value =~ s/-/_/g;
$device =~ s/-/_/g;
# next if $value =~ /^sw_dip/;
$device = $value if $value =~ /^ma\d+_\d/;
next unless $part =~ /\w+/;
next unless $value =~ /\w+/;
next unless $device =~ /\w+/;
$device =~ s/x$//;
$device =~ s/-array$//;
$value = 'cpol_use' if $device =~ /^cpol/;
$value = $device if $device eq 'r';
$value = $device if $device =~ /^r-us/;
# warn "info: $value ne $device\n" unless $value eq $device;
next if $value eq "spare";
$value =~ s/^74s/74/;
$value =~ s/^74ls/74/;
$value =~ s/^lm(.*)n/lm\1/;
$value =~ s/^74(.*)n/sn74\1/;
$value =~ s/^(\d*74\d*)$/sn\1/;
$value =~ s/^(\d*88\d*)$/ds\1/;
$value =~ s/^74(.*)/sn74\1n/;
$partlist{$part} = $value;
$connector{$part} = ($pack =~ /^con-/);
$connector{$part} = 1 if $pack =~ /^wirepad$/;
$connector{$part} = 1 if $pack =~ /^do35-/;
$connector{$part} = 1 if $pack =~ /^to5$/;
$connector{$part} = 1 if $device =~ /^edg/;
$connector{$part} = 1 if $pack =~ /^edg/;
$connector{$part} = 1 if $device =~ /^j5mm/;
$connector{$part} = 1 if $device =~ /^j10mm/;
$connector{$part} = 1 if $device =~ /^jumper4/;
$connector{$part} = 1 if $device =~ /^dec40pin/;
$connector{$part} = 1 if $device =~ /^b3f/;
$connector{$part} = 1 if $device =~ /^0r2/;
$connector{$part} = 1 if $device =~ /^275p$/;
$connector{$part} = 1 if $device =~ /^g09r/;
$connector{$part} = 1 if $device =~ /^74123/; # BUGBUG vrs kludge
$connector{$part} = 1 if $device =~ /^9601/; # BUGBUG vrs kludge
$connector{$part} = 1 if $device =~ /^w/; # BUGBUG vrs kludge
$connector{$part} = 1 if $device =~ /^empty/;
$connector{$part} = 1 if $device =~ /^m903/;
$connector{$part} = 1 if $device =~ /^m916/;
$used{$value} = 1;
}
#
# Scan the pin file, keeping track of which pin directions
# are used for which signals. As we go, build a string $code,
# containing the Verilog instantiations of each part.
#
%in = %out = %con = ();
$code = "";
open(INPUT, "${stem}pins.txt") || die "${stem}pins.txt (pinlist): $!";
while () {
last if /^Part/;
}
undef $part;
while () {
chop;
s/\r$//;
y/A-Z/a-z/;
if (/^$/) {
next unless defined $part;
$code .= ");\n" unless $connector{$part};
# Elide the stuff we were asked to elide.
$code .= "*/\n" if $elide{$partlist{$p}};
undef $part;
next;
}
if (/^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/) {
# Some parts are in the board, but not the schematic.
# (Ignore them).
($p, $pad, $pin, $dir, $signal) = ($1, $2, $3, $4, $5);
$p =~ s/-/_/g;
next unless defined $partlist{$p};
$part = $p;
undef %pin;
# Elide the stuff we were asked to elide.
$code .= "/*\n" if $elide{$partlist{$p}};
# Instantiation names must not equal a signal name.
$code .= "$partlist{$p} $p$hat{$p}(" unless $connector{$part};
$tline = 0;
# Special kludge here to add ".clk(clk), " for Kyle.
if ($clocked{$partlist{$p}}) {
$code .= ".clk(clk), ";
$tline++;
}
$comma = 0;
$lcount = 0;
} else {
die "$_" unless /^\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/;
($pad, $pin, $dir, $signal) = ($1, $2, $3, $4);
next unless $part;
}
$signal = &eagle2pld($signal); # Fix up signal name.
next if $signal eq '***';
if ($connector{$part}) {
# Just make a note of signals that go to a connector pin.
$con{$signal} = 1 unless $dir eq 'pwr';
next;
}
# Fix numeric pad names.
$pad =~ s/^/p/ if $pad =~ /^\d/;
# Fix numeric pin names.
$pin =~ s/^/y/ if $pin =~ /^\d/;
# Kludge to use pin name (but make it unique).
$pin{$pin} = 0 unless defined $pin{$pin};
# Kludge for distant 'g' and 'a' pins on sn74240.
$pin{$pin} = !$pin{$pin} if $partlist{$part} =~ /sn7424./ && $pin eq 'g';
$pin{$pin} = !$pin{$pin} if $partlist{$part} =~ /sn7424./ && $pin =~ /^a/;
# $pad = "${pin}_$pin{$pin}";
# $pad = $pin unless $pin{$pin};
$pin{$pin}++;
$pad =~ s/[\\]/_not/;
# Ignore passive and power pins.
# Direction may be NC | IN | OUT | I/O | OC | HIZ | SUP | PAS | PWR | SUP
$dir = 'oc' if ($dir eq 'pas') && ($partlist{$p} eq 'm506');
next if $dir eq 'pas';
next if $dir eq 'pwr';
# Ignore unconnected pins.
next if $signal =~ /^[\*]/;
next if $signal =~ /^nc$/;
# Make note of which signals are read and written.
$in{$signal} = 1 if $dir eq 'in';
$out{$signal} = 1 if $dir eq 'out';
$out{$signal} = 1 if $dir eq 'i/o';
$out{$signal} = 1 if $dir eq 'io';
$oc{$signal} = 1 if $dir eq 'oc';
$out{$signal} = 1 if $dir eq 'oc';
$out{$signal} = 1 if $dir eq 'hiz';
$signals{$signal} = 1;
next if $connector{$p};
$code .= ", " if $comma; $comma = 1;
if ($tline == 4) {
$code .= "\n\t"; $tline = 0;
}
$pad =~ y/a-z/A-Z/;
$code .= ".$pad($signal)";
$tline++;
}
#
# Now we know how each pin was used, which is enough to emit the declarations.
# (This outputs the interface signals alphabetically.)
#
@foo = sort keys %con;
printf "module $stem (clk, ";
$comma = 0;
foreach $signal (@foo) {
next if $signal =~ /^1/;
print ", " if $comma;
print "$signal";
$comma = 1;
$tline++;
next unless $tline > 8;
print ",\n\t";
$tline = $comma = 0;
}
printf ");\n";
printf "input clk;\n";
foreach $signal (@foo) {
next if $signal =~ /^1/;
$direction = 'input' if $in{$signal};
$direction = 'output' if $out{$signal};
$direction = 'inout' if $in{$signal} && $out{$signal};
print "$direction $signal;\n";
}
printf "\n";
#
# Output wire declarations for everything in %signal
# #that isn't also in %con.
#
@foo = sort keys %signals;
foreach $signal (@foo) {
next if $signal =~ /^1/;
# next if defined $con{$signal};
if ($oc{$signal}) {
print "wire $signal = 1'b1;\n";
} else {
print "wire $signal;\n";
}
}
printf "\n";
#
# Now emit the code, and wrap things up.
#
print $code;
print "\n/* lint_on */\n";
print "endmodule\n";
exit 0;