;====================================================================== ; 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 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 panic_valcount res 1 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 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 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 ;**************************************************************************** pan_ code ;**************************************************************************** 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<=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 ; flash_pattern flash pattern preserved ; bit_counter any undefined mov_lw 9 mov_wf bit_counter rr_f flash_pattern morse_readout_loop dec_f_ifz bit_counter ; done all the bits yet ? return ; No: rl_f flash_pattern ; top bit goes into N, ;ie Negative if 1 bra_n morse_readout_if_led_1 morse_readout_if_led_0 call led_black bra morse_readout_endif_led morse_readout_if_led_1 call led_red morse_readout_endif_led rcall waiting bra morse_readout_loop ;-------------------------- ;-------------------------- registermsg register_msg_start clr_f register_counter ; clear loop counter register_loop mov_fw panic_regs cmp_fw_ifge register_counter ; if loop counter >=panic_regs return ; return to panic tblrd *+ 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 ;**************************************************************************** ; 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 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) 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 ;====================================================================== ; 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