#!/usr/bin/perl -w use strict qw(vars); our ($basename); $basename= @ARGV ? $ARGV[0] : 'safety'; die if $basename =~ m/^\-/; $basename =~ s/\.wiring$//; our ($mistakes, $currentline); our (%segs); # $segs{$seg}{Inv} # $segs{$seg}{BoOb} # $segs{$seg}{Posns} # $segs{$seg}{FeatCount} does not include Fixed # $segs{$seg}{Feats}{$pt}{Kind} Point or Fixed # $segs{$seg}{Feats}{$pt}{Weight} ) for Point only # $segs{$seg}{Feats}{$pt}{Posns} ) for Point only # $segs{$seg}{Feats}{$pt}{BoOb}[] ) for Point only # $segs{$seg}{Feats}{$pt}{Fixed} position, for Fixed only # $segs{$seg}{Num} # $segs{$seg}{Ends}[$combpos][$end] = [ $node,$side ] # $segs{$seg}{Dist}[$combpos] our (%nodes); # $nodes{$node}[$side]{Seg} # $nodes{$node}[$side]{End} our ($nextboardnum,@objkinds,@boardobjbase,@boardtype,%pin_used); # @boardtype[$boardnum] # $boardobjbase[$boardnum]{$kind} # %pin_used{$objkind}[$objnum] = [ $boardnum, $pin_info, $objonboard ] $nextboardnum= 0; @objkinds= qw(pt sense reverse); map { $boardobjbase[0]{$_}= 1; } @objkinds; our (%kind_count,%pin_info); # from BOARD.pin-info our ($mode,$invertible); $mode= 'barf'; sub line_barf () { return if $mistakes; mistake("first input line does not determine phase"); } sub syntaxerror () { our (%syntaxerror_once); return if exists $syntaxerror_once{$mode}; $syntaxerror_once{$mode}= 1; mistake("syntax error"); return undef; } sub ditch ($) { my ($m) = @_; print STDERR "ditching $m\n"; } sub begin_points () { } sub line_points () { my ($seg,$pt,@boob,$bodef); m,^\s+(\w+)/([A-Za-z]+)\s+((\d+)\.\d+)\s+(\d*\.\d+)$, or return syntaxerror(); ($seg,$pt,$boob[0],$bodef,$boob[1])=($1,$2,$3,$4,$5); $boob[1] =~ s/^\./$bodef./; mistake("unknown wiring for $seg in $seg/$pt") unless exists $segs{$seg}; mistake("duplicate wiring for $seg/$pt") if exists $segs{$seg}{Feats}{$pt}; $segs{$seg}{Feats}{$pt}= { Kind => Point, Weight => $segs{$seg}{Posns}, Posns => 2, BoOb => [ map { pa_boob($_) } @boob ] }; $segs{$seg}{Posns} *= 2; $segs{$seg}{FeatCount}++; } sub begin_fixed () { } sub line_fixed () { my ($seg,$pt,$pos); m,^\s+(\w+)/([A-Za-z]+)(\d+)$, or return syntaxerror(); ($seg,$pt,$pos)=($1,$2,$3); mistake("unknown wiring for $seg in $seg/$pt") unless exists $segs{$seg}; mistake("duplicate fixed $seg/$pt") if exists $segs{$seg}{Feats}{$pt}; $segs{$seg}{Feats}{$pt}= { Kind => Fixed, Fixed => $pos }; } sub begin_segment () { } sub line_segment () { my ($seg,$boob); m/^\s+(\w+)\s+(\d+\.\d+)$/ or return syntaxerror(); ($seg,$boob)=($1,$2); mistake("duplicate topology for $seg") if exists $segs{$seg}; $segs{$seg}= { BoOb => pa_boob($boob), Inv => $invertible, Posns => 1, Feats => { }, FeatCount => 0 }; } sub begin_endwiring () { } sub begin_boards () { } sub line_boards () { my ($num,$type,$k); m/^\s+(\d+)\s+(\w+)$/ or return syntaxerror(); ($num,$type)=($1,$2); mistake("board $num when expected $nextboardnum") if $num != $nextboardnum; $nextboardnum++; require "./$type.pin-info"; $boardtype[$num]= $type; foreach $k (@objkinds) { $boardobjbase[$nextboardnum]{$k}= $boardobjbase[$num]{$k} + $kind_count{$type}{$k}; } } sub mistake ($) { my ($m) = @_; print STDERR "mistake: $m\n in $mode, \`$currentline'\n"; $mistakes++; } sub line_endwiring () { my (@ns,$seg,$subspec,$dist); my ($segr,@subsegil,$feat,$pos,$featr,$combpos,%featposwant); my ($end,$node,$side,$nsr,$endposr); m,^\s*segment\s+(\w+\.\d+)\s+(\w+\.\d+)\s+(\w+)(?:/((?:[A-Za-z]+\d+)+)\*\d+)?\s+([0-9.]+)$, or return syntaxerror(); ($ns[0],$ns[1],$seg,$subspec,$dist)=($1,$2,$3,$4,$5); if (!exists $segs{$seg}) { ditch("unwired $seg$subspec"); return; } $segr= $segs{$seg}; @subsegil= defined $subspec ? $subspec =~ m/([A-Za-z]+)(\d+)/g : (); while (@subsegil) { ($feat,$pos,@subsegil) = @subsegil; if (!exists $segr->{Feats}{$feat}) { mistake("no wiring for $seg/$feat"); next; } $featr= $segr->{Feats}{$feat}; if (exists $featr->{Fixed}) { if ($pos != $featr->{Fixed}) { ditch("fixed-elsewise $seg$subspec"); return; } } else { mistake("position $seg/$feat$pos exceeds wiring") unless $pos < $featr->{Posns}; $featposwant{$feat}= $pos; } } $combpos= 0; for $feat (keys %{ $segr->{Feats} }) { $featr= $segr->{Feats}{$feat}; next if exists $featr->{Fixed}; mistake("wiring $seg/$feat not covered by $seg/$subspec") if !exists $featposwant{$feat}; $combpos += $featposwant{$feat} * $featr->{Weight}; } mistake("duplicate topology for $seg/$subspec") if defined $segs{$seg}{Dist}[$combpos]; $segs{$seg}{Dist}[$combpos]= $dist; $endposr= $segr->{Ends}[$combpos]; die "$seg $combpos @$endposr ?" if defined $endposr && @$endposr; for ($end=0; $end<2; $end++) { $ns[$end] =~ m/^([a-z]\w+)\.([01])$/; ($node,$side)=($1,$2); $nsr= $nodes{$node}[$side]; if (!exists $nsr->{Seg}) { $nodes{$node}[$side]= { Seg => $seg, End => $end }; } else { $seg eq $nsr->{Seg} or mistake("topology for $node.$side both $seg and $nsr->{Seg}"); $end == $nsr->{End} or mistake("topology for $node.$side $seg both ends ($end". " and also $nsr->{End})"); } $segr->{Ends}[$combpos][$end]= [ $node, $side ]; } } sub o ($) { print STDOUT $_[0] or die $!; } sub pa_boob ($) { my ($boob) = @_; if ($boob !~ m/^([1-9]\d*|0)\.([1-9]\d*|0)$/) { mistake("invalid board object $boob"); return [ 0,0 ]; } return [ $1,$2 ]; } sub so_boob ($$) { my ($k,$bo) = @_; if (defined $bo) { my ($board,$obj)= @$bo; my ($objnum,$type,$pi); mistake("unknown board number $board") unless defined $boardtype[$board]; $objnum= $boardobjbase[$board]{$k} + $obj; $type= $boardtype[$board]; $pi= $pin_info{$type}{$k}; mistake("object reference $k $board.$obj out of range for". " board type $type") unless defined $pi->[$obj]; $pin_used{$k}[$objnum]= [ $board, $pi->[$obj], $obj ]; return sprintf("%4d /* %d.%-2d*/", $objnum, $board, $obj); } else { return " 0 /*none*/ "; } } sub so_oboob ($$) { my ($k,$obj) = @_; return so_boob($k, defined $obj ? $obj->{BoOb} : undef); } sub mainread () { $mistakes= 0; while (<>) { next if m/^\#/; chomp; s/\s+$//; next unless m/\S/; last if m/^end$/; if (m/^(invertible|vanilla|points|fixed|endwiring|boards)$/) { $mode= $1; $invertible= ($mode eq 'invertible'); $mode= 'segment' if $mode =~ m/^(?:vanilla|invertible)$/; &{"begin_$mode"}; } else { $currentline= $_; &{"line_$mode"}; } } } sub nummap ($) { my ($p) = @_; $p =~ s/\d{1,6}/ sprintf "%06d%d",$&,$& /ge; return $p; } sub writeout () { my (@segs,$segn,$seg,$segr,$pt,$ptv, $delim); my ($comb,$pi,$feat,$featr,$end,$boob); my ($node,$side,$otherend,$nodeotherside,$otherseg,$otherbackrelus); o("/* autogenerated - do not edit */\n\n"); @segs=(); for $seg (sort { nummap($a) cmp nummap($b) } keys %segs) { $segs{$seg}{Num}= @segs; push @segs, $seg; } o(sprintf "#define NUM_TRAINS 1000000\n". "#define NUM_SEGMENTS %s\n\n". "#include \"layout-data.h\"\n\n", scalar @segs); foreach $seg (@segs) { $segr= $segs{$seg}; o("static const SegPosCombInfo spci_${seg}"."[]= {"); $delim=''; for ($comb=0; $comb < $segr->{Posns}; $comb++) { $pi=''; foreach $feat (keys %{ $segr->{Feats} }) { $featr= $segr->{Feats}{$feat}; next if exists $featr->{Fixed}; $pi.= sprintf("%s%d", $feat, ($comb / $featr->{Weight}) % $featr->{Posns}); } o("$delim\n"); o(sprintf " { %-8s %4d", '"'.$seg.(length $pi ? '/' : '').$pi.'",', $segr->{Dist}[$comb]); for ($end=0; $end<2; $end++) { o(", { "); $otherend= $segr->{Ends}[$comb][$end]; defined $otherend or die "$seg $comb $end ?"; ($node,$side) = @$otherend; $nodeotherside= $nodes{$node}[1-$side]; if (defined $nodeotherside) { $otherseg= $nodeotherside->{Seg}; $otherbackrelus= $nodeotherside->{End} ^ $end ^ 1; o(sprintf "/*%5s.%d %-5s*/ %d,%3d", $node,$side, ($otherbackrelus?'-':' ').$otherseg, $otherbackrelus, $segs{$otherseg}{Num}); } else { o(sprintf "/*%5s.%d*/ 0,NOTA(Segment)", $node,$side); } o(" }"); } o(sprintf " }"); $delim= ','; } o("\n};\n"); next unless $segr->{FeatCount}; for $pt (keys %{ $segr->{Feats} }) { $ptv= $segr->{Feats}{$pt}; next if exists $ptv->{Fixed}; o("static const BoardObject mfbo_${seg}_${pt}"."[]= {"); $delim=' '; foreach $boob (@{ $ptv->{BoOb} }) { o($delim); o(so_boob('pt',$boob)); $delim= ', '; } o(" };\n"); } o("static const MovFeatInfo mfi_${seg}"."[]= {"); $delim=''; for $pt (keys %{ $segr->{Feats} }) { $ptv= $segr->{Feats}{$pt}; next if exists $ptv->{Fixed}; o("$delim\n"); o(" { \"$seg/$pt\", mfk_".lc($ptv->{Kind}).",". " $ptv->{Posns}, $ptv->{Weight}, mfbo_${seg}_$pt }"); $delim=','; } o("\n};\n"); } o("const SegmentNum info_nsegments=NUM_SEGMENTS;\n"); o("const SegmentInfo info_segments[NUM_SEGMENTS]= {"); $delim= ''; foreach $seg (@segs) { $segr= $segs{$seg}; o("$delim\n"); o(sprintf " { %-7s %d, %2d,%-9s %3d,%-10s %-6s,%-6s }", "\"$seg\",", $segr->{Inv}, $segr->{FeatCount}, ($segr->{FeatCount} ? "mfi_$seg," : '0,'), $segr->{Posns}, "spci_$seg,", so_oboob('sense',$segr), so_oboob('reverse', $segr->{Inv} ? $segr : undef)); $delim= ','; } o("\n};\n"); } sub writeasm () { my ($k,$w,$i,@d,$or,$p,$portnum,$bit,$each); close STDOUT or die $!; open STDOUT, ">$basename-pindata.asm" or die $!; o("; autogenerated - do not edit\n"); o(" include pindata.inc\n". " radix hex\n". "X equ 0xff\n"); $each= 10; for $k (@objkinds) { for $w (qw(pic port bit)) { @d=(); o("\n"); o("${k}_${w}_data_section org ${k}_${w}_data\n"); for ($i=0; $i<@{ $pin_used{$k} }; $i++) { $or= $pin_used{$k}[$i]; if (defined $or) { $or->[1] =~ m/^(\d+)\,(\w+)$/; ($portnum,$bit)= ($1,$2); $portnum= sprintf "%02x", $portnum + 0x89; # 89=LATA $bit= sprintf "%02x", hex $bit; } else { $portnum=$bit='00'; } if ($w eq 'pic') { if (defined $or) { push @d, $or->[0]; } else { push @d, 'X', } } elsif ($w eq 'port') { push @d, $portnum; } elsif ($w eq 'bit') { push @d, $bit; } else { die; } } push @d, 'X' if @d^1; @d= map { s/^[a-f]/0$&/; sprintf "%3s", $_ } @d; for (;;) { $d[$each/2] = " $d[$each/2]" if $#d >= $each/2; last if @d <= $each; o(" db ". join(',',@d[0..($each-1)]). "\n"); @d= @d[$each..$#d]; } o(" db ".join(',',@d)."\n"); if ($w eq 'pic') { o(" if \$ > ${k}_pic_data + ${k}_num_max\n". " error \"too much ${k}_picdata\"\n". " endif\n". " fill 0xffff, ${k}_pic_data + ${k}_num_max - \$\n"); } } } o("\n end\n"); } mainread(); writeout(); writeasm();