chiark / gitweb /
Send HELLO as a result of all slaves being online. Do not crash if slave is slow...
[trains.git] / detpic / panic.asm
index 69ff7a7a4c3dc329430dd0fd605ddc6184ebf168..663d7fe443fe2b33109e52aba34b013fe1d5e871 100644 (file)
-; program writes SOS msg into flash then turns LED green
-; when serial interrupt received, turns off interrupts, turns off
-; power, transmits contents of SSPCON1 by flashing LED red, repeats
-; (next version will transmit SOS code first, then contents of 
-; SSPCON1)
-
-
-; to start, need to write into flash, starting at 30 0000h:
-; 10 10 10 00 | 1110 1110 | 1110 00 10 | 10 10
+;======================================================================
+; panic.asm
+;
+; This file implements panic_routine, which is called by the
+; `panic' macro in panic.inc.  See panic.inc for the functionality
+; of `panic'.
 
        include common.inc
 
 ;---------------------------------------------------------------------------
 ; reserved access bank locations
 
-WREG2          equ     00h     ; a 2nd working reg :-)
-WREG3          equ     01h     ; a 3rd working reg :-)
-WREG4          equ     02h     ; a 4th working reg :-)
-BLANK          equ     03h     ; register full of zeros
-TESTFLASH      equ     04h     ; test LED flash pattern
+  udata_acs
 
+psave_intcon   res     1
+psave_bsr      res     1
 
+panicst                                res     1
+panicst_restart_i2c            equ     7
+panicst_acked                  equ     5
+panicst_ferroerr               equ     4
+panicst_writeslave             equ     3
+panicst_i2cmours               equ     2
+panicst_i2cmenable             equ     1
 
-;---------------------------------------------------------------------------
-; memory location definitions
+panic_valcount                 res     1
 
-ERROR_BUF_PAGE equ     3       ; error codes on flash p3
-F_ERROR_U      equ     30h     ; upper part of error memory locations
-F_SOS_H                equ     00h     ; high (middle) part of SOS error memory loc.
-F_SOS_L                equ     00h     ; lower part of SOS error memory loc.
+panic_vars_section udata 0x060 + maxpics ; not available via access bank
+; used in panic routine for temporary storage:
 
+flash_pattern          res     1
+morse_counter          res     1
+register_counter       res     1
+bit_counter            res     1
 
-;---------------------------------------------------------------------------
-; error messages
+panic_address  res     1       ; condensed form of message start addr.
+panic_morse    res     1       ; # bytes of morse msg in panic readout
+panic_regs     res     1       ; # registers in panic readout
+
+t0l_count      res     1
+t0h_count      res     1
 
-err_SOS        equ     0       ; msg 0 = SOS
+psave_latc     res     1
+psave_t                res     1
+psave_tablat   res     1
+psave_tblptr   res     3
+psave_fsr0     res     2
+psave_fsr1     res     2
+psave_prod     res     2
+psave_stkptr   res     1
+
+stack_depth    equ     31
+panic_stack    res     stack_depth*3
 
 ;****************************************************************************
 
-        code
+pan_ code
+
 ;****************************************************************************
 
-;----------------------------------------
-readout
-; Flashes the per-pic led red and black in a specified pattern.
+
+panic_routine @
+; switch off interrupts and power
+; reconfigure timer0 for writing diagnostic msg to the LED
+
+       mov_ff  INTCON, psave_intcon
+       bc_f    INTCON, GIEH   ; disable all interrupts
+
+       mov_ff  BSR, psave_bsr
+       banksel flash_pattern
+
+       mov_ff  LATC, psave_latc
+
+; now we have time to save registers etc
+; (turning off interrupts is urgent (we might get interrupted while
+;  panicing which would be bad because we might forget to panic).
+
+        mov_wf   panic_address
+
+       mov_ff  t, psave_t
+       mov_ff  TABLAT, psave_tablat
+       mov_ff  TBLPTRL, psave_tblptr
+       mov_ff  TBLPTRH, psave_tblptr+1
+       mov_ff  TBLPTRU, psave_tblptr+2
+       mov_ff  FSR0L, psave_fsr0
+       mov_ff  FSR0H, psave_fsr0+1
+       mov_ff  FSR1L, psave_fsr1
+       mov_ff  FSR1H, psave_fsr1+1
+       mov_ff  PRODL, psave_prod
+       mov_ff  PRODH, psave_prod+1
+       mov_ff  STKPTR, psave_stkptr
+
+       mov_lfsr panic_stack + stack_depth*3 - 1, 0
+       mov_lw  stack_depth
+       mov_wf  STKPTR
+stacksave_loop
+       mov_ff  TOSU, POSTDEC0
+       mov_ff  TOSH, POSTDEC0
+       mov_ff  TOSL, POSTDEC0
+       dec_f_ifnz STKPTR
+       bra     stacksave_loop
+
+       clr_f    STKPTR         ; avoids stack overruns
+       clr_f   panicst
+
+       call    panic_kill_hook
+
+; re-initialise timer0 config, etc.
+       call    read_pic_no
+       bra_z   panic_setup_if_master
+       ; must be slave:
+
+panic_setup_if_slave
+       movlw   (1<<TMR0ON) | morse_slave_t0scale
+       movwf   T0CON
+       movlw   morse_slave_t0inith
+       movwf   t0h_count
+       movlw   morse_slave_t0initl
+       movwf   t0l_count
+
+       bra     panic_setup_endif_masterslave
+
+panic_setup_if_master
+       movlw   (1<<TMR0ON) | morse_master_t0scale
+       movwf   T0CON
+       movlw   morse_master_t0inith
+       movwf   t0h_count
+       movlw   morse_master_t0initl
+       movwf   t0l_count
+
+       pin_l   p0_booster_userfault
+
+       mov_lw  0x0b ; AAARGH
+       bt_f_if1 TXSTA, TXEN
+       call    serial_write_char
+;...
+panic_setup_endif_masterslave
+
+; get # bytes of morse msg, # registers in panic readout, message start addr.
+; back from condensed message start addr. stored in panic_address
+
+panic_loop
+       mov_lw  4 ; size of each message's details
+       mul_wf  panic_address
+       mov_ff  PRODL,TBLPTRL           
+       mov_ff  PRODH,WREG
+       add_lw  (morse_messages_start)/256
+       mov_wf  TBLPTRH
+       clr_f   TBLPTRU
+
+       tblrd   *+              ; read 1st byte of error message
+                               ; (gives # bytes morse, # bytes registers)
+       dw      0xffff ; silicon errata: B4 issue 4
+
+       mov_ff  TABLAT,panic_morse
+       mov_lw  00001111b
+       and_wff panic_morse     ; panic_morse now contains # bytes of morse msgs
+
+       mov_ff  TABLAT,panic_regs
+       mov_lw  01110000b
+       and_wff panic_regs
+       swap_f  panic_regs      ; panic_regs now contains # registers to read
+
+       call    led_black
+       rcall   waiting16
+       rcall   morsemsg        ; transmit morse in red
+       call    led_black
+       rcall   waiting8
+       rcall   waiting4
+       rcall   registermsg     ; transmit contents of registers in 
+                               ; red(=low) and blue(=high)
+       rcall   waiting16
+        bra    panic_loop
+
+;****************************************************************************
+; PANIC SUBROUTINES
+
+morsemsg
+; wrapper round morse_readout to flash the per-pic led red for a morse msg
+
+morse_msg_start
+       clr_f           morse_counter           ; clear loop counter
+
+morse_loop
+       mov_fw          panic_morse
+       cmp_fw_ifge     morse_counter           ; if loop counter >=panic_morse
+       return                                  ; return to panic
+
+       tblrd           *+
+       mov_ff          TABLAT,flash_pattern
+       rcall           morse_readout
+       inc_f           morse_counter
+       bra             morse_loop
+
+
+;--------------------------
+morse_readout
+
+; Flashes the per-pic led and black in a specified pattern.
+;
 ; The pattern is specified as the state for 8 identically-long time
 ; periods each as long as a morse `dot', encoded into a byte with
 ; most significant bit first.
-;              On entry                On exit
-; W            any                     undefined
-; WREG2                flash pattern           preserved
-; WREG4                any                     undefined
-;
-       clrf    WREG4,0         ; clear loop counter (WREG4)
-       rrncf   WREG2,1
+;                      On entry                On exit
+; W                    any                     undefined
+; flash_pattern                flash pattern           preserved
+; bit_counter          any                     undefined
+
+       mov_lw          9
+       mov_wf          bit_counter
+       rr_f            flash_pattern
 
-readout_loop
-       movlw   8
-       cpfslt  WREG4,0         ; if loop counter >=8, return
+morse_readout_loop
+       dec_f_ifz       bit_counter             ; done all the bits yet ?
        return
+       ; No:
 
-       rlncf   WREG2,1         ; top bit goes into N flag, ie Negative if 1
-       bn      readout_if_led_on
-readout_if_led_off
-        call   led_black
-       bra     readout_endif_led
+       rl_f            flash_pattern           ; top bit goes into N, 
+                                               ;ie Negative if 1
+       bra_n           morse_readout_if_led_1
 
-readout_if_led_on
-       call    led_red
-readout_endif_led
-       incf    WREG4,1,0       ; increment loop counter
-       call    waiting
-       bra     readout_loop
+morse_readout_if_led_0
+        call           led_black
+       bra             morse_readout_endif_led
 
+morse_readout_if_led_1
+       call            led_red
 
-;****************************************************************************
-; this is what happens when we panic
+morse_readout_endif_led
+       rcall           waiting
+       bra             morse_readout_loop
 
-informative_panic
-; switch off interrupts and power
-; reconfigure timer0 for writing diagnostic msg to the LED
+;--------------------------
+;--------------------------
+registermsg
 
-        clrf    INTCON,0        ; disable all interrupts EVER
-        bcf     PORTC,1,0       ; switch off booster
+register_msg_start
+       clr_f           register_counter        ; clear loop counter
 
-       movlw   10101100b
-       movwf   TESTFLASH
+register_loop
+       mov_fw          panic_regs
+       cmp_fw_ifge     register_counter        ; if loop counter >=panic_regs
+       return                                  ; return to panic
 
+       tblrd           *+
 
-; re-initialise timer0 config
-        bcf     T0CON,6,0       ; p107 Timer0 -> 16bit mode
-        bcf     T0CON,5,0       ; timer0 use internal clock
-        bcf     T0CON,3,0       ; use prescaler
-        bsf     T0CON,2,0       ; }
-        bcf     T0CON,1,0       ; } prescale value 1:32 (13ms x 32)
-        bcf     T0CON,0,0       ; }
+       mov_fw          TABLAT          ; TABLAT has the 8-bit version
+       mov_wf          FSR0L           ; of the address.  So, 8 bits
+                                       ; go straight into FSR0L.
+
+       mov_lw          0x0f            ; For FSR0H, we see if the
+       mov_fw          FSR0H           ; address XX is >=0x60.
+                                       ; If it is then we meant 0xfXX;
+       mov_lw          0x5f            ; if not then we meant 0x0XX.
+       cmp_fw_ifle     FSR0L           ; (This is just like PIC does
+       clr_f           FSR0H           ; for insns using Access Bank)
+
+       mov_ff          INDF0,flash_pattern
+       rcall           register_readout
+
+       inc_f           register_counter        ;increment loop counter
+
+       rcall           waiting8
+       bra             register_loop
+
+;--------------------------
+
+register_readout
+
+; Flashes the per-pic led red(0) and green(1) in a specified pattern.
+; (black gap between each bit)
+;
+; The pattern is specified as the state for 8 identically-long time
+; periods each as long as a morse `dot', encoded into a byte with
+; most significant bit first.
+;                      On entry                On exit
+; W                            any                     undefined
+; flash_pattern                flash pattern           preserved
+; bit_counter          any                     undefined
+
+        clr_f          bit_counter             ; clear loop counter
+        rr_f           flash_pattern
+
+
+register_readout_loop
+        mov_lw         8
+        cmp_fw_ifge    bit_counter             ; if loop counter >=8 (register 
+                                               ; length), return
+        return
+
+        mov_lw         4
+        cmp_fw_ifne    bit_counter     ; if loop counter !=4 (nybble length), 
+                                       ; skip insertion of extra black space
+       bra             not_nybble_boundary
+       rcall           waiting4
+
+not_nybble_boundary
+        rl_f           flash_pattern           ; top bit goes into N flag, 
+                                               ; ie Negative if 1
+        bra_n          register_readout_if_led_1
+
+register_readout_if_led_0
+        call           led_red
+        bra            register_readout_endif_led
+
+register_readout_if_led_1
+        call           led_green
+
+register_readout_endif_led
+        inc_f          bit_counter       ; increment loop counter
+        rcall          waiting
+        call           led_black
+        rcall          waiting
+        bra            register_readout_loop
 
-       clrf    BLANK,0
-panic_loop
-;      errmsg  err_SOS,0       ; transmit SOS in red
-       movff   TESTFLASH,WREG2
-       rcall   readout
-;      readout BLANK,0         ; transmit blank buffer
-       call    led_green
-       call    waiting
-        goto    panic_loop
 
 ;****************************************************************************
 ; GENERAL SUBROUTINES
 
 ;----------------------------------------
+waiting16      rcall   waiting8
+waiting8       rcall   waiting4
+waiting4       rcall   waiting2
+waiting2       rcall   waiting
 waiting
 ; waits for a fixed interval, depending on the configuration of TMR0
 
-        bcf     INTCON,2,0      ; clear timer0 interrupt bit (p109)
-        clrf    TMR0H,0         ; p107 set high byte of timer0 to 0 (buffered,
+       bt_f_if1 idloc1,idloc1_master
+       pin_z   p0_booster_userfault
+
+        bc_f           INTCON,2        ; clear timer0 interrupt bit (p109)
+; Interrupt happens on overflow.  So start at 65535-morse_t0cycles:
+       mov_fw  t0h_count
+       mov_wf  TMR0H           ; p107 set high byte of timer0 (buffered,
                                 ; only actually set when write to tmr0l occurs)
-        clrf    TMR0L,0         ; set timer0 low byte - timer now set to 0000h
-loop
-        btfss   INTCON,2,0      ; check whether timer0 interrupt has been set -
-                                ; skip next instruction if so
-        bra     loop
-        return
+       mov_fw  t0l_count
+        mov_wf         TMR0L           ; set timer0 low byte - timer now set
+waiting_loop   ; wait for timer0 interrupt, or some other interrupt
+        bt_f_if1 INTCON,TMR0IF
+       return
 
+       bt_f_if1 idloc1, idloc1_master
+       bra     waiting_master
+       ; slave:
+
+       bt_f_if0 SSPCON1, SSPEN
+       bra     waiting_loop    ; no readouts if i2c is disabled
+       ; slave, i2c enabled:
+
+       bt_f_if1 PIR1, SSPIF
+       call    pan_i2cs_interrupt
+
+        bra    waiting_loop
 
 ;****************************************************************************
+; MEMORY READOUT - CRASH DUMP
+
+;----------------------------------------
+; MASTER'S PANIC SERIAL PORT HANDLING
+
+;--------------------
+waiting_master
+       bt_f_if1 PIR1,RCIF ; host sent us something ?
+       call    panicd_serialrx
+
+       bt_f_if0 SSPCON1, SSPEN
+       bra     waiting_loop
+       ; master, i2c enabled:
+
+       bt_f_if0 panicst, panicst_i2cmenable
+       bra     waiting_loop
+
+       bt_f_if1 PIR1, SSPIF
+       rcall   pan_i2cm_interrupt
+
+       bra     waiting_loop
+
+;----------
+panicst_oerrferr
+       mov_fw  RCREG
+       xor_lw  0x11
+       bra_z   panic_reset
+       xor_lw  0x10 ^ 0x11
+       bra_nz  panicd_serialrx_err_loop
+       ; yay! host ack'd ferr/oerr
+       bc_f    panicst, panicst_ferroerr
+       return ; return from panicd_serialrx
+
+;----------
+panicd_serialrx_err
+       bs_f    panicst, panicst_ferroerr
+       bc_f    RCSTA, RCEN     ; disable       } to clear FERR/OERR
+       mov_fw  RCREG           ; read RCREG    } (see PIC18FXX8 DS p182)
+       bs_f    RCSTA, RCEN     ; reenable      }
+panicd_serialrx_err_loop
+       bt_f_if0 PIR1, RCIF ; wait for a byte 0x10 to ack the overrun/error
+       bra     panicd_serialrx_err_loop
+;...
+;----------
+panicd_serialrx
+       pin_nz  p0_booster_userfault
+       bt_f_if1 RCSTA,FERR
+       bra     panicd_serialrx_err
+       bt_f_if1 RCSTA,OERR
+       bra     panicd_serialrx_err
+       bt_f_if1 panicst, panicst_ferroerr
+       bra     panicst_oerrferr
+
+       mov_fw  RCREG
+       bra     panicd_process_input_byte
+
+;----------------------------------------
+; CRASHREAD MASTER/SLAVE COMMON COMMAND BYTE HANDLING
+
+;----------
+pan_i2csu_write_data
+       call    led_green
+panicd_process_input_byte
+;              W       instruction from host or master
+       tst_w_ifnz
+       bra     write_ifnot_00
+       ; we've received 0x00:
+
+       mov_lfsr 0,1
+       bs_f    panicst, panicst_acked
+       return
+
+;----------
+write_ifnot_00
+       bt_f_if0 panicst, panicst_acked ; well, ignore that !
+       bra     write_only_tellmode
+       ; OK, we have an instruction:
+
+       bt_w_if1 7 ; huh?
+       bra     write_if_setbytetowrite
+       bt_w_if1 6
+       bra     panic_crashread_setpointer
+       bt_f_if0 idloc1,idloc1_master
+       bra     write_ifnot0_ifnotmaster
+       ; the next few options are for master only:
+
+       bt_w_if1 5
+       bra     write_if_master_slaveselect
+       bt_w_if1 4
+       bra     write_if_master_masterread
+       bt_w_if0 3
+       bra     write_if_master_slaveread
+;...
+write_ifnot0_ifnotmaster
+       xor_lw  0x09
+       bra_z   panic_reset
+       xor_lw  0x09
+;...
+write_only_tellmode
+       xor_lw  0x0a
+       bra_z   panic_tellmode
+       ; nope, well, we ignore it
+       return
+
+;----------
+panic_crashread_setpointer
+;  W                   byte from master or host        undefined
+;  FSR1*               crashread pointer               updated
+;  t, STATUS, PROD*    any                             undefined
+;  all others          any                             preserved
+       mov_wf  t
+       mov_lw  1<<6
+       mul_wf  FSR1L
+       mov_ff  PRODH, FSR1H
+       mov_fw  t
+       and_lw  0x3f
+       ior_wfw PRODL
+       mov_wf  FSR1L
+panic_noop
+       return
+
+;======================================================================#
+; SPECIAL COMMANDS 0x08..0x0f
+
+;----------
+panic_reset
+       reset
+
+;----------
+panic_tellmode
+       bt_f_if0 idloc1,idloc1_master
+       return
+       mov_lw  0x0b
+       bc_f    panicst, panicst_acked
+       goto    serial_write_char
+
+;======================================================================
+; MASTER READOUT AND MASTER READOUT OF SLAVES
+
+;----------
+write_if_setbytetowrite
+       bt_f_if0 idloc1,idloc1_master
+       return ; for master only
+
+       bc_w    7
+       mov_wf  panic_valcount
+       bs_f    panicst, panicst_writeslave
+       bs_f    panicst, panicst_i2cmenable
+       return
+
+;----------
+write_if_master_slaveread
+       mov_wf  panic_valcount
+       bc_f    panicst, panicst_writeslave
+       return
+
+;----------
+write_if_master_slaveselect
+       bc_w    5
+       btg_w   4
+       bs_f    panicst, panicst_i2cmours
+       bt_f_if1 panicst, panicst_writeslave
+       bra     pan_i2cm_write_start
+       bra     pan_i2cm_read_start
+
+;----------
+write_if_master_masterread
+       bc_w    4
+       mov_wf  panic_valcount
+write_if_master_masterread_loop
+       mov_fw  POSTINC1
+       call    serial_write_char
+       dec_f_ifnz panic_valcount
+       bra     write_if_master_masterread_loop
+       return
+
+;----------
+pan_i2cmu_read_got_byte
+       bt_f_if0 panicst, panicst_i2cmours
+       return
+       call    serial_write_char
+       dec_f_ifnz panic_valcount
+       bra     pan_i2cm_read_another
+       return
+
+;----------
+pan_i2cmu_write_next_byte
+       mov_fw  panic_valcount
+       bc_f    STATUS, Z
+       bt_f_if0 panicst, panicst_i2cmours
+       retlw   0x00
+       bt_f_if0 panicst, panicst_writeslave
+       bs_f    STATUS, Z
+       bc_f    panicst, panicst_writeslave
+       return
+
+;----------
+pan_i2cmu_done
+       mov_lw  ' '
+       goto    serial_write_char
+
+;----------
+pan_i2cmu_slave_no_ack
+       i2cpanic morse_SP
+
+;======================================================================
+; SLAVE I2C
+
+pan_near_i2csu code
+;----------
+pan_i2csu_write_begin
+       return
 
+;----------
+pan_i2csu_read_begin
+       mov_lw  0x80 ; M0000000
+       bt_f_if0 panicst, panicst_acked
+       goto    i2cs_read_data
+;...
+i2csu_read_panicd_ok
+       mov_fw  POSTINC1
+       goto    i2cs_read_data
+
+;----------
+pan_i2csu_read_another
+       bt_f_if1 panicst, panicst_acked
+       bra     i2csu_read_panicd_ok
+       ; not ok
+       mov_lw  0x0b ; AARGH
+       goto    i2cs_read_data
+
+near_gots code
+;----------
+got_aargh @
+       panic   morse_T
+
+command_crashed_section code 0x2100
+;----------
+command_crashed @
+panic_crashread_commanded @
+       panic   morse_E
+
+;***************************************************************************
        include final.inc