; ***************************************************************
; * Copyright (C) 2002, Embed Inc (http://www.embedinc.com) *
; * *
; * Permission to copy this file is granted as long as this *
; * copyright notice is included in its entirety at the *
; * beginning of the file, whether the file is copied in whole *
; * or in part and regardless of whether other information is *
; * added to the copy. *
; * *
; * The contents of this file may be used in any way, *
; * commercial or otherwise. This file is provided "as is", *
; * and Embed Inc makes no claims of suitability for a *
; * particular purpose nor assumes any liability resulting from *
; * its use. *
; ***************************************************************
;
; Interrupt service and related routines.
;
include "hos.inc"
extern uart_intr_recv ;receive interrupt routine in UART module
extern uart_intr_xmit ;transmit interrupt routine in UART module
extern_flags ;declare global flag bits EXTERN
;
;***********************************************************************
;
; Configuration constants.
;
save_fsr equ true ;indicate whether ISR must save/restore FSR
niregs equ 1 ;num of IREGn private interrupt routine registers
;
;**********
;
; Derived constants.
;
;
;***********************************************************************
;
; Global state.
;
; The following global state is in the normal register bank for global
; state. The bank is GBANK, and GBANKADR is an address guaranteed to
; be within this bank.
;
.bank#v(gbank) udata
;
;***********************************************************************
;
; Local state. This is always in the same register bank as the global
; state.
;
;
; The following state is private to the interrupt service routine, and
; must always be in bank 0.
;
if gbank != 0
.bank0 udata
endif
status_save res 1 ;saved copy of STATUS, nibbles swapped
if save_fsr
fsr_save res 1 ;saved copy of FSR (if FSR save enabled)
endif
if ncodepages > 1
pclath_save res 1 ;saved copy of PCLATH (if multiple code pages)
endif
;
; Define the IREGn general register for use during an interrupt. The
; general registers REGn must not be altered during an interrupt without
; being explicitly saved/restored, which usually makes them unusable.
; The IREGn registers are used instead, although these are in bank 0
; instead of global memory. The number of IREGn registers is defined
; by the constant NIREGS above. The first is IREG0, then IREG1, etc.
;
ii set 0
while ii < niregs ;once for each IREG register to define
ireg#v(ii) res 1 ;define this IREGn register
global ireg#v(ii) ;make is global for interrupt code in other modules
ii set ii + 1 ;advance to next IREG number
endw ;back to define next IREG
;
; This state is private to the interrupt service routine and must always
; be accessible regardless of the current direct register bank setting.
;
udata_shr
w_save res 1 ;saved W during interrupt, mapped to all banks
.intr code
;
;***********************************************************************
;
; Subroutine INTR_INIT
;
; Initialize the interrupt system and other state managed by this module.
;
glbsub intr_init, noregs
;
; Initialize global state.
;
;
; Initialize local state.
;
;
; Enable interrupts. Any interrupts used have already been enabled
; individually, but interrupts are still disabled globally.
;
ifdef pir1
dbankif pir1
clrf pir1 ;clear any exiting peripheral 1 intr condition
endif
ifdef pir2
dbankif pir2
clrf pir2 ;clear any exiting peripheral 2 intr condition
endif
ifdef peie
bsf intcon, peie ;enable peripheral interrupts
endif
bsf intcon, gie ;globally enable interrupts
leaverest
;
;***********************************************************************
;
; Interrupt service routine.
;
; The processor executes a call to location 4 on an interrupt, and in
; addition globally disables interrupts. These are re-enabled at the end
; of the ISR by the RETFIE instruction.
;
; Note that subroutine calls must be minimized or avoided in the ISR.
; Since an interrupt can come at any time in the main code, any additional
; call stack locations used here are not available anywhere else.
;
.intr_svc code 4 ;start at interrupt vector location
movwf w_save ;save W
swapf status, w ;make copy of status without effecting status bits
clrf status ;select direct and indirect register banks 0
dbankis 0
ibankis 0
movwf status_save ;save old STATUS value with nibbles swapped
if save_fsr ;FSR needs to be saved ?
movf fsr, w ;save FSR
movwf fsr_save
endif
if ncodepages > 1 ;multiple code pages may be in use ?
movf pclath, w ;save PCLATH
movwf pclath_save
clrf pclath ;now definitely on code page 0
endif
;
; W, STATUS, FSR (if SAVE_FSR set), and PCLATH (if multiple code pages)
; have been saved. Direct and indirect register banks 0 are selected, and
; the bank assumptions have been set accordingly. Program memory page 0
; is selected.
;
;
; Check for UART receive interrupt.
;
dbankif pir1
btfss pir1, rcif
goto no_uart_recv
gjump uart_intr_recv ;handle interrupt, will go to INTR_RET on done
no_uart_recv dbankis pir1
;
; Check for UART transmitter ready interrupt.
;
dbankif pir1
btfss pir1, txif
goto no_uart_xmit
gjump uart_intr_xmit ;handle interrupt, will go to INTR_RET on done
no_uart_xmit dbankis pir1
gjump 0 ;unexpected interrupt, should never happen
;
;********************
;
; Restore state to when the interrupt occurred and return from interrupt.
;
glbent intr_ret ;common code to return from the interrupt
clrf status ;register bank settings are now 0
dbankis 0
ibankis 0
if ncodepages > 1 ;multiple code pages may be in use ?
movf pclath_save, w ;restore PCLATH
movwf pclath
endif
if save_fsr ;FSR needs to be restored ?
movf fsr_save, w ;restore FSR
movwf fsr
endif
swapf status_save, w ;get old STATUS with nibble order restored
movwf status ;restore STATUS, register banks now unknown
swapf w_save ;swap nibbles in saved copy of W
swapf w_save, w ;restore original W
retfie ;return from interrupt, re-enable interrupts
end