#!/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;