-; 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