Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PIC SWAPF f,d Instruction

Status
Not open for further replies.

fenderman

Member
Hi All,
I am new to PIC's having 'come up' from Micro (Z80/8080/8085) systems, and am experimenting with the 16F628A and 16F88 pics.
I have been looking through some Interrupt service routines for some idea's of the handlers and appreciate that registers such as the W and STATUS registers need to saved for the Return From Interrupt instruction at the end.
Many Interrupt Service Routines seem to use the SWAPF <STORE>,W instruction as a method of storing the W register, but on checking this insturction, this instruction seems to Swap the Upper with the Lower Nibbles of the specified register and place the result in either the source register or the W register based on the value of 'd' (destination), this can only be a '0' or a '1', (so assume that W is not valid).
I can't follow why this instruction can be used to store the W and STATUS registers .... an explanation would be greatly appreciated.

Fenderman
 
Last edited:
It's used because it doesn't affect the STATUS flags, obviously one thing you MUST save and restore is the STATUS flags register, but it's no good saving and restoring it if doing so changes it.
 
You may use the common BANK for the 16F family. Variables defined within the common bank is accessible to all banks with no need to invoke BANKSEL, or toggling status bits.

The range for the common bank for the 16F628 is 0x70 to 0x7F, 16 bytes in length.

Code:
	;=====CBLOCK======================================
	CBLOCK 0X70 	;-----COMMON BANK-----------------
        W_REG, STATUS_REG
        ENDC

	CBLOCK 0X20	;-----APP SPECIFIC RAM------------
	;
	;	
	ENDC
	;=====END OF CBLOCK===============================

	ORG 0X04
	;=====INTERRUPT===================================
INTERRUPT:
	MOVWF	W_REG
	SWAPF	STATUS, W    
	MOVWF   STATUS_REG
	;--CODE-----------------------------


	;--END OF CODE----------------------
INT_END	SWAPF	STATUS_REG, W
        MOVWF	STATUS
        SWAPF   W_REG, F
        SWAPF   W_REG, W
	RETFIE
	;=====END OF INTERRUPT===========================
 
Last edited:
Do not use the code posted by donniedj, it corrupts the Zero flag when an interrupt occurs. Just use the code shown in the data sheet or use the template file supplied by Microchip.

Mike.
Code:
INT_END	MOVF	STATUS_REG, W
	MOVWF	STATUS
	MOVF	W_REG, W    [COLOR="Red"];<----- will set or clear the Zero flag[/COLOR].
	RETFIE
 
Here's a pretty standard ISR routine, nicely commented. Note it's even got the extra GIE check that some older PICs didn't clear correctly. The complete program is here.
https://www.electronic-engineering.ch/microchip/projects/rs232/rs_test/rs_test.asm
Code:
;***** INTERRUPT SERVICE ROUTINE *****

ISR    ;************************
    ;*** ISR CONTEXT SAVE ***
    ;************************

    bcf    INTCON,GIE    ; disable all interrupts
    btfsc    INTCON,GIE    ; assure interrupts are disabled
    goto    ISR
    movwf    W_TEMP        ; context save: W
    swapf    STATUS,W    ; context save: STATUS
    movwf    STATUS_TEMP    ; context save
    clrf    STATUS        ; bank 0, regardless of current bank
    movfw    PCLATH        ; context save: PCLATH
    movwf    PCLATH_TEMP    ; context save
    clrf    PCLATH        ; page zero, regardless of current page
    bcf    STATUS,IRP    ; return to bank 0
    movfw    FSR        ; context save: FSR
    movwf    FSR_TEMP    ; context save
    ;*** context save done ***

    ;**************************
    ;*** ISR MAIN EXECUTION ***
    ;**************************
    
    ;*** check origin of interrupt ***
    btfsc    INTCON,INTF    ; check for RB0/INT interrupt
    goto    _ISR_RS232    ; if set, there was a keypad stroke

    ; catch-all
    goto    ISRend        ; unexpected IRQ, terminate execution of ISR

    ;******************************
    ;*** RS232 DATA ACQUISITION ***
    ;******************************
_ISR_RS232
    ; first, disable interrupt source
    bcf    INTCON,INTE    ; disable RB0/INT interrupt
    ; second, acquire RS232 data
    RECEIVE            ; macro of RS232 software reception
    bsf    RSflag        ; enable RS232 data reception flag
    goto    _ISR_RS232end    ; terminate RS232 ISR properly

    ;***********************************
    ;*** CLEARING OF INTERRUPT FLAGS ***
    ;***********************************
    ; NOTE: Below, I only clear the interrupt flags! This does not
    ; necessarily mean, that the interrupts are already re-enabled.
    ; Basically, interrupt re-enabling is carried out at the end of
    ; the corresponding service routine in normal operation mode.
    ; The flag responsible for the current ISR call has to be cleared
    ; to prevent recursive ISR calls. Other interrupt flags, activated
    ; during execution of this ISR, will immediately be served upon
    ; termination of the current ISR run.
_ISR_RS232error
    bsf    INTCON,INTE    ; after error, re-enable IRQ already here
_ISR_RS232end
    bcf    INTCON,INTF    ; clear RB0/INT interrupt flag
    ;goto    ISRend        ; terminate execution of ISR

    ;*****************************************
    ;*** ISR TERMINATION (CONTEXT RESTORE) ***
    ;*****************************************

ISRend    movfw    FSR_TEMP    ; context restore
    movwf    FSR        ; context restore
    movfw    PCLATH_TEMP    ; context restore
    movwf    PCLATH        ; context restore
    swapf    STATUS_TEMP,W    ; context restore
    movwf    STATUS        ; context restore
    swapf    W_TEMP,F    ; context restore
    swapf    W_TEMP,W    ; context restore
    RETFIE            ; enable global interrupt (INTCON,GIE)

;***** END OF INTERRUPT SERVICE ROUTINE *****
 
These are the only instructions, in addition to swapf, that you can use without context saving on the 16F series PIC:
BCF f, b ;f can not = STATUS
BSF f, b ;f can not = STATUS
BTFSC f, b
BTFSS f, b
DECFSZ f, d ;d can not = W
INCFSZ f, d ;d can not = W
MOVWF f ;f can not = STATUS
NOP
RETFIE
RETURN
CALL
GOTO

As a NOOB it is best to leave these types of optimizations for later. Follow the example templates installed with MPLAB to build your code:
C:\Program Files\Microchip\MPASM Suite\Template\Code
Look for the files f628Atemp.asm and f88temp.asm and copy these to use as a starting point for new code.
 
Last edited:
Pommie said:
Do not use the code posted by donniedj, it corrupts the Zero flag when an interrupt occurs. Just use the code shown in the data sheet or use the template file supplied by Microchip.


Then swap it in and swap it out like so:
Code:
;=====INTERRUPT===================================
INTERRUPT:
	MOVWF	W_REG
	SWAPF	STATUS, W
	MOVWF   STATUS_REG
	;--CODE-----------------------------


	;--END OF CODE----------------------
INT_END	SWAPF	STATUS_REG, W
        MOVWF	STATUS
        SWAPF   W_REG, F
        SWAPF   W_REG, W
	RETFIE

Now you may just use the code posted by donniedj.
 
Guys,
What can I say, NEVER, on ANY other forum have I had such a fantastic, quick, informative and helpful number of responces to a request I only posted last night. I thank you all, this has got to be the best furum about and am certainly glad to have found it (via Google), I'm sure I will be using it frequently.
Roy
 
blueroomelectronics said:
Here's a pretty standard ISR routine, nicely commented. Note it's even got the extra GIE check that some older PICs didn't clear correctly. The complete program is here.
https://www.electronic-engineering.ch/microchip/projects/rs232/rs_test/rs_test.asm
Code:
;***** INTERRUPT SERVICE ROUTINE *****

ISR    ;************************
    ;*** ISR CONTEXT SAVE ***
    ;************************

    bcf    INTCON,GIE    ; disable all interrupts
    btfsc    INTCON,GIE    ; assure interrupts are disabled
    goto    ISR
    movwf    W_TEMP        ; context save: W
    swapf    STATUS,W    ; context save: STATUS
    movwf    STATUS_TEMP    ; context save
    clrf    STATUS        ; bank 0, regardless of current bank
    movfw    PCLATH        ; context save: PCLATH
    movwf    PCLATH_TEMP    ; context save
    clrf    PCLATH        ; page zero, regardless of current page
    bcf    STATUS,IRP    ; return to bank 0
    movfw    FSR        ; context save: FSR
    movwf    FSR_TEMP    ; context save
    ;*** context save done ***

    ;**************************
    ;*** ISR MAIN EXECUTION ***
    ;**************************
    
    ;*** check origin of interrupt ***
    btfsc    INTCON,INTF    ; check for RB0/INT interrupt
    goto    _ISR_RS232    ; if set, there was a keypad stroke

    ; catch-all
    goto    ISRend        ; unexpected IRQ, terminate execution of ISR

    ;******************************
    ;*** RS232 DATA ACQUISITION ***
    ;******************************
_ISR_RS232
    ; first, disable interrupt source
    bcf    INTCON,INTE    ; disable RB0/INT interrupt
    ; second, acquire RS232 data
    RECEIVE            ; macro of RS232 software reception
    bsf    RSflag        ; enable RS232 data reception flag
    goto    _ISR_RS232end    ; terminate RS232 ISR properly

    ;***********************************
    ;*** CLEARING OF INTERRUPT FLAGS ***
    ;***********************************
    ; NOTE: Below, I only clear the interrupt flags! This does not
    ; necessarily mean, that the interrupts are already re-enabled.
    ; Basically, interrupt re-enabling is carried out at the end of
    ; the corresponding service routine in normal operation mode.
    ; The flag responsible for the current ISR call has to be cleared
    ; to prevent recursive ISR calls. Other interrupt flags, activated
    ; during execution of this ISR, will immediately be served upon
    ; termination of the current ISR run.
_ISR_RS232error
    bsf    INTCON,INTE    ; after error, re-enable IRQ already here
_ISR_RS232end
    bcf    INTCON,INTF    ; clear RB0/INT interrupt flag
    ;goto    ISRend        ; terminate execution of ISR

    ;*****************************************
    ;*** ISR TERMINATION (CONTEXT RESTORE) ***
    ;*****************************************

ISRend    movfw    FSR_TEMP    ; context restore
    movwf    FSR        ; context restore
    movfw    PCLATH_TEMP    ; context restore
    movwf    PCLATH        ; context restore
    swapf    STATUS_TEMP,W    ; context restore
    movwf    STATUS        ; context restore
    swapf    W_TEMP,F    ; context restore
    swapf    W_TEMP,W    ; context restore
    RETFIE            ; enable global interrupt (INTCON,GIE)

;***** END OF INTERRUPT SERVICE ROUTINE *****

Those first three instructions of the ISR can't possibly be required. I understand about some older PICs that might not actually disable interrupts when you execute BCF INTCON,GIE, but that didn't apply to an interrupt turning off GIE.

Imagine that the interrupt didn't actually turn off GIE, although you did arrive at the ISR routine. The interrupt would just occur immediately again, before you could turn off GIE and you would be in an infinite loop.

This extra code doesn't hurt anything (other than your interrupt latency), but it is definitely not required.

Mike
 
blueroomelectronics said:
Like I said, it's old, 16C84 old and many 16C5x. Not sure if it applied to any F series parts.
https://www.phanderson.com/PIC/16C84/interrupts/interrupt_1a.html
I know, but my point was that the code in that interrupt handler was never needed, even for those old parts.

The web page you reference here explains the problem, but correctly shows that it was needed only when you were explicitly disabling interrupts via BCF INTCON,GIE, not when interrupts are disabled by an actual interrupt.

Whoever wrote that original code misunderstood how interrupts work, thinking that the ISR needed to disable interupts.

BTW, the datasheets for many current parts show using that loop when disabling interrupts in examples, even though it is not required for any of the newer parts. (eg. 12F683 - example of how to write EEPROM)

Mike
 
mike50 said:
BTW, the datasheets for many current parts show using that loop when disabling interrupts in examples, even though it is not required for any of the newer parts. (eg. 12F683 - example of how to write EEPROM)

Mike

I notice this recently but only in newer data sheets. The 876A data sheet doesn't have it, yet the 887 does!! The flash write routine also contains bugs. At the same time their template files started using a tab setting of 5 - argh.

Microchip seem to have recently taken a big step backward in their documentation department.

Mike.
 
A bit of confirmation

Hi again, I'm still a little confused over the SwapF (f)ile, (d)estination instruction and could do with a bit of confirmation, MANY of the examples show instructions such as:

(As in Blueroomelectronics and donniedj post's)
swapf STATUS,W ; context save: STATUS
swapf STATUS_TEMP,W ; context restore
swapf W_TEMP,F ; context restore
swapf W_TEMP,W ; context restore

I can only see this working if the 'W' and 'F' variables are equated as '0' and '1' respectively, as the swapf instruction ONLY exchanges the UPPER and LOWER nibbles within the byte of the specified register (f) .... and places the result in either 'W' if the 'd' = '0' or back in the 'f' register if it is a '1'.
This impies that the 'data' in the 'f' register is actually stored by the MOVFW 'f' instruction but with the nibbles within that register exchanged, and hence are exchanged back again on the subsequent swapf f,d instruction.
Is this correct or am I missing something ?
Roy
 
You are correct. W & F are equated as 0 and 1. Also, the 2 swaps cancel each other out therefore restoring the original values.

Mike.
 
Try reading the include file for the processor in question, W and F are indeed equated to their required numeric values, as is STATUS and all other required names. You should always use the include file names, NEVER use the numeric values directly - it's pointless and confusing.
 
Thanks for that,
I never thought to look in the .inc file for those equates ... I did see all the config / special registers / bit variables in there, but obviously missed the W and F (and probably a few more) ....
But now that you have confirmed it all .... onwards .... (and hopefully upwards) ...
My thanks to all who have taken the time to answer my query.
Roy
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top