> From: Tjaart van der Walt > > A simple solution is to use a MPASM address for a label. Right shift it > 8 times, and load it into PCLATH. You can even make a macro out of it : > > Fix_up_PCLATH MACRO > local Local_Label > Local_Label > movlw ((Local_Label>>8)&&0xFF) > movwf PCLATH > ENDM > > Now all you have to do after returning from a unknown address location, > is "Fix_up_PCLATH" > > It uses two words of ROM, but saves your sanity. Unfortunately, it also destroys W which forces subroutines to return results in registers. There are plenty of solutions. How about the following untested macro for general calls. No doubt Andrew Warren et al. have something similar in their web pages, but this is my 5 cents worth (sorry, Oz doesn't have 2 cents any more - inflation, you know). ; Expands to 1 or 3 instructions, depending on whether cross-block call. perform macro routine if (routine & 0x800) != ($ & 0x800) if (routine & 0x800) [optionally disable interrupts] bsf pclath,3 else bcf pclath,3 endif call routine if ($ & 0x800) bsf pclath,3 else bcf pclath,3 [optionaly enable interrupts] endif else call routine endif endm ----- Another correspondent (Mike Riendeau ) writes: ===quote=== I use the following fragment. It doesn't modify w and uses goto's and calls carefully. I use a register "SaveRP" to record the interrupted page and ram bank setting. My interrupt routine is in page1. You can change that if you wish. Leave enough room at the interrupt vector for the following code. It's a little ugly, but if anybody else has a better way, I would love to see it. You can't depend on the regular swaps to save the ram bank setting, because you have to define it in order to save the page setting. ORG IntVector btfss PCLATH,3 ;Interrupted a page1 routine goto $+11 ;goto is safe, already using page0 bcf PCLATH,3 ;set page0 so we can use goto's btfss STATUS,RP0 ;Test which ram bank is set goto $+4 bcf STATUS,RP0 ;Set bank0 so we can use SaveRP register bsf SaveRP,1 ;Save bank1 status goto $+2 bcf SaveRP,1 ;Save bank0 status bsf SaveRP,0 ;set page1 as saved page bsf PCLATH,3 ;interrupt routine in page 1 goto Int_svc ;vector to interrupt service btfss STATUS,RP0 ;Test which ram bank is set goto $+4 bcf STATUS,RP0 ;Set bank0 so we can use SaveRP register bsf SaveRP,1 ;Save bank1 status goto $+2 bcf SaveRP,1 ;Save bank0 status bcf SaveRP,0 ;set page0 as saved page bsf PCLATH,3 ;interrupt routine in page 1 goto Int_svc ;vector to interrupt service Int_svc: (save w) (save status) (save fsr) . blah.. blah.. blah.. . . . (restore fsr) (restore status) (restore w) bcf STATUS,RP0 ;Set bank0 btfss SaveRP,0 ;Test page setting bcf PCLATH,3 ;set page0 btfsc SaveRP,1 ;test bank setting bsf STATUS,RP0 ;set bank1 retfie ===end quote=== Maybe I missed something, but what is all this bit manipulation achieving over _simply_ saving W, STATUS, FSR and PCLATH? By careful ordering of the saves and restores only 5 registers need to be allocated (2 for W, 1 for the others, since the register bank is 'unknown' only when saving W). Just in case Mike is not aware of the 'standard', here it is for the record: org 4 movwf w_temp ; 1 - Save W in either bank swapf status,w ; 2 - Swap status into W clrf status ; 3 - Select bank 0 movwf s_temp ; 4 - Save swapped status in bank 0 movf pclath,w movwf p_temp ; 6 - Save PCLATH in bank 0 (optional) movf fsr,w movwf f_temp ; 8 - Save FSR in bank 0 (optional) ... movf f_temp,w movwf fsr ; 10 - Restore FSR (optional) movf p_temp,w movwf pclath ; 12 - Restore PCLATH (optional) swapf s_temp,w ; 13 - Unswap status in bank 0 movwf status ; 14 - Move into status swapf w_temp,f ; 15 - Swap W (whichever bank) swapf w_temp,w ; 16 - ...back into W retfie ; 17,18 w_temp must be reserved in both banks (e.g. 0x20 and 0xA0). This also has the advantage of being isochronous. Regards, SJH Canberra, Australia