Each byte after the first contains 7 more R bits. The first R bit
(most significant R bit in the first byte) corresponds to track
-detection segment 1; The next bit (2nd most significant bit in the
-first byte) corresponds to track detection segment 2; and so on.
+reversal segment 1; The next bit (2nd most significant bit in the
+first byte) corresponds to track reversal segment 2; and so on.
-Bits which do not correspond to defined track detection segments will
-be sent as 0 by the host but may be ignored by the PICs. The host
-must send exactly as many bytes as are necessary to include all of the
-defined segments.
+Bits which do not correspond to defined reversal segments will be
+ignored by the PICs. The host must send exactly as many bytes as are
+necessary to include all of the reversal segments for each reversers
+board (for every potential reversal segment, regardless of whether
+that segment is a defined segment corresponding to some actual track).
-For example, if there are 14 detection segments (numbered 1 to 14)
+For example, if there are 14 reversible segments (numbered 1 to 14)
then the following message
1 0010 000 1 000 1000 0 111 1010 Actual message
(E RRR) (E RRR RRRR) (E RRR R---) } helpful annotations
1 111 1111 } and commentary
123 456 7890 123 4567 }
specifies to reverse segments 7 and 11 to 14. The trailing bits are
-for segments 15 to 17 and are ignored.
+for segments 15 to 17 and are ignored. (Note that the assignment of
+physical segments to segment numbers is complex due to bit-twiddling.
+see detpic/reverse.asm and layout/data2safety.)
The PIC will reply to POLARITY with POLARISED when the polarity change
is complete. The host must not send another POLARITY until then.
;======================================================================
-; DETECTION
+; DETECTION AND SLAVE I2C
; FSR1 is used as pointer to where to add bytes of message; it
; points to previous byte whose top bit must be set before
; to be the same as last time (initially: 0)
; zz is a zero bit
; MM indicates that there are extra message byte(s)
+; two digits indicates that the bit is the corresponding
+; detection information. The bit is clear iff current
+; was detected since the last poll by the master.
+; The bit value is not defined for unused sense
+; segments.
;
; Following that are the zero, one or two more bytes of
-; detection data,
-; X and Y indicate that further detection bytes exist
-; M indicates that more
+; detection data:
+; 19 09 12 15 18 04 20 17 iff reversers and B1 was set
+; 06 01 07 02 11 14 03 00 iff reversers and B2 was set
+;
+; Finally, zero or more bytes of extra messages:
+; MM XX XX XX XX XX XX XX
+; where
+; MM indicates that further extra message bytes follow;
+; it is clear iff this is the last extra message byte.
+; XX are the lower 7 bits of a POLARISED or POINTED
+; message (see README.protocol).
+
+; Master may also write to slave. Every written byte is independent:
+;
+; 11RRRRRR Set reverse to RRRRRR, see reverse.asm
;======================================================================
; variables and memory organisation
return
+init_bitnum2bit
+; populate bitnum2bit
+ mov_lw 0x80
+ mov_lfsr bitnum2bit,0
+init_bitnum2bit_loop
+ rl_w
+ mov_wf POSTINC0
+ bra_nn init_bitnum2bit_loop
+ return
+
include final.inc
DW ; slave write (nyi)
DQ FSR2L,outmsg_end ; previous slave read incomplete
DR FSR2L,outmsg_end ; slave read overrun
+
+# Messages for specific peripherals
+PS FSR0L ; POLARITY message too short
+PL FSR0L ; POLARITY message too long
--- /dev/null
+;======================================================================
+
+
+board0 res 1
+gather res 1
+
+polarities_waiting res 1
+ ; no of 11... entries in reversers_commanded_buffer
+
+reversers_commanded_buffer res 32
+ ; Each byte is:
+ ; 11RRRRRRR reverse command for slave pic
+ ; 000000001 this pic is not a reversers pic
+ ; 000000000 have sent any relevant POLARITY
+ ; 000000002 sentinel
+
+;----------
+polarity_decode_message
+; message format
+; SS zz zz SS ZZ 2f 2e 2d g is board 2
+; MM 2c 0f 0e 0d 0c 0b 0a board 0
+; MM 2b 1f 1e 1d 1c 1b 1a board 1
+; MM 2a 3f 3e 3d 3c 3b 3a g, board 2, complete, also 3
+; MM 9f 4f 4e 4d 4c 4b 4a g is board 9
+; MM 9e 5f 5e 5d 5c 5b 5a
+; MM 9d 6f 6e 6d 6c 6b 6a
+; MM 9c 7f 7e 7d 7c 7b 7a
+; MM 9b 8f 8e 8d 8c 8b 8a
+; MM 9a af ae ad ac ab aa
+; etc.
+; where
+; SS bit set
+; zz bit zero
+; other things are <board><segment> where <segment>
+; is a for LSb in message to PIC, b for next bit,
+; and so on until f for bit 5. (See polarity_do_here, below.)
+;
+ mov_lfsr message_buffer_start,0
+ mov_lfsr reversers_commanded_buffer,1
+ mov_fw POSTINC0 ; W = 10010RRR
+ mov_wf gather ; gather = 10010ggg
+ xor_lw 0b10001000 ; gather = 00011ggg
+loop ; exit from this loop is done by board popping and returning
+ rrc_fw INDF0 ; W = ?Mhhhhhh C = g
+ rlc_f gather ; gather = 0*11g+ C = ?
+ bra_nn if_not_gathered
+ ; ; gather = 11gggggg
+ mov_fw gather
+ rcall board
+ mov_lw 0b00000011 ; W = 00000011
+ mov_wf gather ; gather = 00000011
+if_not_gathered ; *INDF0 = Mhhhhhhg
+ rr_fw INDF0 ; W = gMhhhhhh
+ or_lw 0b11000000 ; W = 11hhhhhh
+ rcall board
+ bt_f_if1 POSTINC0,7 ; *POSTINC0 : M.......
+ bra loop
+ ; otherwise:
+ panic morse_PS
+
+;----------
+board
+ mov_wf INDF1 ; *(this pic) = 11RRRRRR
+ ; FSR1 -> pic we've just filled
+;...
+board_next_loop
+ dec_fw PREINC1 ; FSR1 -> pic after one we're testing
+ ; W = 1??????? existing reverse command
+ ; 00000000 not a reversers pic
+ ; ffffffff no existing command
+ ; 00000001 sentinel
+ bra_z board_next_loop ; not a reversers pic
+ bra_nn board_next_none ; sentinel
+
+ bt_f_if0 INDF1,7 ; 1....... existing command
+ ; 0....... no existing command
+ inc_f polarities_waiting
+ return
+
+;----------
+board_next_none
+ bt_f_if1 INDF0,7 ; *INDFO : M.......
+ bra board_next_none_more_message
+;...
+; now we're exiting from the loop in when_reverse_message_found
+ pop
+ return
+
+
+;----------
+polarity_do_here
+; W here polarity SS SS v3 v0 v2 v1 v5 v4
+ mov_wf input ; input = SS SS v3 v0 v2 v1 v5 v4
+
+ mov_wf LATE ; W = kk kk kk kk kk kk o5 o4
+ xor_wfw input ; W = ?? ?? ?? ?? ?? ?? d5 d4
+ and_wfw maske ; W = zz zz zz zz zz zz d5 d4
+ xor_wff LATE ; LATA = kk kk kk kk kk kk v5 v4
+
+ bc_f input,2 ; input = SS SS v3 v0 v2 v1 zz v4
+ bt_f_if1 input,4 ; input : .. .. .. v0 .. .. .. ..
+ bs_f input,2 ; input = SS SS v3 v0 v2 v1 v0 v4
+
+ mov_wf LATA ; W = kk kk r3 kk r2 r1 r0 kk
+ xor_wfw input ; W = ?? ?? r3 ?? r2 r1 r0 ??
+ and_wfw maska ; W = zz zz r3 zz r2 r1 r0 zz
+ xor_wff LATA ; LATE = kk kk r3 kk r2 r1 r0 kk
+ return
outbuf_size equ (1<<outbuf_szln2)
outbuf res outbuf_size
+ udata 0x0f8 ; bottom byte is all-bits-set except for 3 bitnum bits
+bitnum2bit res 8 ; bitnum2bit[x] = 1<<x
+
include final.inc
;======================================================================
# $nodes{$node}[$side]{Seg}
# $nodes{$node}[$side]{End}
-our ($nextboardnum,@objkinds,@boardobjbase,@boardtype,%pin_used);
+our ($nextboardnum,@boardtype,%numboards,$nreverses);
# @boardtype[$boardnum]
+# $numboards{$type}
+# $nreverses
# $boardobjbase[$boardnum]{$kind}
-# %pin_used{$objkind}[$objnum] = [ $boardnum, $pin_info, $objonboard ]
$nextboardnum= 0;
+$nreverses= 0;
@objkinds= qw(pt sense reverse);
map { $boardobjbase[0]{$_}= 1; } @objkinds;
$nextboardnum++;
require "./$type.pin-info";
$boardtype[$num]= $type;
- foreach $k (@objkinds) {
- $boardobjbase[$nextboardnum]{$k}=
- $boardobjbase[$num]{$k} + $kind_count{$type}{$k};
+ $numboards{$type}++;
+ if ($type eq 'reversers') {
+ my ($i,$objnum);
+ for ($i=0; $i<5; $i++) {
+ $objnum= so_boob('reverse', [ $num,$i ]);
+ $nreverses= $objnum+1 if $objnum >= $nreverses;
+ }
}
}
return [ $1,$2 ];
}
+# so_boob_KIND($boardnum,$boardtype,$objnum) -> global object number
+
+sub so_boob_pt($$$) {
+ my ($boardnum,$boardtype,$obj)=@_;
+ die if $boardnum>31 || $obj>31;
+ return ($boardnum << 5) | $obj;
+}
+
+sub so_boob_reverse($$$) {
+ my ($boardnum,$boardtype,$obj)=@_;
+
+ # Converts board and object number (in canonical pic number plus
+ # and reverse0...reverse5 as seen on pinout diagrams), to
+ # object number for POLARITY command numbered as shown in
+ # README.protocol.
+ #
+ # There are three basic stages:
+ #
+ # * We invert the on-board mapping; ie, we untangle the
+ # tangling between the message from master to slave pic
+ # and the actual pins (see reverse.asm, polarity_do_here)
+ #
+ # * We figure out which bit of which message byte the
+ # object corresponds to. (see reverse.asm, polarity_decode_message)
+ #
+ # * We compute the README.protocol bit and byte number.
+
+ my ($cycle);
+ mistake("reversable segment on non-reversers board $board")
+ unless $boardtype eq 'reversers';
+ mistake("reversable segment out of range")
+ unless unless $obj>=0 && $obj<6;
+ $obj = sprintf '%d', $obj;
+ $obj =~ y/302154/543210/; # mapping due to polarity_do_here
+ $cycle= int(($boardnum+3) / 7);
+ $boardincycle= ($boardnum+3) - $cycle*7;
+ $cyclebasebyte= $cycle*6 - 2;
+ if ($boardnum==2 && $obj > 2) {
+ $byte= 0; $bit= $obj-3;
+ return 3 - $bit; # only these three in byte 0, a special case
+ } elsif ($boardincycle<5) {
+ $byte= $cyclebasebyte + $boardincycle; $bit= $obj;
+ } elsif ($boardincycle==6) {
+ $byte= $cyclebasebyte + 5; $bit= $obj;
+ } elsif ($boardincycle==5) {
+ $byte= $cyclebasebyte + 5 - $bit; $bit= 6;
+ } else {
+ die;
+ }
+ return $byte*7 + 3 - $bit;
+}
+
+sub so_boob_sense($$$) {
+ my ($boardnum,$boardtype,$obj)=@_;
+
+ die 'unimplemented';
+}
+
sub so_boob ($$) {
- my ($k,$bo) = @_;
+ my ($kind,$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".
+ $objnum= &{"so_boob_$kind"}($board,$type,$obj);
+ $pi= $pin_info{$type}{$kind};
+ mistake("object reference $kind $board.$obj out of range for".
" board type $type")
unless defined $pi->[$obj];
- $pin_used{$k}[$objnum]= [ $board, $pi->[$obj], $obj ];
+ $pin_used{$kind}[$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);
+ my ($kind,$obj) = @_;
+ return so_boob($kind, defined $obj ? $obj->{BoOb} : undef);
}
sub mainread () {
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("
+# $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+)\,\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();
extern const TrainNum info_nsegments;
extern const TrainInfo info_trains[];
+extern const BoardObject info_nreverses; /* max. reverse + 1 */
+
#define NOTA(x) (~(x##Num)0)
#endif /*LAYOUT_DATA_H*/
$cpin++;
} elsif (s/^[ABCDE]\s+//) {
$port= ord($&) - ord('A');
- } elsif (s/^([0-9a-f][0-9a-f])\s+//) {
+ } elsif (s/^([0-7])\s+//) {
die unless defined $port;
- $pins[$cpin++]= "$port,0x$1";
+ $pins[$cpin++]= sprintf "%d,%d,0x%02x",
+ $port, $1, 1 << $1;
} else {
die "$_ ?";
}
__DATA__
# 1..20
-
-A 01 02 04 08 10 20
-E 01 02 04
+A 0 1 2 3 4 5
+E 0 1 2
- - -
-A 40
-C 01 02 04 08
-D 01 02
-# 21..40
-D 04 08
-C 10 20 40 80
-D 10 20 40 80
+A 6
+C 0 1 2 3
+D 0 1
+# 21..6
+D 2 3
+C 4 5 6 7
+D 4 5 6 7
- -
-B 01 02 04 08 10 20 40 80
+B 0 1 2 3 4 5 6 7