#!/usr/bin/perl # Perl script to read the partlist, pinlist and netlist from Eagle and # output Verilog to instantiate the parts. @pins = ("a","b","c","d","e","f","h","j","k","l","m","n","p","r","s","t","u","v"); # Read the partlist. %partlist = (); open(INPUT, "pdp8i.prt") || die "pdp8i.prt: $!"; while () { last if /^Part\s/; } while () { y/A-Z/a-z/; next unless /^(\S+)\s+(\S+)\s+(\S+)/; ($part, $value, $device) = ($1, $2, $3); $device =~ s/x$//; $device =~ s/-array$//; #warn "$value ne $device" unless $value eq $device; $value =~ s:.*/::; $partlist{$part} = $value; } # Munge an Eagle name into a valid Verilog name. sub sigfix { #print "$signal: "; $signal =~ s/^\+/s/; $signal =~ s/^\-/m/; $signal =~ s/^/n/ if $signal =~ /^[^a-z]/; $signal = "1'b1" if $signal eq 'vcc'; $signal = "1'b0" if $signal eq 'gnd'; $signal = "1'b1" if $signal =~ /^s3v.*/; $signal =~ s/^[\+]//; $signal =~ s/[\+]$/_plus/; $signal =~ s/[\+]/_or_/g; $signal =~ s/[\-@\/]/_/g; $signal =~ s/[\$\(\)]/__/g; $signal =~ s/\\$/_l/; $signal =~ s/\\/_bar/g; $signal = 'and_h' if $signal eq 'and'; $signal = 'end_h' if $signal eq 'end'; #print "$signal\n"; } # Read the pinlist, acquiring a list of the signals # and their directions. %ignore = ("m6v", 1, "m30v", 1, "m36v", 1); print "module pdp8i(\n"; open(INPUT, "pdp8i.pin") || die "pdp8i.pin: $!"; while () { last if /^Part/; } while () { chop; s/\r$//; y/A-Z/a-z/; if (s/^(\S+)//) { $part = $1; $parts{$part} = 1; $dev = $partlist{$part}; print "\t$list\n" if $list; $list = ""; } ($foo, $pad, $pin, $dir, $signal, $foo) = split(/\s+/, $_); next unless defined $signal; next if $signal eq "***"; next if $dir eq "pwr"; # ignore power pads *func = eval "*elide_$dev"; next if defined &func; # Skip pads if no code for device &sigfix; $signal{"$part$pad"} = $signal; next if $signal eq "1'b1"; # Skip vcc on I/O connector next if $signal eq "m15v"; # Skip -15v on I/O connector next if $signal eq "1'b0"; # Skip gnd on I/O connector $nets{$signal} = 1; $direction{"$part$pad"} = $dir; #print "$signal: $dir\n" if $signal =~ /^in00/; next if $ignore{$signal}; # Skip it if blacklisted if ($dir eq "out") { $out{$signal} = 1; } elsif ($dir eq "oc") { warn "Mixed 'out' and 'wc' on $signal; converted 'out' to 'oc\n" if (!defined $wand{$signal}) && defined $out{$signal}; $out{$signal} = 1; $wand{$signal} = 1; } elsif ($dir eq "pas") { # Just assume the passive is actually a pull-up. $wand{$signal} = 1; } elsif ($dir eq "in") { $in{$signal} = 1; } elsif ($dir eq "i/o") { next if $io{$signal}; # Skip it if seen before $io{$signal} = 1; if ($list) { $list .= " $signal,"; } else { $list = "$signal,"; } } } print "\tdclk\n);\n"; print "input dclk;\n"; print "// synthesis attribute CLOCK_SIGNAL of dclk is \"yes\";\n"; # Read the netlist, acquiring a list of the sheet # number on which the parts and pads appear. open(INPUT, "pdp8i.net") || die "pdp8i.net: $!"; while () { last if /^Net\s/; } while () { chop; s/\r$//; y/A-Z/a-z/; next if /^change.*;$/; if (s/^(\S+)//) { $signal = $1; &sigfix; } ($foo, $part, $pad, $pin, $sheet) = split(/\s+/, $_); next unless defined $sheet; next if $sheet eq "*"; $sheets{$sheet} = 1; $sheet{"$part$pad"} = $sheet; $sheet{$part} = $sheet unless defined $sheet{$part}; $sheet{$part} = $sheet if $sheet < $sheet{$part}; #$signal{"$part$pad"} = $signal; # redundant } # Pass 1 # Figure out where the "reg"s and pullups are. for $part (sort keys %parts) { $dev = $partlist{$part}; *func = eval "*pass1_$dev"; &func if defined &func; } # # Now we have all the I/O pins, and enough # information about the signals to finish # declaring them. foreach (sort keys %nets) { if (defined $io{$_}) { if (defined $wand{$_}) { if ($out{$_}) { print "output wand $_;\n" unless $in{$_}; print "inout wand $_;\n" if $in{$_}; } else { print "input wand $_;\n"; } print "// synthesis attribute PULLUP of $_ is \"yes\";\n"; } elsif (defined $out{$_}) { # Assume that since we set it, it's an output. print "output $_;\n" unless $reg{$_}; print "output reg $_;\n" if $reg{$_}; } else { # Didn't set it, must be an input. print "input $_;\n"; } } elsif (defined $wand{$_}) { print "wand $_ = 1'b1;\n"; print "// synthesis attribute PULLUP of $_ is \"yes\";\n"; } elsif (defined $reg{$_}) { print "reg $_;\n"; } else { print "// " unless defined $in{$_} || defined $out{$_}; print "wire $_;\n"; } } print "\n"; sub bynum { $a <=> $b } # Now iterate over the sheets and invoke the code generator # functions to emit code for the gates and latches. for $sheet (sort bynum keys %sheets) { print "\n// Sheet $sheet\n"; for $part (sort keys %parts) { $dev = $partlist{$part}; *func = eval "*$dev"; #warn "No code generator for $part/$dev" unless defined &func; *func = *foobar unless defined &func; &func; } } print "\n"; print "endmodule\n"; close(STDOUT) || die; # BUGBUG: Experimental for $sheet (sort bynum keys %sheets) { open(STDOUT, ">sheet$sheet.v") || die "sheet$sheet.v: $!"; # # Iterate over all pads, collecting information for those which # appear on the current sheet. %sheet_sig = (); %sheet_out = %sheet_in = (); for $partpad (sort keys %signal) { next unless $sheet{$partpad} == $sheet; $dir = $direction{$partpad}; $signal = $signal{$partpad}; next unless $signal; next if $signal =~ /^1'b/; $sheet_sig{$signal} = 1; $sheet_out{$signal} = 1 if $dir eq "out"; $sheet_out{$signal} = 1 if $dir eq "oc"; $sheet_in{$signal} = 1 if $dir eq "in"; #print "$signal: $dir\n" if $signal =~ /^in00/; } # # Now output an interface specification for this sheet. print "module sheet$sheet("; foreach $signal (sort keys %sheet_sig) { print "$signal, "; } print "dclk);\n"; print "input dclk;\n"; print "// synthesis attribute CLOCK_SIGNAL of dclk is \"yes\";\n"; # Iterate again and declare a direction for each signal. foreach $signal (sort keys %sheet_sig) { #print "$reg{'pause'}: $signal: $reg{$signal}\n"; if ($sheet_out{$signal}) { if ($reg{$signal}) { print "output reg"; } elsif ($sheet_in{$signal}) { print "inout"; } else { print "output"; } print " wand" if @wand{$signal}; print " $signal;\n"; } else { print "input $signal;\n"; } } # # Now output the code for the sheet. print "\n// Sheet $sheet\n"; for $part (sort keys %parts) { $dev = $partlist{$part}; *func = eval "*$dev"; #warn "No code generator for $part/$dev" unless defined &func; *func = *foobar unless defined &func; &func; } print "\n"; print "endmodule\n"; close(STDOUT) || die; } exit 0; # # Given a bit of vhdl code, substitute signal names for # pad names, and emit the code. sub emit { ($text) = @_; # Substitute the module name as needed. $text =~ s/\${m}/$part/g; # Substitute the signal names as needed. foreach (@pins) { $text =~ s/([^'])\b${_}1\b/\1$signal{$part.$_.1}/g; $text =~ s/([^'])\b${_}2\b/\1$signal{$part.$_.2}/g; $text =~ s/([^'])\ba${_}1\b/\1$signal{${part}."a$_".1}/g; $text =~ s/([^'])\ba${_}2\b/\1$signal{${part}."a$_".2}/g; $text =~ s/([^'])\bb${_}1\b/\1$signal{${part}."b$_".1}/g; $text =~ s/([^'])\bb${_}2\b/\1$signal{${part}."b$_".2}/g; } print "$text\n"; } # # lookup substitutes signal names for pad names, and also does # simple substitutions for common constant expressions. sub lookup { local @_ = @_; # Substitute the signal names as needed. #print "in lookup $dev: @_\n"; foreach $p (@pins) { foreach (@_) { next if /'/; s/\b${p}1\b/\1$signal{$part.$p.1}/g; s/\b${p}2\b/\1$signal{$part.$p.2}/g; s/\ba${p}1\b/\1$signal{${part}."a$p".1}/g; s/\ba${p}2\b/\1$signal{${part}."a$p".2}/g; s/\bb${p}1\b/\1$signal{${part}."b$p".1}/g; s/\bb${p}2\b/\1$signal{${part}."b$p".2}/g; } } #print "out lookup: @_\n"; return @_; } # # andr simplifies a set of AND terms. sub andr { foreach (@_) { s/^s3v__.*/1'b1/; } return ("1'b0") if grep(/^1'b0$/, @_); return grep(!/^1'b1$/, @_); } # # nand takes a nand expression, simplifies it, and returns an # equivalent string. sub nand { return unless $sheet == $sheet{"${part}$_[0]"}; @_ = &lookup(@_); $dest = shift(@_); return unless $dest; @_ = &andr(@_); $text = join(" & ", @_); $text = "1'b1" if $text eq ""; if ($text eq "1'b0") { print "assign $dest = 1'b1;\n" unless $dest =~ /^1'b/; } else { print "assign $dest = ~($text);\n"; } } # For use only in pass 1. (The PULLUP attribute must be # specified at declaration time.) sub pullup { foreach $pad (@_) { $partpad = "$part$pad"; next unless $signal{$partpad}; next if $signal{$partpad} =~ /^1'b1/; # We mark each signal with a pull-up as being "wand". $wand{$signal{$partpad}} = 1; } } sub foobar { return unless $sheet == $sheet{$part}; print "//\n"; print "// $part: BUGBUG: No code generator for $dev!\n"; print "//\n"; } sub a607 { return unless $sheet == $sheet{$part}; print "// $part: A607 D-A Converter\n"; print "// implement externally (analog)\n"; } sub elide_g021 {} sub g021 { return unless $sheet == $sheet{$part}; print "// $part: G021 Core Sense Amplifier\n"; print "// not implemented (core memory)\n"; } sub elide_g221 {} sub g221 { return unless $sheet == $sheet{$part}; print "// $part: G221 Memory Selector\n"; print "// not implemented (core memory)\n"; } sub elide_g228 {} sub g228 { return unless $sheet == $sheet{$part}; print "// $part: G228 Inhibit Driver\n"; print "// not implemented (core memory)\n"; } sub elide_g610 {} sub g610 { return unless $sheet == $sheet{$part}; print "// $part: G610 Diode Board\n"; print "// not implemented (core memory)\n"; } sub elide_g611 {} sub g611 { return unless $sheet == $sheet{$part}; print "// $part: G611A Diode Board\n"; print "// not implemented (core memory)\n"; } sub elide_g624 {} sub g624 { return unless $sheet == $sheet{$part}; print "// $part: G624 Resistor Board\n"; print "// not implemented (core memory)\n"; } sub g785a { return unless $sheet == $sheet{$part}; print "// $part: G785A Regulator Board\n"; print "// not implemented (power supply)\n"; } sub g785b { return unless $sheet == $sheet{$part}; print "// $part: G785B Regulator Board\n"; print "// not implemented (power supply)\n"; } sub g805 { return unless $sheet == $sheet{$part}; print "// $part: G805 Negative Regulator\n"; print "// not implemented (power supply)\n"; } sub g821 { return unless $sheet == $sheet{$part}; print "// $part: G821 Regulator Control\n"; print "// not implemented (power supply)\n"; } sub pass1_g826 { &pullup("af2", "ah2", "aj2", "as2"); # Convert AJ2 from an output to an input pin. ($aj2) = &lookup("aj2"); undef $out{$aj2}; $io{$aj2} = 1; $in{$aj2} = 1; ($af2) = &lookup("af2"); undef $out{$af2}; } sub g826 { return unless $sheet == $sheet{$part}; print "// $part: G826 Regulator Control\n"; print "// not implemented (power supply)\n"; # Just claim that power is OK. # BUGBUG: Should really assert as2 at power up. #&emit("assign af2 = 1'b1;"); # shut_down_ #&emit("assign ah2 = 1'b1;"); # stop_ok_ (input with pullup) #&emit("assign aj2 = 1'b0;"); # power_ok_ #&emit("assign as2 = 1'b1;"); # power_clear_ } sub g921a { return unless $sheet == $sheet{$part}; print "// $part: G921b 8/L Front Panel Connector\n"; print "// implemented in the interface (above)\n"; } sub g921b { return unless $sheet == $sheet{$part}; print "// $part: G921b 8/L Front Panel Connector\n"; print "// implemented in the interface (above)\n"; } sub g921c { return unless $sheet == $sheet{$part}; print "// $part: G921c 8/L Front Panel Connector\n"; print "// implemented in the interface (above)\n"; } sub g921d { return unless $sheet == $sheet{$part}; print "// $part: G921d 8/L Front Panel Connector\n"; print "// implemented in the interface (above)\n"; } sub m040 { # Can't mimic the darlington drive, so just do the logic. &nand("r2", "d2", "e2", "f2", "h2"); &nand("s2", "j2", "k2", "l2", "m2"); } sub pass1_m113 { &pullup("u1", "v1"); } sub m113 { # M113 2 Input NAND Gates &nand("c1", "a1", "b1"); &nand("f1", "d1", "e1"); &nand("k1", "h1", "j1"); &nand("n1", "l1", "m1"); &nand("s1", "p1", "r1"); &nand("f2", "d2", "e2"); &nand("k2", "h2", "j2"); &nand("n2", "l2", "m2"); &nand("s2", "p2", "r2"); &nand("v2", "t2", "u2"); } sub m115 { # M115 3 Input NAND Gates &nand("d1", "a1", "b1", "c1"); &nand("j1", "e1", "f1", "h1"); &nand("n1", "k1", "l1", "m1"); &nand("u1", "p1", "r1", "s1"); &nand("h2", "d2", "e2", "f2"); &nand("m2", "j2", "k2", "l2"); &nand("s2", "n2", "p2", "r2"); &nand("v1", "t2", "u2", "v2"); } sub pass1_m117 { &pullup("u1", "v1"); } sub m117 { # M117 4 Input NAND Gates &nand("e1", "a1", "b1", "c1", "d1"); &nand("l1", "f1", "h1", "j1", "k1"); &nand("s1", "m1", "n1", "p1", "r1"); &nand("j2", "d2", "e2", "f2", "h2"); &nand("p2", "k2", "l2", "m2", "n2"); &nand("v2", "r2", "s2", "t2", "u2"); } sub pass1_m119 { &pullup("u1", "v1"); } sub m119 { # M119 8 Input NAND Gates &nand("j2", "a1", "b1", "c1", "d1", "d2", "e2", "f2", "h2"); &nand("p2", "f1", "h1", "j1", "k1", "k2", "l2", "m2", "n2"); &nand("v2", "m1", "n1", "p1", "r1", "r2", "s2", "t2", "u2"); } sub m160 { if ($sheet == $sheet{"${part}r1"}) { ($r1, $a1, $b1, $c1, $d1, $e1, $f1, $h1, $j1, $k1, $l1, $m1, $n1, $p1) = &lookup("r1", "a1", "b1", "c1", "d1", "e1", "f1", "h1", "j1", "k1", "l1", "m1", "n1", "p1"); $tmp1 = join(" & ", &andr($a1, $b1, $c1, $d1)); $tmp2 = join(" & ", &andr($e1, $f1)); $tmp3 = join(" & ", &andr($h1, $j1)); $tmp4 = join(" & ", &andr($k1, $l1)); $tmp5 = join(" & ", &andr($m1, $n1, $p1)); print "assign $r1 = ($tmp1) | ($tmp2) | ($tmp3) | ($tmp4) | ($tmp5);\n"; } if ($sheet == $sheet{"${part}t2"}) { ($t2, $d2, $e2, $f2, $h2, $j2, $k2, $l2, $m2, $n2, $p2, $r2, $s2) = &lookup("t2", "d2", "e2", "f2", "h2", "j2", "k2", "l2", "m2", "n2", "p2", "r2", "s2"); $tmp1 = join(" & ", &andr($d2, $e2, $f2, $h2)); $tmp2 = join(" & ", &andr($j2, $k2)); $tmp3 = join(" & ", &andr($l2, $m2)); $tmp4 = join(" & ", &andr($n2, $p2, $r2, $s2)); print "assign $t2 = ($tmp1) | ($tmp2) | ($tmp3) | ($tmp4);\n"; } if ($sheet == $sheet{"${part}v2"}) { ($v2, $s1, $u1, $v1, $u2) = &lookup("v2", "s1", "u1", "v1", "u2"); $tmp1 = join(" & ", &andr($s1, $u1)); $tmp2 = join(" & ", &andr($v1, $u2)); print "assign $v2 = ($tmp1) | ($tmp2);\n"; } } sub m162 { if (($sheet == $sheet{"${part}k1"}) || ($sheet == $sheet{"${part}l1"})) { ($k1, $l1, @_) = &lookup("k1", "l1", "a1", "b1", "c1", "d1", "e1", "f1", "h1", "j1"); if (!$k1) { $k1 = $l1; $k1 =~ s/_$//; } @_ = grep(!/^1'b0$/, @_); print "assign $k1 = ", join(" ^ ", @_), ";\n"; print "assign $l1 = ~$k1;\n" if $l1; } if (($sheet == $sheet{"${part}u2"}) || ($sheet == $sheet{"${part}v2"})) { ($u2, $v2, @_) = &lookup("u2", "v2", "k2", "l2", "m2", "n2", "p2", "r2", "s2", "t2"); if (!$u2) { $u2 = $v2; $u2 =~ s/_$//; } @_ = grep(!/^1'b0$/, @_); print "assign $u2 = ", join(" ^ ", @_), ";\n"; print "assign $v2 = ~$u2;\n" if $v2; } } # # Force foo into existence as the complement of bar. sub kludge { local($foopad, $barpad) = @_; ($foo, $bar) = &lookup($foopad, $barpad); if (!$foo) { # Already defined return unless $bar; $foo = $bar; # Convert $bar to a value for $foo. $foo =~ s/_$//; # Convert $bar to a value for $foo. $foo = $bar."__" unless $bar =~ /_$/; $nets{$foo} = 1; $signal{$part.$foopad} = $foo; $direction{$part.$foopad} = "out"; $sheet{$part.$foopad} = $sheet{$part.$barpad}; $out{$foo} = 1; #print "// kludge: created $bar on sheet ", $sheet{"$part$barpad"}, "\n"; #print "// kludge: \$sheet{$part.$foopad} = \$sheet{$part.$barpad};\n"; #print "// kludge: $sheet{$part.$foopad} = $sheet{$part.$barpad};\n"; } $reg{$foo} = 1; } sub pass1_m216 { # By convention, we have chosen to make "Q" a reg, and "Q_" a wire. @foopad = ("e1", "h2", "l1", "p2", "s1", "v2"); @barpad = ("f1", "j2", "m1", "r2", "u1", "v1"); foreach $foopad (@foopad) { $barpad = shift @barpad; &kludge($foopad, $barpad); } } sub dflop { if ($sheet == $sheet{"${part}$_[0]"}) { ($q, $q_, $d, $c, $r_, $s_) = &lookup(@_); #print "// synthesis attribute CLOCK_SIGNAL of $c is \"yes\";\n"; print "always @(posedge $c"; print ", negedge $r_" if $r_ ne "1'b1"; print ", negedge $s_" if $s_ ne "1'b1"; print ") begin\n "; if ($d eq "1'b1") { if ($s_ ne "1'b1") { print "if (~$s_)\n $q <= 1'b1;\n else\n "; } if ($r_ ne "1'b1") { print "if (~$r_)\n $q <= 1'b0;\n else\n "; } } else { if ($r_ ne "1'b1") { print "if (~$r_)\n $q <= 1'b0;\n else\n "; } if ($s_ ne "1'b1") { print "if (~$s_)\n $q <= 1'b1;\n else\n "; } } print " $q <= $d;\nend\n"; print "assign $q_ = ~$q;\n" if $q_; } } sub m216 { &dflop("e1", "f1", "c1", "b1", "a1", "d1"); &dflop("h2", "j2", "e2", "d2", "a1", "f2"); &dflop("l1", "m1", "j1", "h1", "a1", "k1"); &dflop("p2", "r2", "m2", "l2", "k2", "n2"); &dflop("s1", "u1", "p1", "n1", "k2", "r1"); &dflop("v2", "v1", "t2", "s2", "k2", "u2"); } sub pass1_m220 { # By convention, we have chosen to make "Q" a reg, and "Q_" a wire. # Here, we also kludge into existance Q, if only Q_ has a net. @foopad = ("ba1", "at2", "ap1", "am2", "av1", "as2", "an1", "al2"); @barpad = ("bb1", "au2", "ar2", "am1", "av2", "as1", "ap2", "al1"); foreach $foopad (@foopad) { $barpad = shift @barpad; &kludge($foopad, $barpad); } ($aj1, $ak2, $am2, $al2) = &lookup("aj1", "ak2", "am2", "al2"); if (!$aj1) { $aj1 = $am2; $aj1 =~ s/^ma/regbus/; $ak2 = $al2; $ak2 =~ s/^ma/regbus/; $nets{$aj1} = 1; $nets{$ak2} = 1; $signal{"${part}aj1"} = $aj1; $signal{"${part}ak2"} = $ak2; $direction{"${part}aj1"} = "in"; $direction{"${part}ak2"} = "in"; $sheet{"${part}aj1"} = $sheet{"${part}am2"}; $sheet{"${part}ak2"} = $sheet{"${part}al2"}; $out{$aj1} = 1; $out{$ak2} = 1; } } # # Now for the hair. sub m220 { if ($sheet == $sheet{"${part}am2"}) { print "// Latch ALU results in the appropriate register.\n"; ($ak1, $aj1, $am2, $ak2, $al2, $am1, $al1) = &lookup("ak1", "aj1", "am2", "ak2", "al2", "am1", "al1"); if ($aj1 eq "") { ($aj1, $ak2) = ($am2, $al2); grep(s/ma/regbus/, ($aj1, $ak2)); print "wire $aj1, $ak2;\n"; } print "always @(posedge $ak1) begin\n"; print " $am2 <= $aj1; // MA\n"; print " $al2 <= $ak2;\n"; print "end\n"; print "assign $am1 = ~$am2;\n"; print "assign $al1 = ~$al2;\n"; ($an2, $ap1, $an1, $ar2, $ap2) = &lookup("an2", "ap1", "an1", "ar2", "ap2"); if ($ap1 eq "") { ($ap1, $an1) = ($ar2, $ap2); grep(s/_$//, ($ap1, $an1)); print "reg $ap1, $an1;\n"; } print "always @(posedge $an2) begin\n"; print " $ap1 <= $aj1; // PC\n"; print " $an1 <= $ak2;\n"; print "end\n"; print "assign $ar2 = ~$ap1;\n"; print "assign $ap2 = ~$an1;\n"; ($ar1, $at2, $as2, $au2, $as1) = &lookup("ar1", "at2", "as2", "au2", "as1"); print "always @(posedge $ar1) begin\n"; print " $at2 <= $aj1; // MB\n"; print " $as2 <= $ak2;\n"; print "end\n"; print "assign $au2 = ~$at2;\n"; print "assign $as1 = ~$as2;\n"; ($au1, $ba1, $av1, $bb1, $av2) = &lookup("au1", "ba1", "av1", "bb1", "av2"); print "always @(posedge $au1) begin\n"; print " $ba1 <= $aj1; // AC\n"; print " $av1 <= $ak2;\n"; print "end\n"; print "assign $bb1 = ~$ba1;\n"; print "assign $av2 = ~$av1;\n"; } if ($sheet == $sheet{"${part}af1"}) { # Select the adder inputs. ($bh1, $bf1, $bh2, $ba1, $bj2, $bb1, $bm2, $bl1, $be1, $bc1, $bd1, $bf2, $bl2, $bk1) = &lookup("bh1", "bf1", "bh2", "ba1", "bj2", "bb1", "bm2", "bl1", "be1", "bc1", "bd1", "bf2", "bl2", "bk1"); $t1 = join(" & ", &andr($bf1, $bh1)); $t2 = join(" & ", &andr($bh2, $ba1)); $t3 = join(" & ", &andr($bj2, $bb1)); $t4 = join(" & ", &andr($bl1, $bm2)); $t5 = join(" & ", &andr($bc1, $be1)); $t6 = join(" & ", &andr($bf2, $bd1)); $t7 = join(" & ", &andr($bl2, $bk1)); $l0 = "~($t1 | $t2 | $t3 | $t4 | $t5 | $t6 | $t7)"; ($bn2, $av1, $be2, $av2, $bp2, $bd2, $bn1, $bm1) = &lookup("bn2", "av1", "be2", "av2", "bp2", "bd2", "bn1", "bm1"); $t1 = join(" & ", &andr($bf1, $bn2)); $t2 = join(" & ", &andr($bh2, $av1)); $t3 = join(" & ", &andr($bj2, $av2)); $t4 = join(" & ", &andr($bl1, $bp2)); $t5 = join(" & ", &andr($bc1, $bd2)); $t6 = join(" & ", &andr($bf2, $bn1)); $t7 = join(" & ", &andr($bl2, $bm1)); $l1 = "~($t1 | $be2 | $t2 | $t3 | $t4 | $t5 | $t6 | $t7)"; ($br1, $bu2, $am2, $bp1, $ap1, $bs2, $bt2, $bs1) = &lookup("br1", "bu2", "am2", "bp1", "ap1", "bs2", "bt2", "bs1"); if ($ap1 eq "") { $ap1 = $am2; $ap1 =~ s/^ma/pc/; } $t1 = join(" & ", &andr($bu2, $br1)); $t2 = join(" & ", &andr($bp1, $am2)); $t3 = join(" & ", &andr($bs2, $ap1)); $t4 = join(" & ", &andr($bt2, $bs1)); $r0 = "~($t1 | $t2 | $t3 | $t4)"; ($bv1, $bv2, $al2, $br2, $an1, $bu1) = &lookup("bv1", "bv2", "al2", "br2", "an1", "bu1"); if ($an1 eq "") { $an1 = $al2; $an1 =~ s/^ma/pc/; } $t1 = join(" & ", &andr($bv1, $bv2)); $t2 = join(" & ", &andr($br2, $al2)); $t3 = join(" & ", &andr($bs2, $an1)); $t4 = join(" & ", &andr($bt2, $bu1)); $r1 = "~($t1 | $t2 | $t3 | $t4)"; ($bk2, $ae2, $af1, $bj1) = &lookup("bk2", "ae2", "af1", "bj1"); print "// This hair takes two operand bits and carry-in, adds them, and\n"; print "// generates two bits of result and a carry-out. Note that the\n"; print "// inputs are complemented, and therefore, so are the outputs.\n"; print "assign {$bk2, $ae2, $af1} = $bj1 + { $l0, $l1 } + { $r0, $r1 };\n"; # Now select the correct outputs for regbus. ($aa1, $ad1, $ae1, $ad2, $af2, $ah1, $ab2) = &lookup("aa1", "ad1", "ae1", "ad2", "af2", "ah1", "ab2"); ($aj1, $au2, $ab1, $ae2, $ac1, $af1, $ah2, $bb2) = &lookup("aj1", "au2", "ab1", "ae2", "ac1", "af1", "ah2", "bb2"); if ($aj1 eq "") { $aj1 = $ae2; $aj1 =~ s/adder/regbus/; } $t1 = join(" & ", &andr($aa1, $au2)); $t2 = join(" & ", &andr($ad1, $ab1)); $t3 = join(" & ", &andr($ae1, $ae2)); $t4 = join(" & ", &andr($ad2, $ac1)); $t5 = join(" & ", &andr($af2, $af1)); $t6 = join(" & ", &andr($ah1, $ah2)); $t7 = join(" & ", &andr("~$ab2", $bb2)); print "assign $aj1 = ~($t1 | $t2 | $t3 | $t4 | $t5 | $t6 | $t7);\n"; ($ak2, $as1, $aj2) = &lookup("ak2", "as1", "aj2"); if ($ak2 eq "") { $ak2 = $af1; $ak2 =~ s/adder/regbus/; } $t1 = join(" & ", &andr($aa1, $as1)); $t2 = join(" & ", &andr($ad1, $ac1)); $t3 = join(" & ", &andr($ae1, $af1)); $t4 = join(" & ", &andr($ad2, $ae2)); $t5 = join(" & ", &andr($af2, $ah2)); $t6 = join(" & ", &andr($ah1, $aj2)); $t7 = join(" & ", &andr("~$ab2", $af1)); print "assign $ak2 = ~($t1 | $t2 | $t3 | $t4 | $t5 | $t6 | $t7);\n"; } } sub m310 { if ($sheet == $sheet{"${part}h2"}) { ($h2, @_) = &lookup("h2", "j2", "k2", "l2", "m2", "n2", "p2", "r2", "s2", "t2", "u2", "v2"); for ($d = 0; $d <= 500; $d += 50) { $signal = shift @_; next unless $signal; print "DelayLine #($d) dl_$signal(dclk, $h2, $signal);\n"; die "$signal must not be 'wand'" if $wand{$signal}; } } if ($sheet == $sheet{"${part}f1"}) { ($e1, $f1) = &lookup("e1", "f1"); print "assign $f1 = $e1;\n" if $f1; } if ($sheet == $sheet{"${part}j1"}) { ($h1, $j1) = &lookup("h1", "j1"); print "assign $j1 = $h1;\n" if $j1; } } sub m360 { next unless $sheet == $sheet{"${part}s2"}; ($p2, $r2, $s2, $t2) = &lookup("p2", "r2", "s2", "t2"); print "Monostable #(100) m360s_$s2(dclk, $p2 & $r2, $s2);\n"; print "assign $t2 = ~$s2;\n"; } sub m452 { next unless $sheet == $sheet{"${part}k2"}; ($p2, $r2, $j2, $m2, $n2, $l2, $k2) = &lookup("p2", "r2", "j2", "m2", "n2", "l2", "k2"); # BUGBUG: This is specific to the particular invocation excpected. print "Oscillator #(880) m452_$j2(dclk, 1'b1, $j2);\n"; die "$j2 must not be 'wand'" if $wand{$j2}; print "Oscillator #(220) m452_$k2(dclk, 1'b1, $k2);\n"; die "$k2 must not be 'wand'" if $wand{$k2}; print "assign $r2 = $p2;\n"; } sub m501 { next unless $sheet == $sheet{"${part}f2"}; ($j2, $f2) = &lookup("j2", "f2"); # BUGBUG: This is specific to the particular invocation excpected. print "Oscillator #(60) m501_$f2(dclk, $j2, $f2);\n"; die "$f2 must not be 'wand'" if $wand{$f2}; } sub pass1_m506 { &pullup("a1", "b1", "f1", "h1", "m1", "n1"); &pullup("d2", "e2", "k2", "l2", "r2", "s2"); } sub m506 { # Obviously we can't do the negative input conversion for # a1, d2, f1, k2, m1, and r2, so we just assume those will # positive level inputs, driven by OC devices. This makes # us essentially equivalent to the M516. &m516; } sub pass1_m516 { &pullup("b1", "h1", "n1", "e2", "l2", "s2"); #&pullup("a1", "b1", "f1", "h1", "m1", "n1"); #&pullup("d2", "e2", "k2", "l2", "r2", "s2"); } sub m516 { # The M516 is essentially a set of NAND gates, with pull-ups # on some of the inputs. &nand("e1", "a1", "b1", "c1", "d1"); &nand("l1", "f1", "h1", "j1", "k1"); &nand("s1", "m1", "n1", "p1", "r1"); &nand("j2", "d2", "e2", "f2", "h2"); &nand("p2", "k2", "l2", "m2", "n2"); &nand("v2", "r2", "s2", "t2", "u2"); } sub m617 { &m117; } sub pass1_m650 { &pullup("d2", "k2", "s2"); } sub m650 { # We can't do the negative logic conversion for the M650, # so our M650 ends up equivalent to an M661. (This also # means we ignore the disable inputs.) &m661; } sub m660 { # The M660 is a set of 3 2-input NAND buffers with huge fan-out. &nand("d2", "h2", "j2"); &nand("k2", "n2", "p2"); &nand("s2", "u2", "v2"); } sub pass1_m661 { &pullup("d2", "k2", "s2"); } sub m661 { # These are essentially 3-input OC AND gates with a pull-up. if ($sheet == $sheet{"${part}d2"}) { ($d2, $f2, $h2, $j2) = &lookup("d2", "f2", "h2", "j2"); print "assign $d2 = ", join(" & ", andr($f2, $h2, $j2)), ";\n"; } if ($sheet == $sheet{"${part}k2"}) { ($k2, $m2, $n2, $p2) = &lookup("k2", "m2", "n2", "p2"); print "assign $k2 = ", join(" & ", andr($m2, $n2, $p2)), ";\n"; } if ($sheet == $sheet{"${part}s2"}) { ($s2, $t2, $u2, $v2) = &lookup("s2", "t2", "u2", "v2"); print "assign $s2 = ", join(" & ", andr($t2, $u2, $v2)), ";\n"; } } sub pass1_m700 { ($aj2, $af2) = &lookup("aj2", "af2"); $reg{$aj2} = 1; $reg{$af2} = 1; &pullup("be2", "bf2"); } sub m700 { if ($sheet == $sheet{"${part}at2"}) { ($at2, $ar2, $as2, $ap2, $an2, $am2) = &lookup("at2", "ar2", "as2", "ap2", "an2", "am2"); print "// TODO: $as2 should be suitably filtered.\n"; print "assign $at2 = ($ar2 & $as2) | ~$ap2;\n"; print "assign $an2 = $at2;\n" if $an2; print "assign $am2 = ~$at2;\n"; ($al2, $ah2, $aj2, $ak2) = &lookup("al2", "ah2", "aj2", "ak2"); print "always @(posedge $am2, negedge $al2, negedge $ah2) begin\n"; print " if (~$ah2)\n"; print " $aj2 = 1'b0;\n"; print " else if (~$al2)\n"; print " $aj2 = 1'b0;\n"; print " else\n"; print " $aj2 = 1'b1;\n"; print "end\n"; print "assign $ak2 = ~$aj2;\n"; ($ae2, $bd2, $af2) = &lookup("ae2", "bd2", "af2"); print "DelayLine #(2000) m700ae2(dclk, $at2, $ae2);\n"; die "$ae2 must not be 'wand'" if $wand{$ae2}; print "DelayLine #(2000) m700bd2(dclk, $ae2, $bd2);\n"; die "$bd2 must not be 'wand'" if $wand{$bd2}; print "always @(posedge $ae2, posedge $bd2, negedge $al2) begin\n"; print " if (~$al2)\n"; print " $af2 = 1'b0;\n"; print " else if ($bd2)\n"; print " $af2 = 1'b0;\n"; print " else\n"; print " $af2 = 1'b1;\n"; print "end\n"; print "assign $ah2 = ~$af2;\n"; } if ($sheet == $sheet{"${part}be2"}) { ($be2) = &lookup("be2"); } if ($sheet == $sheet{"${part}bf2"}) { ($bf2) = &lookup("bf2"); } } # Several of the M7xx modules implement a feature with # sufficient modularity that nothing is gained by expanding # the logic inline. For those, just invoke the specified # module name. sub m7xx { return unless $sheet == $sheet{$part}; $module = shift @_; @ifc = @_; foreach $partpad (sort keys %signal) { next unless $signal{$partpad}; next unless $partpad =~ /^$part/; next if $partpad eq "${part}a2"; # Skip vcc next if $partpad eq "${part}aa2"; # Skip vcc next if $partpad eq "${part}ba2"; # Skip vcc next if $partpad eq "${part}c2"; # Skip vcc next if $partpad eq "${part}ac2"; # Skip vcc next if $partpad eq "${part}bc2"; # Skip vcc #print "partpad: $partpad\n"; $pad = $partpad; $pad =~ s/^$part//; push(@ifc, ".$pad("."$signal{$partpad})"); } # Invoke the module print "$module $part$dev(", join(", ", @ifc), ");\n"; } sub m701 { &m7xx("DisplayControl"); } sub pass1_m703 { ($r2) = &lookup("r2"); $reg{$r2} = 1; } sub m703 { #&m7xx("PowerFail"); return unless $sheet == $sheet{$part}; ($d2, $e2, $f2, $h2, $j2, $k2, $l2, $m2) = &lookup("d2", "e2", "f2", "h2", "j2", "k2", "l2", "m2"); ($n2, $p2, $r2, $s2, $t1, $t2, $u1, $u2) = &lookup("n2", "p2", "r2", "s2", "t1", "t2", "u1", "u2"); if (!$t2) { $t2 = $r2; $t2 =~ s/_$//; } print "always @(negedge $s2, negedge $u2) begin\n"; print " if (~$s2)\n"; print " $r2 <= 1;\n"; print " else\n"; print " $r2 <= 0;\n"; print "end\n"; print "assign $t2 = ~$r2;\n" if $t2; print "assign $l2 = ~($d2 & $e2 & $f2 & $h2 & $j2 & $k2 & $m2 & $t2);\n"; print "Monostable #(1000000) ${part}a(dclk, $u2, $p2);\n"; print "// TODO: kp8i_enable should be a switch, which would require\n"; print "// an input pin.\n"; print "`ifdef kp8i_enable\n"; print "Monostable #(200000000) ${part}b(dclk, $p2 & $u2, ${part}c1);\n"; print "`else\n"; print "assign ${part}c1 = 1'b0;\n"; print "`endif\n"; print "Monostable #(1000000) ${part}c(dclk, ${part}c1, $n2);\n"; print "assign $u1 = ~$n2;\n"; } sub m704 { &m7xx("PlotterControl", ".dclk(dclk)"); } sub m705 { &m7xx("ReaderControl"); } sub m706 { &m7xx("TTYReceiver"); } sub m707 { &m7xx("TTYTransmitter"); } sub m708 { &m7xx("ClockControl"); } sub m709 { &m7xx("ClockCounter", ".dclk(dclk)"); } sub m710 { &m7xx("PunchControl", ".dclk(dclk)"); } sub m714 { &m7xx("CardReaderControl"); } sub m715 { &m7xx("ReaderClock", ".dclk(dclk)"); } sub m716 { &m7xx("CardReaderBuffer", ".dclk(dclk)"); } sub m720 { if ($sheet == $sheet{"${part}d2"}) { ($d2, $e2, $j2, $v2) = &lookup("d2", "e2", "j2", "v2"); print "Monostable #(35000) ${part}e2(dclk, $j2 & $v2, ${e2}__);\n"; # GROT: Messy work-around for inability to connect "reg" output of # Monostable directly to a "wand" output pin. print "assign $e2 = ${e2}__;\n"; print "Monostable #(40000) ${part}d2(dclk, $j2 & $v2, $d2);\n"; } &nand("u2", "s2", "t2"); } sub m900 { # The M900 is essentially a connector, which we dealt with at # interface time. The buffering behavior can't really be # implemented here } sub w011 { # The W011 is essentially a connector, which we dealt with at # interface time. } sub w023 { # The W023 is essentially a connector, which we dealt with at # interface time. } sub w025 { # The W025 is essentially a connector to the core plane, which # isn't implemented here. } sub w076 { # The W076 is essentially a connector, which we dealt with at # interface time. } sub w077 { # The W077 is essentially a connector, which we dealt with at # interface time. } sub w991 { # The W991 is essentially a connector, which we dealt with at # interface time. }