chiark / gitweb /
Send HELLO as a result of all slaves being online. Do not crash if slave is slow...
[trains.git] / detpic / mascan.asm
index 23e80e2f9f1a846c238f663766f7e564ae144f5e..36c16f495fdfed36b1f8f1e6c31ce5d9a7334a06 100644 (file)
@@ -1,11 +1,12 @@
 ;======================================================================
 ; MASTER - SCANNING ETC.
 
- include common.inc
 include common.inc
 
 ;----------------------------------------------------------------------
- udata_acs
 udata_acs
 
+; for reading and detection:
 b      res     1       ; byte just read
 cslot  res     1       ; current slave in slave table, points to flags byte
 cbyte  res     1
@@ -14,46 +15,67 @@ cbyte       res     1
        ;       M0B1 0000       we're expecting more detection byte 1
        ;       M010 0000       we're expecting more detection byte 2
        ;       1000 0000       we're expecting an extra byte
+       ;       ???? ???1       reading halted for any reason:
+cbyte_halted equ 0 ; also set briefly while we decide what to do next
+
+wslave                 res 1 ; slave we need to write to
+outmsg_targetlen       res 1 ;
+
+slaves_awaiting                res 1 ; no. of slaves without stf_responding
+slavenoack_counter     res 2 ; +0=L, +=H
+slavenoack_counter_init equ (i2c_kbitpersec * 100)
+       ; slaves/sec, @ 10clocks/slave
 
-;----------------------------------------------------------------------
-slavetable_section udata 0x280
-
-ste_szln2      equ     3
-       ; each entry is a number of bytes, at these offsets:
-ste_slave      equ     0 ; slave number
-ste_flags      equ     1 ; flags (stf_...)    cslot normally points here
-ste_detbasel   equ     2
-ste_lastd0     equ     3
-ste_lastd1     equ     4
-ste_lastd2     equ     5
-ste_detmsgh    equ     7
-ste_size       equ     (1<<ste_szln2)
-slavetable res maxpics * ste_size
-
-stf_detect     equ     7
-
- code
 ;======================================================================
 ; HANDLING OF I2C EVENTS
 
+near_getwritebyteyes code
+;----------------------------------------
+i2c_getwritebyte_yes @
+       pop             ; we don't care where we were in i2cmu_write_next_byte
+       bc_f    STATUS, Z       ; yes, we want to write this byte
+       return          ; from i2cmu_write_next_byte
+       
+  code
+;----------------------------------------
+i2cmu_write_next_byte
+       Dl 0x91
+       ; add calls to getwritebyte_<foo> here:
+       call    polarity_getwritebyte
+       call    points_getwritebyte
+       ; end of list of calls to getwritebyte_<foo>
+       ; so, no-one wants this slave:
+       bs_f    STATUS, Z
+       return
+
 ;----------------------------------------
-i2cm_intrl
+i2cm_intrl @
 ; handles i2c interrupt using i2cm_interrupt[_definite],
 ; according to the rules for <something>_intrl.
+       Dl 0x90
        bt_f_if0 PIR1, SSPIF
        return
        call    i2cm_interrupt_definite
        intrl_handled_nostack
 
-;----------------------------------------
-i2cmu_done     panic   morse_MD
-
-;----------------------------------------
-i2cmu_write_next_byte
-       panic   morse_UI
-
 ;======================================================================
-; PROCESSING OF INCOMING BYTES
+; PROCESSING OF INCOMING BYTES - CORE AND DETECTION
+
+;--------------------
+read_first_response
+;              on entry                on return
+;  W           received byte           preserved
+;  b           received byte           preserved
+;  FSR0                any                     trashed
+;  STATUS      any                     trashed
+       bs_f    INDF1, stf_responding
+       dec_f_ifnz slaves_awaiting
+       return
+; that's the last slave, excellent
+       mov_lw  b'00001001'     ; W trashed
+       call    serial_addbyte
+       mov_fw  b               ; W =           received byte (again)
+       return
 
 ;----------------------------------------
 i2cmu_read_got_byte
@@ -66,6 +88,11 @@ i2cmu_read_got_byte
                                ; W =           received byte
        mov_wf  b               ; W = b =       received byte
 
+       Dl 0x90
+       Df cslot
+       Df cbyte
+       Df b ; also restores b to W
+
        mov_lfsr slavetable, 1
        mov_ff  cslot, FSR1L    ; FSR1 ->       slave's flags
 
@@ -73,13 +100,26 @@ i2cmu_read_got_byte
        bra     read_got_notfirst
        ; this is a first (head) byte:
 
+       bt_f_if0 INDF1, stf_responding ; seen this PIC ack already ?
+       rcall   read_first_response ; no, we might have to send HELLO
+
        bt_f_if0 POSTINC1, stf_detect ; FSR1 -> detbasel
        bra     read_got_first_reversers
-read_got_first_detectors
+read_got_first_detectors       ; b =           MdBBdddd
        and_lw  0xb0            ; W =           M0BB0000
        mov_wf  cbyte           ; cbyte =       M0BB0000
+       mov_lw  0x4f            ; W =           01001111
+       and_wff b               ; b =           0d00dddd
        mov_fw  POSTINC1        ; W = detbasel; FSR1 -> lastd0
-       rcall   read_prep_detectbyte
+       rcall   read_got_detectbyte_prep ; b =  0d00dddd
+                                        ; u =  0C00CCCC
+       bt_f_if1 b, 6           ; b bit         .d......
+       bs_f    b, 4            ; b =           0d0ddddd
+                               ;                ^ ^ copies of same bit
+                               ; u = (still)   0C00CCCC
+                               ; or, using detection segment bit numbers:
+                               ; b =           z4z43210
+                               ; u =           z4zz3210
        goto    addmsgs_dethead
 
 ;----------
@@ -88,40 +128,66 @@ read_got_first_reversers
        bra     read_got_bad_first_reversers
        and_lw  0x80            ; W =           M0000000
        mov_wf  cbyte           ; cbyte =       M0000000
+       bc_f    b, 7            ; b =           00dddddd
        mov_fw  POSTINC1        ; W = detbasel; FSR1 -> lastd0
-       rcall   read_prep_detectbyte
+       rcall   read_got_detectbyte_prep
        goto    addmsgs_revhead
 
 ;-----
 read_got_bad_first_reversers panic morse_MR
 
 ;----------
-read_got_detectors_b1
+read_got_detectors_b1          ; b =           dddddddd
+;                              ; W = detbasel; FSR1 -> detbasel
+       add_lw  5               ; W = adjdetbasel
+       bs_f    FSR1L, 2        ; FSR1L -> lastd1
        bc_f    cbyte, 4        ; cbyte =       M0B00000
-       mov_fw  POSTINC1        ; W = detbasel; FSR1 -> lastd0
-       inc_f   FSR1L           ; FSR1 -> lastd1
-       add_lw  8               ; W = detbasel+8
-       rcall   read_prep_detectbyte
+       rcall   read_got_detectbyte_prep
        goto    addmsgs_all
 
 ;----------
-read_got_detectors_b2
+read_got_detectors_b2          ; b =           dddddddd
+;                              ; W = detbasel; FSR1 -> detbasel
+       add_lw  13              ; W = adjdetbasel
+       inc_f   FSR1L           ; FSR1 -> lastd0
+       inc_f   FSR1L           ; FSR1 -> lastd2
        bc_f    cbyte,5         ; cbyte =       M0000000
-       mov_fw  POSTDEC1        ; W = detbasel; FSR1 -> flags
-       bs_f    FSR1L, 2        ; FSR1L ->      lastd2
-       add_lw  16              ; W = detbasel+16
-       rcall   read_prep_detectbyte
+       rcall   read_got_detectbyte_prep
        goto    addmsgs_all
 
 ;----------
-read_got_detectbyte_something
-       xor_wfw INDF1           ; lastd<n> =    ?d??dddd
+read_got_detectbyte_prep_ifsomething
+;
+; This is a branch of read_got_detectbyte_prep, called if we're doing
+; `return' rather than `pop+return'.  For conditions on return, see
+; read_got_detectbyte_prep; these are supposed to be (basically) the
+; same as the entry conditions for addmsgs_<kind>.
+;
+;              on entry
+;  W           [C0]*
+;  t           adjdetbasel
+;  u           undefined
+;  b           [d0]*
+;  lastd<n>    [o0]*
+;  FSR1 ->     lastd<n>
+;
+       mov_wf  u               ; u =           [C0]*
+
+       Dl 0x94
+       Df FSR1L
+       Df u ; also restores u to W
+
+       xor_wff INDF1           ; lastd<n> =    [d0]*
+       ; to force test of repeated detection notification,
+       ;  comment out previous line
        mov_lw  0x07
        ior_wff FSR1L           ; FSR1L ->      detmsgh
-       return ; to addmsgs_<something>
+       return ; to addmsgs_<something>, very shortly
 
 ;----------------------------------------
 read_got_notfirst
+;                              ; FSR1 ->       flags
+       mov_fw  PREINC1         ; W = detbasel; FSR1 -> detbasel
        bt_f_if1 cbyte, 4
        bra     read_got_detectors_b1
        bt_f_if1 cbyte, 5
@@ -131,34 +197,40 @@ read_got_notfirst
        bt_f_if0 b, 7           ; any more ?
        bc_f    cbyte, 7
        bc_f    b, 7
-       rcall   process_got_extra
+       call    process_got_extra
        bra     i2c_arrange_next_byte
 
-;----------------------------------------
-process_got_extra
-       mov_fw  b
-loopback_read_byte
-;...
-;  W           message
-       xor_lw  0x00 ^ 0x20
-       bra_z   cdu_got_pointed
-       xor_lw  0x20 ^ 0xb0
-       bra_z   slave_got_aargh
-       panic   morse_MX
-
 ;----------
-read_prep_detectbyte
-;  W           adjusted detbase l
-;  cbyte       set for next byte to read
-;  b           received byte
-;  FSR1 ->     lastd<n>
-;  TOS ->      goto addmsgs_<something>
+read_got_detectbyte_prep
+;
+; Sees if anything has changed.  If no changes pops one return address
+; and branches to i2c_arrange_next_byte; if some changes, returns to
+; calling point.
+;
+; So, caller should be i2cmu_read_got_byte, and next stuff
+; should basically be a call to addmsg_<something> (perhaps preceded
+; by a bit of fiddling of b).  addmsg_<something> will finish
+; by branching to i2c_arrange_next_byte.
+;
+;              call                    return          pop+return
+;  W           adjdetbasel             preserved       undefined
+;  b           [d0]*                   preserved       preserved
+;  FSR1 ->     lastd<n>                detmsgh         preserved
+;  cbyte       set for next read etc.  preserved       preserved
+;  u           undefined               [C0]*           preserved
+;  lastd<n>    [o0]*                   [d0]*           preserved = [d0]*
+;
+;  TOS ->      (optionally, fiddle b, and then:) goto addmsgs_<something>
 ;  NOS         return address for i2cmu_read_got_byte
-       mov_wf  t               ; t =           adj.detbasel
-       mov_fw  b               ; W =           ?d??dddd
-       xor_wfw INDF1           ; lastd<n> =    ?C??CCCC, Z iff same
-       bra_nz  read_got_detectbyte_something
-       xor_wfw INDF1           ; lastd<n> =    ?d??dddd
+;
+       mov_wf  t               ; t =           adjdetbasel
+       Dl 0x93
+       Df INDF1
+       mov_fw  b               ; W =           [d0]*
+       Dv
+       xor_wfw INDF1           ; W =           [C0]*, Z iff same
+                       ;  where C set iff change to that detection segment
+       bra_nz  read_got_detectbyte_prep_ifsomething
        ; there's nothing to do
        pop
 ;...
@@ -171,87 +243,299 @@ i2c_arrange_next_byte
 ; DECIDING WHICH SLAVE TO ADDRESS
 ;...
 i2c_arrange_something
+i2cmu_done
 ; figure out what to do next - which pic to address, etc.
-       panic   morse_UG
+       bs_f    cbyte, cbyte_halted
+
+       tst_f_ifnz wslave       ; anyone asked to write ?
+       bra     arrange_write
+
+       ; Anyone else to write to ?
+       ; add calls to needwrite_<foo> here:
+       call    polarity_needwrite
+       call    points_needwrite
+       ; end of list of calls to needwrite_<foo>
+
+       ; no, if we're here, no-one wants to write:
+
+nextslave_nowrite
+       ; no writing needed, we consider reading:
+       bt_f_if1 flags, flags_polarising
+       return  ; do not scan while booster PWM is off while polarising
+               ; to avoid all trains disappearing and reappearing
+
+       mov_fw  outmsg_begin
+       sub_wfw outmsg_end
+       and_lw  outbuf_size - 1
+       cmp_fw_ifle outmsg_targetlen
+       return ; target len < actual len, do not add anything
+       ; ok, there's space, go ahead:
+       bc_f    cbyte, cbyte_halted
+
+       mov_lw  ste_size
+       add_wff cslot           ; cslot -> next ste_flags
+       mov_lfsr slavetable, 1  ; FSR1H -> slavetable
+       mov_ff  cslot, FSR1L    ; FSR1 -> new ste_flags
+
+       bt_f_if1 POSTDEC1, stf_sentinel ; FSR1 -> ste_slave
+       bra     nextslave_looparound
+       ; Ok, we have a slave:
+
+       Dl 0x91
+       mov_fw  INDF1           ; W = new slave number
+       goto    i2cm_read_start
+
+nextslave_looparound
+       ; now we do our own detection
+       mov_lw  (slavetable + ste_flags) & 0xff ; select our own slot
+       mov_wf  cslot
+       Dl 0x92
+       call    read_detection_head_master
+       goto    i2cmu_read_got_byte
+
+;----------------------------------------
+i2c_needwrite @
+; Informs mascan that we need to write to some slave.
+; Some time after this, mascan will call getwritebyte_<everything>
+; and this must yield at least one byte to write.
+;  W           slave that we must write to
+       mov_wf  wslave
+       bt_f_if0 cbyte, cbyte_halted
+       return ; we're currently doing something
+;...   
+;----------
+arrange_write
+;  wslave      slave to write to
+       bc_f    cbyte, cbyte_halted
+       mov_fw  wslave
+       mov_wf  cwslave
+       clr_f   wslave
+       goto    i2cm_write_start
+
+;----------------------------------------
+i2c_consider_restartread @
+       bt_f_if0 cbyte, cbyte_halted
+       return
+       bra     nextslave_nowrite
+
+;----------------------------------------
+i2cmu_slave_no_ack
+       mov_lfsr slavetable, 1
+       mov_ff  cslot, FSR1L    ; FSR1 -> slave's flags
+       bt_f_if1 INDF1, stf_responding
+       bra     slavenoack_crashed
+
+       dec_f_ifnz slavenoack_counter
+       return
+       dec_f_ifnz slavenoack_counter+1
+       return
+       panic   morse_ST
+
+slavenoack_crashed
+       panic   morse_SC
+
+;======================================================================
+; INITIALISATION
+
+mascan_init @
+       mov_lw  (slavetable + ste_flags) & 0xff
+                ; pretend we've just done us, to start with 1st actual slave
+       mov_wf  cslot
+       clr_f   cbyte
+       bs_f    cbyte, cbyte_halted
+       clr_f   wslave
+
+       mov_lw  slavenoack_counter_init & 0xff
+       mov_wf  slavenoack_counter
+       mov_lw  slavenoack_counter_init >> 8
+       mov_wf  slavenoack_counter+1
+       clr_f   slaves_awaiting
+
+       mov_lw  2
+       mov_lfsr slavetable, 0          ; FSR0 -> slavetable
+       load_tblptr pic2detinfo         ; TBLPTR* -> pic2detinfo
+       clr_f   t                       ; t = loop counter
+mascan_init_loop
+       tblrd_postinc_fixup             ; TABLAT = EOOOOSSS
+       mov_fw  TABLAT                  ; W = EOOOOSSS, N = E
+
+       tblrd_postinc_fixup             ; TABLAT = DSSSSSSS, N (still) = E
+       bra_nn  mascan_init_ifabsent    ;     E.......
+
+       inc_f   slaves_awaiting
+
+       mov_ff  t, POSTINC0             ; ste_slave = slave
+       mov_wf  u                       ; u = 1OOOOSSS
+       and_lw  0x78
+       bra_nz  mascan_bad_detinfo0
+       ; ok                            ; u = 10000SSS
+
+       mov_fw  TABLAT                  ; W = DSSSSSSS
+       and_lw  0x80                    ; W = D0000000
+       mov_wf  POSTINC0                ; ste_flags = D0000000
+
+       mov_fw  TABLAT                  ; W = DSSSSSSS
+       bc_w    7                       ; W = 0SSSSSSS = first
+       add_lw  -0xf8                   ; W = first - 0xf8 = detbasel
+       mov_wf  POSTINC0                ; detbasel
+
+       mov_lw  0x4f                    ; W = 01001111 for det., MM 05 B2 B1...
+       bt_f_if0 TABLAT, 7              ; D ?  otherwise, rev. board:
+       mov_lw  0x3f                    ; W = 01111111 for rev., MM zz 01...
+       mov_wf  POSTINC0                ; lastd0
+       set_f   POSTINC0                ; lastd2
+       set_f   POSTINC0                ; unused
+       set_f   POSTINC0                ; lastd1
+
+       mov_fw  u                       ; W = 10000SSS
+       xor_lw  b'10011000' ^ 0x80      ; W = detmsgh
+       mov_wf  POSTINC0                ; detmsgh
+
+mascan_init_ifabsent
+       inc_f   t                       ; next slave
+       bt_f_if0 t, maxpics_ln2
+       bra     mascan_init_loop
+       ; we've read the whole flash table
+
+  if slavetable == 0x400
+       bt_f_if1 FSR0H, 0
+       bra     mascan_bad_toomany
+  endif
+
+       clr_f   POSTINC0                ; ste_slave
+       mov_lw  (1<<stf_detect)|(1<<stf_sentinel)
+       mov_wf  POSTINC0                ; ste_flags
+       ; rest of final entry, and rest of table, is undefined
+
+       ; at 9600, it's about 1ms per char.
+       ; we allow 1ms to scan 2 pics via i2c.
+       ; so our target len is (no of pics)/2
+       ; plus 2 bytes of slop
+       rl_fw   t
+       add_lw  2
+       mov_wf  outmsg_targetlen
+
+       return
+
+mascan_bad_detinfo0 panic morse_DF
+mascan_bad_toomany panic morse_DG
+
+;======================================================================
+; PROCESSING OF INCOMING BYTES - EXTRA (NON-DETECTION)
+
+near_gots code
+;----------------------------------------
+process_got_extra @
+       mov_fw  b
+loopback_read_byte @
+;...
+;  W           message
+       xor_lw  0x00 ^ 0x20
+       bra_z   got_pointed
+       xor_lw  0x20 ^ 0xb0
+       bra_z   got_aargh
+       panic   morse_MX
 
 ;======================================================================
 ; GENERATION OF DETECTION MESSAGES FOR HOST - MAD BT_F_IF1 TABLES
 
-addmsg_testbit macro bit
-       bt_f_if1 w, bit
-       rcall   addmsg
+addmsg_testbit macro addmsg_macro_bit
+       bt_f_if1 u, addmsg_macro_bit
+       rcall   addmsg_one
        endm
 
-addmsg_return macro dummy_bit
-       return
-       mov_lw  dummy_bit ; makes disassembly a bit clearer than a nop
+addmsg_return macro dummy_addmsg_macro_bit
+       goto    i2c_arrange_next_byte
        endm
 
-addmsg_ignore macro dummy_bit
+addmsg_ignore macro dummy_addmsg_macro_bit
        nop
        nop
        endm
 
-addmsg_padding macro dummy_bit
+addmsg_padding macro dummy_addmsg_macro_bit
        nop
-       mov_lw  dummy_bit
+       mov_lw  dummy_addmsg_macro_bit
        endm
 
-addmsgs_section code 0x2100 + 6*4
+;----------------------------------------
+;addmsgs_<kind>
+;
+;                      on entry        after first addmsg_one, or when done
+;  W, STATUS, v, FSR0  undefined       trashed
+;  t                   adjdetbasel     not modified by addmsgs_<kind> or _one
+;  u                   [C0]*           not modified by addmsgs_<kind> or _one
+;  b                   [d0]*           not modified by addmsgs_<kind> or _one
+;  lastd<n>            [d0]* (new)     not modified by addmsgs_<kind> or _one
+;  FSR1 ->             detmsgh         not modified by addmsgs_<kind> or _one
+;  outbuf, outmsg_*    not full, updated appropriately
+;  all others          any             not interfered with
+;  
+; (this is all set up by read_prep_detectbyte and
+;  read_got_detectbyte_prep_ifsomething)
+; when done, branches to i2c_arrange_next_byte, rather than returning
 
-addmsgs_dethead        addmsg_testbit  6
-               addmsg_ignore   7
-               addmsg_testbit  0
+addmsgs_section code (         7       )*4 + 0x2100
+;
+;                              A
+;                              |- PCL bbb value after macro - number in this
+;                              V       column should increment 1 each line
+;
+addmsgs_revhead        addmsg_testbit  0
                addmsg_testbit  1
                addmsg_testbit  2
                addmsg_testbit  3
-               addmsg_return   4
+               addmsg_testbit  4
+               addmsg_testbit  5
+               addmsg_return   6
 
-addmsgs_all    addmsg_testbit  5
-               addmsg_testbit  6
-               addmsg_testbit  7
+addmsgs_all    addmsg_testbit  7
                addmsg_testbit  0
                addmsg_testbit  1
                addmsg_testbit  2
                addmsg_testbit  3
                addmsg_testbit  4
-               addmsg_return   5
-
-               addmsg_padding  6
-               addmsg_padding  7
+               addmsg_testbit  5
+               addmsg_testbit  6
+               addmsg_return   7
 
-addmsgs_revhead        addmsg_testbit  0
+addmsgs_dethead        addmsg_testbit  0
                addmsg_testbit  1
                addmsg_testbit  2
                addmsg_testbit  3
-               addmsg_testbit  4
-               addmsg_testbit  5
-               addmsg_return   6
+               addmsg_testbit  6 ; bit 6 was copied to 4 but only in b, not u
+               addmsg_return   5
 
 ;----------
-addmsg
-;  TOS - 4 ->  bt_f_if1 w, <some bit>
-; other conditions set up by read_prep_detectbyte
-; and read_got_detectbyte_something
-;  t           adj.detbasel
-;  
+addmsg_one
+;  TOS - 4 ->  bt_f_if1 u, b'bbb'
+;  TOSL                ???bbb00
+; other conditions on entry and exit as for entry to addmsgs_<kind>, above
+       Dl 0x95
+       Df TOSL
        rr_fw   TOSL            ; W =           0???bbb0
-       and_fw  0x0e            ; W =           0000bbb0
-       rr_w                    ; W =           00000bbb
-       set_f   FSR0L           ; FSR0L =       11111111
-       and_wff FSR0L           ; FSR0L =       11111bbb
-       clr_f   FSR0H           ; FSR0 -> bitnum2bit[b]
-       add_wff t               ; t =           detect msg low byte
-       mov_fw  INDF1           ; W =           1 001 0 SSS
-       mov_wf  u               ; u =           1 001 0 SSS
-       mov_fw  b               ; W =           ?d??dddd
-       and_wfw INDF0           ; W =           .....d..,  Z iff detect
-       bt_f_if1 STATUS, Z
-       bs_f    u, 3            ; u =           1 001 Y SSS
-       mov_fw  u
-       rcall   serial_addbyte
-       mov_fw  t
+       rr_w                    ; W =           00???bbb
+       ior_lw  0xf8            ; W =           11111bbb
+       mov_wf  FSR0L           ; FSR0L =       11111bbb
+       clr_f   FSR0H           ; FSR0 ->       bitnum2bit[bbb]
+       add_wfw t               ; W =           adjdetbasel + 11111bbb
+                               ;  ie =         0 SSSSSSS (det msg low byte)
+       mov_wf  v               ; v =           0 SSSSSSS (det msg low byte)
+       bra_n   addmsg_bad
+
+       mov_fw  b               ; W =           [d0]*
+       and_wfw INDF0           ; train: W = 0x00, Z=1; none: W = 0*d0*, Z=0
+       bt_f_if0 STATUS, Z
+       mov_lw  0x08            ; train: W = 0 000 0 000; none: W = 0 000 1 000
+       xor_wfw INDF1           ; W =           1 001 Y SSS (det msg high byte)
+       Dv
+       call    serial_addbyte
+
+       mov_fw  v               ; W =           0 SSSSSSS (det msg low byte)
+       Dv
        goto    serial_addbyte_another
 
+addmsg_bad panic morse_DJ
+
 ;======================================================================
- include final.inc
 include final.inc