;======================================================================
; MASTER - SCANNING ETC.
- include common.inc
- code
+ include common.inc
+
+;----------------------------------------------------------------------
+ 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
+ ; one of the following:
+ ; 0000 0000 we're expecting the first byte
+ ; 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
;======================================================================
+; 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
+;======================================================================
+; 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_done
i2cmu_read_got_byte
-i2cmu_write_next_byte
- panic morse_UI
+; Beforehand At call
+; State Reading Reading-Wait
+; W data from slave
+;
+; See detect.asm head comment for protocol info, in particular
+; the meaning of these bytes.
+ ; 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
+
+ tst_f_ifnz cbyte
+ 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 ; 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_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
+
+;----------
+read_got_first_reversers
+ bt_f_if1 b, 6
+ 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_got_detectbyte_prep
+ goto addmsgs_revhead
+
+;-----
+read_got_bad_first_reversers panic morse_MR
+
+;----------
+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
+ rcall read_got_detectbyte_prep
+ goto addmsgs_all
+
+;----------
+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
+ rcall read_got_detectbyte_prep
+ goto addmsgs_all
+
+;----------
+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>, 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
+ bra read_got_detectors_b2
+ ; it must be an extra byte
+
+ bt_f_if0 b, 7 ; any more ?
+ bc_f cbyte, 7
+ bc_f b, 7
+ call process_got_extra
+ bra i2c_arrange_next_byte
+
+;----------
+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 = 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
+;...
+;----------------------------------------
+i2c_arrange_next_byte
+ tst_f_ifnz cbyte
+ goto i2cm_read_another
+;...
+;======================================================================
+; DECIDING WHICH SLAVE TO ADDRESS
+;...
+i2c_arrange_something
+i2cmu_done
+; figure out what to do next - which pic to address, etc.
+ 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 addmsg_macro_bit
+ bt_f_if1 u, addmsg_macro_bit
+ rcall addmsg_one
+ endm
+
+addmsg_return macro dummy_addmsg_macro_bit
+ goto i2c_arrange_next_byte
+ endm
+
+addmsg_ignore macro dummy_addmsg_macro_bit
+ nop
+ nop
+ endm
+
+addmsg_padding macro dummy_addmsg_macro_bit
+ nop
+ mov_lw dummy_addmsg_macro_bit
+ endm
+
+;----------------------------------------
+;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_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_testbit 4
+ addmsg_testbit 5
+ addmsg_return 6
+
+addmsgs_all addmsg_testbit 7
+ addmsg_testbit 0
+ addmsg_testbit 1
+ addmsg_testbit 2
+ addmsg_testbit 3
+ addmsg_testbit 4
+ addmsg_testbit 5
+ addmsg_testbit 6
+ addmsg_return 7
+
+addmsgs_dethead addmsg_testbit 0
+ addmsg_testbit 1
+ addmsg_testbit 2
+ addmsg_testbit 3
+ addmsg_testbit 6 ; bit 6 was copied to 4 but only in b, not u
+ addmsg_return 5
+
+;----------
+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
+ 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