6 $basename= @ARGV ? $ARGV[0] : 'safety';
7 die if $basename =~ m/^\-/;
8 $basename =~ s/\.wiring$//;
10 our ($mistakes, $currentline);
13 # ->{BoOb}{Kind} 'pt' 'sense' 'reverse' 'waggle'
16 # ->{BoOb}{Indiv} for `indiv' board objects like wagglers
17 # $segs{$seg}{InvBoOb}
20 # $segs{$seg}{FeatCount} does not include Fixed
21 # $segs{$seg}{FeatCountFixed}
22 # $segs{$seg}{Feats}{$feat}{Kind} Point, Fixed, or Relay
23 # $segs{$seg}{Feats}{$feat}{Weight} ) for Point or Relay only
24 # $segs{$seg}{Feats}{$feat}{Posns} ) for Point or Relay only
25 # $segs{$seg}{Feats}{$feat}{BoObs}[] ) for Point or Relay only
26 # $segs{$seg}{Feats}{$feat}{Fixed} position, for Fixed only
27 # $segs{$seg}{FeatMap}[]{Abstract} as from ours.m4
28 # $segs{$seg}{FeatMap}[]{Concrete} as in ours.wiring, for safety:movpos.c
29 # $segs{$seg}{FeatMap}[]{UsedAbstract}
30 # $segs{$seg}{FeatMap}[]{UsedConcrete}
31 # $segs{$seg}{Inter}{Seg} ) calculated
32 # $segs{$seg}{Inter}{Map} ) in writeout
35 # $segs{$seg}{Ends}[$combpos][$end] = [ $node,$side ]
36 # $segs{$seg}{Dist}[$combpos]
39 # $interfs[]{Invert} = $invert
40 # $interfs[]{Segs}[] = "$seg/$posre" "/.*" added during parsing if necc.
43 # $nodes{$node}[$side]{Seg}
44 # $nodes{$node}[$side]{End}
46 our ($maxptixln2) = 5;
47 our ($maxwaggleixln2) = 4;
49 our ($nextboardnum,@boardtype,@sensesin,$maxreverseobjnum);
50 our (@reversersboardnum,@sensesbase,@objkinds,%pin_used);
51 # $boardtype[$boardnum]
54 # $reversersboardnum[$boardnum] # undef => none; -1 => not yet determined
55 # $sensesbase[$boardnum]= ($page << 7) | $baselsbyte
56 # $pin_used{$objkind}[$objnum] = [ $boardnum, $pin_info, $objonboard ]
59 @objkinds= qw(pt sense reverse waggle);
61 our (%kind_count,%pin_info,%pin_info_indiv); # from BOARD.pin-info
63 our ($mode,$invertible);
67 # $sensepermute{$boardtype}[$objonboard]= $offset
69 sub sensepermute_bitmap ($$$) {
70 my ($kind,$base,$mapstring) = @_;
72 my (@map)= split /\s+/, $mapstring;
77 next if $objnum =~ m/[a-z]/i;
78 $objnum =~ m/^\d\d$/ or die "$kind $objnum ($bitnum) ?";
80 die "$kind $objnum ($bitnum from $base)" if
81 defined $sensepermute{$kind}[$objnum];
82 $sensepermute{$kind}[$objnum]= $bitnum;
83 #print STDERR "SPM $kind $objnum $bitnum\n";
88 sensepermute_bitmap('reversers', 0, 'MM zz 01 02 03 00 04 05');
89 sensepermute_bitmap('detectors', 0, 'MM 05 B2 B1 10 13 16 08');
90 sensepermute_bitmap('detectors', 5, '19 09 12 15 18 04 20 17');
91 sensepermute_bitmap('detectors', 13, '06 01 07 02 11 14 03 00');
95 mistake("first input line does not determine phase");
99 our (%syntaxerror_once);
100 return if exists $syntaxerror_once{$mode};
101 $syntaxerror_once{$mode}= 1;
102 mistake("syntax error");
108 print STDERR "info: ditching $m\n";
111 sub seg_wiring ($$$) {
112 my ($seg,$feat,$hash) = @_;
113 if (!exists $segs{$seg}) {
114 foreach my $bo (@{ $hash->{BoObs} }) {
117 ditch("unwired segment for wired point $seg/$feat");
120 mistake("duplicate wiring for $seg/$feat")
121 if exists $segs{$seg}{Feats}{$feat};
122 if (exists $hash->{Posns}) {
123 $hash->{Weight}= $segs{$seg}{Posns};
124 $segs{$seg}{Posns} *= 2;
125 $segs{$seg}{FeatCount}++;
127 $segs{$seg}{Feats}{$feat}= $hash;
130 sub begin_points () { }
132 my ($seg,$pt,@boobstr,$bodef,@boobs);
133 m,^\s+(\w+)/([A-Za-z]+)\s+((\d+)\.\d+)\s+(\d*\.\d+)$, or
134 return syntaxerror();
135 ($seg,$pt,$boobstr[0],$bodef,$boobstr[1])=($1,$2,$3,$4,$5);
136 $boobstr[1] =~ s/^\./$bodef./;
137 @boobs= map { pa_boob('pt',$_) } @boobstr;
138 seg_wiring($seg,$pt, {
145 sub begin_relays () { }
147 my ($seg,$rly,$waggle);
148 m,^\s+(\w+)/([A-Za-z]+)\s+([1-9]\d*|0)\.(\w+)$, or return syntaxerror();
149 ($seg,$rly)= ($1,$2);
150 $waggle= { Kind => 'waggle', Board => $3, Indiv => $4 };
151 seg_wiring($seg,$rly, {
154 BoObs => [ $waggle ],
158 sub begin_fixed () { }
160 my ($seg,$feat,$pos);
161 m,^\s+(\w+)/([A-Za-z]+)(\d+)$, or return syntaxerror();
162 ($seg,$feat,$pos)=($1,$2,$3);
163 seg_wiring($seg,$feat, {
167 $segs{$seg}{FeatCountFixed}++;
170 sub begin_segment () { }
171 sub line_segment () {
172 my ($seg,$boobstr,$boob);
173 m/^\s+(\w+)\s+(\d+\.\d+)$/ or return syntaxerror();
174 ($seg,$boobstr)=($1,$2);
175 mistake("duplicate topology for segment $seg") if exists $segs{$seg};
176 $boob= pa_boob('sense', $boobstr);
179 InvBoOb => $invertible ? { Kind => 'reverse',
180 Board => $boob->{Board},
181 Obj => $boob->{Obj} } : undef,
187 &{"line_segment_".($invertible?'invertible':'vanilla')}($boob);
190 sub begin_endwiring () {
193 sub begin_boards () {
197 m/^\s+(\d+)\s+(\w+)$/ or return syntaxerror();
198 ($num,$type)=($1,$2);
199 mistake("board $num when expected $nextboardnum")
200 if $num != $nextboardnum;
203 $boardtype[$num]= $type;
204 require "./$type.pin-info";
206 my ($sense_count, $page);
207 $sense_count= $kind_count{$type}{'sense'};
209 $sensesin[$page] + $sense_count > 128;
211 mistake("too many senses for encoding scheme")
214 if $page > $#sensesin;
216 $sensesbase[$num]= ($page << 7) | $sensesin[$page];
217 $sensesin[$page] += $sense_count;
219 &{"line_boards_$type"}($num);
222 sub line_boards_reversers { }
223 sub line_boards_detectors { }
224 sub line_segment_vanilla ($) { }
225 sub line_segment_invertible ($) {
227 $reversersboardnum[ $boob->{Board} ]= -1;
230 sub begin_interferences () {
232 sub line_interferences () {
233 s/^\s+// or return syntaxerror();
234 my ($is) = [ split /\s+/, $_ ];
236 if ($is->[0] eq '-') {
241 $invert ^= 1 if s/^\-//;
242 s,$,/.*, unless m,/,;
244 return syntaxerror() if grep { !m,^\w+/, } @$is;
245 push @interfs, { Invert => $invert, Segs => $is };
248 # We read the movfeatmap and write out most things in the output to
249 # have the concrete (RHS) version; the exception is layout-data.c
250 # SegPosCombInfo.pname.
252 # The FeatMap is a bidirectional mapping constructed from "movfeatposmap"
253 # lines, a map between ([A-Za-z]+[0-9]+)* and ([A-Za-z]+[0-9]+)*.
255 # It has two effects:
256 # - in line_endwiring, used "forwards"
257 # - when writing out .pname, used "backwards"
258 # in each case we match only whole feature positions by regexp tricks
259 # we record whether a mapping entry was used, and complain if not
261 sub begin_movfeatposmap () { }
262 sub line_movfeatposmap () {
263 my ($segr,$abstr_namebase,$abstr_firstpos,$abstr_lastpos,$conc_posns) =
264 m,^\s+(\w+)\s+([A-Za-z]+)(\d+)(?:\-(\d+))?((?:\s+(?:[A-Za-z]+\d+)*)+)$,;
265 defined $segr or return syntaxerror();
267 $abstr_lastpos= $abstr_firstpos unless defined $abstr_lastpos;
268 my $nabstr_posns= $abstr_lastpos - $abstr_firstpos + 1;
270 $conc_posns =~ s/^\s+//;
271 my (@conc_posns) = split /\s+/, $conc_posns;
273 my $seg= $segs{$segr};
275 ditch("movfeatposmap for unwired segment".
276 " $segr/$abstr_namebase$abstr_firstpos".
277 ($nabstr_posns>1 ? "-$abstr_lastpos" : ""));
281 @conc_posns == $nabstr_posns
282 or return mistake("number of concrete poscombs ".@conc_posns.
283 " differs from number of abstract poscombs".
285 for (my $i=0; $i<@conc_posns; $i++) {
286 push @{ $seg->{FeatMap} }, {
287 Abstract => $abstr_namebase.($abstr_firstpos+$i),
288 Concrete => $conc_posns[$i],
296 print STDERR "mistake: $m\n in $mode, \`$currentline'\n";
302 print STDERR "mistake: $m\n";
306 sub movfeatposmap ($$$$$) {
307 my ($subspecr, $segr, $entfrom, $entto, $call) = @_;
308 my $featmap= $segr->{FeatMap};
309 return unless $featmap;
311 foreach my $mapent (@$featmap) {
314 (?<! [A-Za-z] ) $mapent->{$entfrom} (?! \d )
315 /$mapent->{$entto}/x;
316 $mapent->{"Used$entfrom"}++;
321 sub movfeatposmap_checks () {
322 foreach my $seg (keys %segs) {
323 my $segr= $segs{$seg};
324 my $featmap= $segr->{FeatMap};
325 next unless $featmap;
326 foreach my $mapent (@$featmap) {
327 foreach my $chk (qw(Abstract Concrete)) {
328 next if $mapent->{"Used$chk"};
329 endmistake("movfeatposmap entry $seg $mapent->{Abstract}".
330 " $mapent->{Concrete} unused for \L$chk lookup");
337 sub line_endwiring () {
338 my (@ns,$seg,$subspec,$dist);
339 my ($segr,@subsegil,$feat,$pos,$featr,$combpos,%featposwant);
340 my ($end,$node,$side,$nsr,$endposr);
341 m,^\s*segment\s+(\w+\.\d+)\s+(\w+\.\d+)\s+(\w+)(?:/((?:[A-Za-z]+\d+)+)\*\d+)?\s+([0-9.]+)$, or return syntaxerror();
342 ($ns[0],$ns[1],$seg,$subspec,$dist)=($1,$2,$3,$4,$5);
343 if (!exists $segs{$seg}) {
344 ditch("unwired $seg".(defined $subspec ? "/$subspec" : ""));
349 if (defined $subspec) {
350 $desc .= "/$subspec";
351 movfeatposmap(\$subspec, $segr, Abstract, Concrete, sub {
353 $desc .= "[$mapent->{Concrete}]";
356 @subsegil= defined $subspec ? $subspec =~ m/([A-Za-z]+)(\d+)/g : ();
358 ($feat,$pos,@subsegil) = @subsegil;
359 if (!exists $segr->{Feats}{$feat}) {
360 mistake("no wiring for $seg/$feat");
363 $featr= $segr->{Feats}{$feat};
364 if (exists $featr->{Fixed}) {
365 if ($pos != $featr->{Fixed}) {
366 ditch("fixed-elsewise $desc");
370 mistake("position $seg/$feat$pos exceeds wiring")
371 unless $pos < $featr->{Posns};
372 $featposwant{$feat}= $pos;
376 for $feat (keys %{ $segr->{Feats} }) {
377 $featr= $segr->{Feats}{$feat};
378 next if exists $featr->{Fixed};
379 mistake("wiring $seg/$feat not covered by $desc"),next
380 if !exists $featposwant{$feat};
381 $combpos += $featposwant{$feat} * $featr->{Weight};
383 mistake("duplicate topology subseg for $desc")
384 if defined $segs{$seg}{Dist}[$combpos];
385 $segs{$seg}{Dist}[$combpos]= $dist;
386 $endposr= $segr->{Ends}[$combpos];
387 die "$seg $combpos ".(map { "@$_" } @$endposr)." ?"
388 if defined $endposr && @$endposr;
389 for ($end=0; $end<2; $end++) {
390 $ns[$end] =~ m/^([a-z]\w+)\.([01])$/;
391 ($node,$side)=($1,$2);
392 $nsr= $nodes{$node}[$side];
393 if (!exists $nsr->{Seg}) {
394 $nodes{$node}[$side]= { Seg => $seg, End => $end };
396 $seg eq $nsr->{Seg} or
397 mistake("topology for $node.$side both $seg and $nsr->{Seg}");
398 $end == $nsr->{End} or
399 mistake("topology for $node.$side $seg both ends ($end".
400 " and also $nsr->{End})");
402 $segr->{Ends}[$combpos][$end]= [ $node, $side ];
407 print STDOUT $_[0] or die $!;
411 my ($kind,$str) = @_;
412 if ($str !~ m/^([1-9]\d*|0)\.([1-9]\d*|0)$/) {
413 mistake("invalid board object $str");
414 return { Kind => $kind, Board => 0, Obj => 0 };
416 return { Kind => $kind, Board => $1, Obj => $2 };
419 # boob2objnum_KIND($boob,$boardnum,$objnum,$boardtype,$mkused ...)
420 # -> global object number
422 sub boob2objnum_waggle {
423 my ($boob,$boardnum,$obj) = @_;
424 mistake("waggle encoding out of range") if
425 $boardnum >= (1 << (9 - $maxwaggleixln2));
426 die if $obj >= (1 << $maxwaggleixln2);
427 # waggle command is 1010 1sss OSS wwwwV
428 # so waggler objnum is sss SS wwww
429 $boardnum= (($boardnum & 0x07) << 2) | ($boardnum >> 3);
430 return ($boardnum << $maxwaggleixln2) | $obj;
434 my ($boob,$boardnum,$obj)=@_;
435 mistake("point encoding out of range") if
436 $boardnum >= (1 << (10 - $maxptixln2));
437 die if $obj >= (1 << $maxptixln2);
438 return ($boardnum << $maxptixln2) | $obj;
441 sub boob2objnum_reverse {
442 my ($boob,$orgboardnum,$obj,$boardtype)=@_;
443 # Converts board and object number (in canonical pic number plus
444 # and reverse0...reverse5 as seen on pinout diagrams), to the
445 # segment number for POLARITY command numbered as shown in
448 # There are three basic stages:
450 # * We invert the on-board mapping; ie, we untangle the
451 # tangling between the message from master to slave pic
452 # and the actual pins (see reverse.asm, polarity_local_do)
454 # * We figure out which bit of which message byte the
455 # object corresponds to. (see reverse.asm, command_polarity)
457 # * We compute the README.protocol segment number.
459 my ($cycle,$boardincycle,$cyclebasebyte,$byte,$bit,$boardnum,$rv);
460 $boardnum= $reversersboardnum[$orgboardnum];
461 die "$orgboardnum $boardnum" unless defined $boardnum;
462 die "$orgboardnum $boardnum" unless $boardnum >= 0;
463 die unless $boardtype eq 'reversers';
464 die $obj if $obj > 5;
465 #print STDERR "data2safety $boardnum.$obj ";
466 $obj = sprintf '%d', $obj;
467 $obj =~ y/302154/543210/; # mapping due to polarity_do_here
468 #print STDERR " obj=$obj";
469 $cycle= int(($boardnum+3) / 7);
470 #print STDERR " cycle=$cycle";
471 $boardincycle= ($boardnum+3) - $cycle*7;
472 #print STDERR " boardin=$boardincycle";
473 $cyclebasebyte= $cycle*6 - 2;
474 #print STDERR " baseby=$cyclebasebyte";
475 if ($boardnum==2 && $obj > 2) {
476 $byte= 0; $bit= $obj-3;
477 $rv= 3 - $bit; # only these three in byte 0, a special case;
478 #print STDERR " special bit=$bit => $rv\n";
480 } elsif ($boardincycle<5) {
481 $byte= $cyclebasebyte + $boardincycle; $bit= $obj + 1;
482 } elsif ($boardincycle==6) {
483 $byte= $cyclebasebyte + 5; $bit= $obj + 1;
484 } elsif ($boardincycle==5) {
485 $byte= $cyclebasebyte + 5 - $bit; $bit= 0;
489 $rv= $byte*7 + 3 - $bit;
490 #print STDERR " ordinary byte=$byte bit=$bit => $rv\n";
494 sub boob2objnum_sense {
495 my ($boob,$boardnum,$obj)= @_;
496 my $type= $boardtype[$boardnum];
497 my $bitnum= $sensepermute{$type}[$obj];
498 die "$type $obj ($boardnum)" unless defined $bitnum;
499 my $base= $sensesbase[$boardnum];
500 my $inpage= $base & 0x7f;
501 die if $inpage+$bitnum > 127;
502 return $base+$bitnum;
505 sub boob2objnum ($$) {
506 my ($mkused,$boob) = @_;
507 my ($kind,$boardnum,$type);
508 $kind= $boob->{Kind};
509 $boardnum= $boob->{Board};
511 #print STDERR "boob2objnum($mkused, ", Dumper($boob), " )\n";
512 $type= $boardtype[$boardnum];
513 return &{"boob2objnum_$kind"}
514 ($boob, $boardnum, $boob->{Obj}, $type, $mkused);
520 $objnum= boob2objnum(0, $boob);
521 return $pin_used{$boob->{Kind}}[$objnum];
524 sub boob_used_bit ($) {
526 return defined boob_used($boob) ? 1 : 0;
531 #print STDERR ">$board<\n";
532 mistake("unknown board number $board") unless defined $boardtype[$board];
533 return $boardtype[$board];
536 sub kind2genkind ($) {
538 return 'indiv' if $k eq 'waggle';
542 sub boob2genkind ($) {
544 return kind2genkind($boob->{Kind});
548 my ($mkused,$bo, $objnum_rr) = @_;
549 my ($type,$objnum,$pi,$genkind);
551 my ($kind,$board,$obj) = map { $bo->{$_} } qw(Kind Board Obj);
552 #print STDERR "so_boob >$kind|$board$obj<\n";
553 $genkind= boob2genkind($bo);
554 #print STDERR "so_boob >$board|$obj<\n";
555 $type= boardtype($board);
556 $pi= $pin_info{$type}{$genkind};
557 mistake("object reference $genkind ($kind) $board.$obj out of range".
558 " for board type $type")
559 unless defined $pi->[$obj];
560 #print STDERR "so_boob >$kind|$board $obj|$pi->[$obj]<\n" if $kind eq 'waggle';
561 $objnum= boob2objnum($mkused,$bo);
562 #print "so_boob >$objnum_rr|$$objnum_rr< = $objnum\n";
563 $$objnum_rr= $objnum;
564 $pin_used{$kind}[$objnum]= [ $board, $pi->[$obj], $obj ]
566 return sprintf("%#5x /* %d.%-*d*/", $objnum, $board,
567 $kind eq 'reverse' ? 1 : 2, $obj);
569 #print "so_boob >$objnum_rr|$$objnum_rr< -\n";
570 return " 0 /*none*/ ";
574 sub so_objboob ($$;$) {
575 my ($mkused,$obj,$objnum_rr) = @_;
576 return so_boob($mkused, defined $obj ? $obj->{BoOb} : undef,
588 if (m/^(invertible|vanilla|points|relays|fixed|endwiring|boards|interferences|movfeatposmap)$/) {
590 $invertible= ($mode eq 'invertible');
591 $mode= 'segment' if $mode =~ m/^(?:vanilla|invertible)$/;
600 sub redact_indir ($$) {
603 #print STDERR "redact ", Dumper($r), "\n";
604 return unless exists $r->{Indiv};
608 #print STDERR "redact >$board|$indiv<\n";
609 my $boardtype= boardtype($board);
610 if (defined $pin_info_indiv{$boardtype}{$indiv}) {
611 $r->{Obj}= $pin_info_indiv{$boardtype}{$indiv};
613 mistake("unknown pin name $boardtype.$indiv for $what");
618 sub record_phys_pin_used ($$) {
619 my ($r,$whatfor) = @_;
620 my ($board,$obj,$kind,$type,$pi);
621 our (%phys_pin_used);
623 return if $obj==0 && $mistakes; # false positives, otherwise
625 $kind= kind2genkind($r->{Kind});
626 $type= $boardtype[$board];
627 $whatfor .= " ($r->{Kind} $kind $obj)";
628 $pi= $pin_info{$type}{$kind}[$obj];
629 $pi =~ m/^([01234]),(\d),/ or die $!;
630 my ($port,$bit)=($1,$2);
631 if (exists $phys_pin_used{$board,$pi} &&
632 $phys_pin_used{$board,$pi} ne $whatfor) {
633 mistake("board $board physical pin ".
634 "R".(qw(A B C D E)[$port]).$bit.
635 " ($pi) used more than once:\n".
636 " $phys_pin_used{$board,$pi};\n".
639 $phys_pin_used{$board,$pi}= $whatfor;
643 my ($num,$mappednum,$i,$objnum);
644 $maxreverseobjnum= 0;
645 for ($num=0, $mappednum=0; $num<@boardtype; $num++) {
646 next unless defined $reversersboardnum[$num];
647 die if $reversersboardnum[$num] != -1;
648 $reversersboardnum[$num]= $mappednum;
649 for ($i=0; $i<6; $i++) {
650 $objnum= boob2objnum(0, { Kind => 'reverse',
653 $maxreverseobjnum= $objnum+1 if $objnum >= $maxreverseobjnum;
657 my ($seg,$segr,$feat,$featr,$board,$indir,$boardtype,$why);
658 foreach $seg (keys %segs) {
660 foreach $feat (keys %{ $segr->{Feats} }) {
661 $featr= $segr->{Feats}{$feat};
663 $why= "segment $featr->{Kind} $seg/$feat";
664 redact_indir($_,$why);
665 record_phys_pin_used($_, $why);
666 } @{ $featr->{BoObs} };
673 $p =~ s/\d{1,6}/ sprintf "%06d%d",$&,$& /ge;
678 return sprintf "s%s", $_[0];
682 my (@segs,$segn,$seg,$segr,$feat,$featv, $delim);
683 my ($comb,$pi,$end,$boob);
684 my ($node,$side,$otherend,$nodeotherside,$otherseg,$otherbackrelus);
685 my ($ourinter,$pcname,$intere,$intother,$fixedi);
686 o("/* autogenerated - do not edit */\n\n");
688 for $seg (sort { nummap($a) cmp nummap($b) } keys %segs) {
689 $segs{$seg}{Num}= @segs;
693 "#define NUM_SEGMENTS %s\n\n".
694 "#include \"layout-data.h\"\n\n",
699 foreach $seg (@segs) {
700 o(sprintf "#define s%-4s %4d\n", $seg, $segnum);
705 foreach $seg (@segs) {
708 o("static const SegPosCombInfo spci_${seg}"."[]= {");
711 $segr->{Inter}{Map}= 0;
712 $segr->{Inter}{Invert}= 0;
713 $ourinter= $segr->{Inter};
714 for ($comb=0; $comb < $segr->{Posns}; $comb++) {
716 foreach $feat (sort keys %{ $segr->{Feats} }) {
717 $featv= $segr->{Feats}{$feat};
718 next if exists $featv->{Fixed};
719 $pi.= sprintf("%s%d", $feat,
720 ($comb / $featv->{Weight}) % $featv->{Posns});
723 movfeatposmap(\$pi_abstr, $segr, Concrete, Abstract, sub { });
726 my $dist= $segr->{Dist}[$comb];
727 o(sprintf " { %-7s%4d, { ",
729 defined($dist) ? $dist : 1);
730 for ($end=0; $end<2; $end++) {
733 $otherend= $segr->{Ends}[$comb][!$end];
734 if (!defined $otherend) {
735 die "segment $seg combination $comb end $end undefined\n"
737 o(" 0,NOTA(Segment)");
739 ($node,$side) = @$otherend;
740 $nodeotherside= $nodes{$node}[1-$side];
741 if (defined $nodeotherside) {
742 $otherseg= $nodeotherside->{Seg};
743 $otherbackrelus= $nodeotherside->{End} ^ $end;
744 o(sprintf "/*%4s.%d*/ %d,%4s",
747 so_segnum($otherseg));
749 o(sprintf "/*%5s.%d*/ 0,NOTA(Segment)",
759 for $intere (@interfs) {
760 my ($inter)= $intere->{Segs};
762 if ($pcname =~ m/^$_$/) {
768 for $intother (@$inter) {
769 $intother =~ m,^(\w+)/, or die "$intother ?";
772 endmistake("unknown segment $1 in interference");
773 if (defined $ourinter->{Seg}) {
774 $1 eq $ourinter->{Seg} or
775 endmistake("unsupported complicated interference ".
776 "involving $seg, $1, $ourinter->{Seg}");
778 $ourinter->{Seg}= $1;
779 $ourinter->{Invert}= $intere->{Invert};
782 endmistake("unsupported too-moveable interference")
784 $ourinter->{Map} |= 1 << $comb;
789 next unless $segr->{FeatCount} || $segr->{FeatCountFixed};
791 for $feat (keys %{ $segr->{Feats} }) {
792 $featv= $segr->{Feats}{$feat};
793 next if exists $featv->{Fixed};
794 o("static const BoardObject mfbo_${seg}_${feat}"."[]= {");
796 foreach $boob (@{ $featv->{BoObs} }) {
798 o(so_boob(1, $boob));
804 o("static const MovFeatInfo mfi_${seg}"."[]= {");
806 for $fixedi (qw(0 1)) {
807 for $feat (keys %{ $segr->{Feats} }) {
808 $featv= $segr->{Feats}{$feat};
809 next if $fixedi != !!exists $featv->{Fixed};
811 o(" { \"$feat\", mfk_".lc($featv->{Kind}).",");
813 o(" $featv->{Posns}, $featv->{Weight}, mfbo_${seg}_$feat");
815 o(" $featv->{Fixed}, 0, 0");
823 for $intere (@interfs) {
825 warn "warning: unused interference specification $_\n" unless m, ,;
826 } @{ $intere->{Segs} };
829 my (@sensemap,$sensenum,$i);
830 o("const SegmentNum info_nsegments=NUM_SEGMENTS;\n");
831 o("const SegmentInfo info_segments[NUM_SEGMENTS]= {");
834 foreach $seg (@segs) {
837 my $sensesoboob= so_objboob(1, $segr, \$sensenum);
838 o(sprintf " { %-7s%d,%d,%2d,%d,%-9s%d,%-10s%-6s,%-7s",
839 "\"$seg\",",$segr->{InvBoOb}?1:0,$segr->{Inter}{Invert},
840 $segr->{FeatCount}, $segr->{FeatCountFixed},
841 ($segr->{FeatCount}||$segr->{FeatCountFixed}) ? "mfi_$seg," : '0,',
842 $segr->{Posns}, "spci_$seg,",
844 so_boob(1, $segr->{InvBoOb}).',');
845 $ourinter= $segr->{Inter};
846 if (defined $ourinter->{Seg}) {
847 o(sprintf "%4s,0%o ", so_segnum($ourinter->{Seg}),
854 endmistake("sense $sensesoboob used for both".
855 " $seg and $sensemap[$sensenum]")
856 if defined $sensemap[$sensenum];
857 $sensemap[$sensenum]= $seg;
861 o("const BoardObject info_maxreverse= $maxreverseobjnum;\n");
863 o("const SegmentNumInMap info_segmentmap[]= {\n");
865 foreach $seg (@sensemap) {
867 !($i % 12) ? ",\n " :
869 o(defined($seg) ? sprintf("%4s",so_segnum($seg)) : ' u');
874 "const int info_segmentmaplen= ".scalar(@sensemap).";\n");
880 my ($sec,$docstring) = @_;
885 sub o_section_end_fill ($$$) {
886 my ($lastnumdone, $fillvalue, $entrysize) = @_;
887 if ($entrysize == 1 and $lastnumdone & 1) {
888 o(", $fillvalue & 0xff\n");
893 o(sprintf " fill %s, %d*(maxpics-%d)\n\n",
894 $fillvalue, $entrysize, $lastnumdone);
898 my ($ix,$every) = @_;
899 $every=16 unless defined $every;
900 o(($every ? $ix % $every : $ix) ? ',' : "\n db ");
905 o_section('pic2detinfo',<<'END');
906 ; Table indexed by pic no., giving information about sensing
907 ; Each element is two bytes:
908 ; 1st byte bit 7 Set iff this board exists for the purposes of sensing
909 ; bits 6-3 Not used, set to zero
910 ; bits 2-0 Top 3 bits of sense segment numbers on this board
911 ; 2nd byte bit 7 Set iff this board is a Detectors board
912 ; bits 6-0 Base for bottom 7 bits of segment number
913 ; (per-board segment no. is added to this; carry
914 ; to upper 3 bits is not permitted)
916 o("SenseExists equ 0x80\n".
917 "Detectors equ 0x80\n".
918 "Reversers equ 0x00\n\n");
919 for ($num=0; $num<@boardtype; $num++) {
920 if (!defined $boardtype[$num]) { o(" dw 0\t\t\t\t; $num\n"); next; }
921 $base= $sensesbase[$num];
922 o(sprintf " db SenseExists | 0x%02x, %12s | 0x%02x\t; %d\n",
923 $base >> 7, ucfirst($boardtype[$num]), $base & 0x7f, $num);
925 o_section_end_fill($num, 0, 2);
928 sub writeasm_pt ($$) { writeasm_ptwag('pt',$maxptixln2); }
929 sub writeasm_waggle ($$) { writeasm_ptwag('waggle',$maxwaggleixln2); }
930 sub writeasm_ptwag ($$) {
931 my ($ptwag, $maxthingixln2) = @_;
932 my $bitmapbitsperpic= 1<<$maxthingixln2;
933 my $bitmapbytesperpic= 1<<($maxthingixln2-3);
934 my ($num, $elemsize, $byte, $bit, $objnum);
936 o_section("picno2${ptwag}map",<<"END");
937 ; Bitmap indexed first by pic no, and then by thing no. on that board,
938 ; saying whether the thing is present or not. Each pic has
939 ; $bitmapbytesperpic bytes, ie $bitmapbitsperpic bits. First byte is
940 ; objects 0 to 7, in bits 0 to 7 respectively so that MSbit of byte 3
941 ; (4th byte) is object no.31. Unused boards or boards with no such
942 ; objects are all-bits-0.
944 for ($num=0; $num<@boardtype; $num++) {
945 if (!defined $boardtype[$num]) { o(" dw 0\t\t\t\t; $num"); next; }
946 die if $maxthingixln2 < 4; # must be whole no. of 16-bit words
947 $elemsize= $bitmapbytesperpic;
948 for ($byte=0; $byte < $elemsize; $byte++) {
951 for ($bit=7; $bit>=0; $bit--) {
952 o(boob_used_bit({ Kind => $ptwag,
954 Obj => $byte*8 + $bit }));
961 o_section_end_fill($num, 0, $elemsize);
963 my ($typeix,$type,$pi,$indexpr);
964 $indexpr= '0'x(7-$maxthingixln2). 'D'. 'o'x$maxthingixln2;
965 o_section("bk${ptwag}ix2portnumbitnum",<<"END");
966 ; Table giving physical ports and pins for each $ptwag for each
967 ; kind of board. Index is object number (for reversers boards)
968 ; or object number + 2^$maxthingixln2 (for detectors boards).
969 ; Value is one byte, either 0xff meaning that board type has
970 ; no such object, or top nybble being port number (0 for A, 1 for B,
971 ; etc.) and bottom nybble being bit number. Ie,
972 ; Index: $indexpr where D is 1 iff detectors board and o is obj
973 ; Value: 0ppp0bbb where p is port num and b is bit num; or 0xff
976 for ($typeix=0; $typeix<2; $typeix++) {
977 $type= qw(reversers detectors)[$typeix];
978 die $type unless $pin_info{$type};
980 for ($objnum=0; $objnum < (1 << $maxthingixln2); $objnum++) {
982 $pi= $pin_info{$type}{kind2genkind($ptwag)}[$objnum];
984 $pi =~ m/^(\d)\,(\d)\,/ or die;
995 sub writeasm_reverse {
996 my ($num,$kc,$bit, @portae,$pu);
997 o_section('picno2revmasks',<<END);
998 ; Table listing which reversers are connected/enabled. Index is pic
999 ; number. Each entry is 2 bytes: mask for port A followed by mask for
1000 ; port E. A 1 bit is a connected reverser. Both masks are 0 for
1001 ; non-reversers boards.
1003 for ($num=0; $num<@boardtype; $num++) {
1005 $kc= $kind_count{$boardtype[$num]}{'reverse'};
1006 for ($bit= $kc-1; $bit>=0; $bit--) {
1007 $pu= boob_used({ Board => $num,
1009 Kind => 'reverse' });
1011 $pu->[1] =~ m/^([04])\,\d,(0x\w{2})$/ or die;
1012 push @{ $portae[!!$1] }, $2;
1015 o(join(', ', map { @$_ ? join('|',@$_) : '0' } @portae));
1016 o(sprintf " ; %d\n",$num);
1018 o_section_end_fill($num, '0x0000', 2);
1022 my ($k,$w,$i,@d,$or,$p,$portnum,$bit,$each);
1023 close STDOUT or die $!;
1024 open STDOUT, ">$basename+pindata.asm" or die $!;
1025 o("; autogenerated - do not edit\n");
1026 o(" include pindata.inc\n".
1030 for $k (@objkinds) {
1037 close STDOUT or die $!;
1038 open STDOUT, ">$basename.dgram.segmap-info" or die $!;
1039 o("# autogenerated - do not edit\n");
1040 foreach my $seg (keys %segs) {
1041 my $segr= $segs{$seg};
1042 my $featmap= $segr->{FeatMap};
1043 next unless $featmap;
1044 foreach my $mapent (@$featmap) {
1045 o("layout-subseg-featmap $seg $mapent->{Abstract}");
1046 local ($_) = $mapent->{Concrete};
1047 s/([A-Z]+)(\d+)/ o(" $1 $2"); ""; /ge;
1048 die "$seg $_ ?" if length;
1059 movfeatposmap_checks();
1060 exit 1 if $mistakes;