My code from 17 years ago had a bug. I'm sorry about that. I haven't used PIC16 microcontrollers much since then.
Firstly, about PCLATH. That is the write-only latch for the high byte of the program counter. I've just had to look up the details.
For CALL and GOTO instructions, the program space is effectively split into areas that are 1024 instructions in length. When any CALL or GOTO instruction happens, the value of PCLATH controls in which area of 1024 instructions is executed next.
A lot of PIC16 microcontrollers have space for less than 1024 instructions, so PCLATH does not need to change for GOTO and CALL instructions.
Another use of PCLATH is for computed jumps. Those are often used in lookup tables, where a number is added to the PCL (which is the bottom 8 bits of the program counter). If PCL is directly manipulated by the program, so something like:-
then PCLATH is used for the top bits of the program counter.
If all lookup tables are in the first 256 instructions, then PCLATH can be left at it's default value of zero.
So PCLATH only needs to be changed if the program is bigger than 1024 instructions or if it has lookup tables that are outside of the first 256 instructions. My ISR code ignores PCLATH on the assumption that it's not needed.
Similarly, the bank select command should be used if the ISR uses any registers that are only in one bank. My code assumes that the temporary registers (status_save and w_save) are in the areas of memory that can be accessed in any bank.
Secondly, the swapf.
My code from 17 years ago is wrong. It should read:-
Code:
movwf w_save ;w_save is now the pre-interrupt W
swapf STATUS,w ;w is now the pre-interrupt STATUS (swapped)
movwf status_save ;status_save is the pre-interrupt STATUS (swapped)
swapf w_save, f ;w_save is now the pre-interrupt W (swapped)
after the ISR, you should use:-
swapf status_save, w ;w is now the pre-interrupt STATUS (swapped twice, so back to how it started)
movwf status ;STATUS is now the pre-interrupt STATUS (swapped twice, so back to how it started)
swapf w_save, w ;W is now the pre-interrupt W (swapped twice, so back to how it started)
retfie
The idea is to save and restore the W register and the STATUS registers. The MOVWF and the SWAPF commands do not affect the STATUS register so the code is written to use those only.
SWAPF, as you worked out, just swaps the nibble order, so 0x12 becomes 0x21. It is used in the ISR instead of MOVF because MOVF affects the STATUS register. To avoid swapping the W or STATUS registers, SWAPF has to be used an even number of times to restore the registers correctly.
Specifically the line:-
could be after the ISR. The other example used w_temp instead of w_save, but that's just a name. It puts the SWAPF w_save, f after the ISR, which is could be better as the ISR gets executed one instruction sooner.
It is needed because SWAPF has to be used to restore the W register because MOVF, W would affect the STATUS register. The W register has to be restored as the last item because restoring anything else uses the W register.