This post describes CALL RCALL and RETURN Instructions for PIC Microcontroller with examples. CALL
and RCALL
instructions are used to call subroutines. RETURN
instruction is used to return from a subroutine.
Subroutines are used when same piece of code is required to be used multiple times in a program. Writing this piece of code as a subroutine allows us to call it as many times as we want. without writing the code again. This saves code memory, since the code is written only once and merely “called” multiple times. The difference between unconditional branch instructions and subroutines is that the subroutines can return after execution, using RETURN
instruction, to the instruction written after from where they are called. Unconditional branch instructions have no such option.
Note: For this tutorial I am using MPLAB X v5.0 but you can use any version upto v5.35. Version 5.35 is last version that included MPASM i.e. the assembler we require to compile the assembly code used in this tutorial. Code given here may not work for later versions.
RCALL: Relative Call
Syntax: RCALL label
Length of the Instruction: 2 bytes
Instruction Cycles: 2 cycles are required since the previously fetched instruction is discarded and new instruction from target address must be fetched before execution.
Instruction Encoding: 1101 1nnn nnnn nnnn
Updated Flags: None
Target Address: The target label
is represented by an 11-bit relative address n
in the opcode. Target address, i.e. the new value of PC where the code jumps, is calculated by adding 2n
to the current value of program counter PC
.
Target Address = New PC
= Current PC
+ 2n
Description: RCALL instruction calls a subroutine and jumps to the target address / label. First the return address (i.e. the address of the instruction immediately after the RCALL
) is saved by pushing it onto the stack. Then the target address is calculated and the new target address is loaded into the PC
.
RCALL instruction is a short call
RCALL instruction is a short call and the target address, i.e. the new value of PC must be within 2048 bytes of the current value of the program counter (PC).
The second byte n
of the instruction is a relative address. Relative address can be negative or positive. Positive address means that the code jumps forward i.e. after current PC. If the address is negative then the code jumps backwards i.e. before current PC. Target address can be calculated using
Target Address = New PC
= Current PC
+ 2n
The relative address n
is represented by 11-bits. The largest -ve relative address can be -1024, and the largest +ve relative address can be +1023. As a result, the target address can be a maximum of 2048 bytes behind the current program counter, and a maximum of 2044 bytes forward from the current program counter.
Note: PC points to the next instruction (after the conditional branch) while calculating the target address. PC is always ahead since it is used to fetch the next instruction.
RETURN: Return from Subroutine
Syntax: RETURN {s}
Length of the Instruction: 2 bytes
Instruction Cycles: 2 cycles are required since the previously fetched instruction is discarded and new instruction from return address must be fetched before execution.
Instruction Encoding: 0000 0000 0001 001s
Updated Flags: None
Return Address: The return address is loaded into PC
by popping from the stack.
Shadow Registers: If s = 1
, the contents of shadow registers WS
, STATUSS
and BSRS
, are loaded into W
, STATUS
and BSR
registers respectively. If s = 0
, the W
, STATUS
and BSR
registers are not updated. Default is s = 0
.
Description: RETURN instruction causes a return from subroutine to the return address (i.e. the address of the instruction immediately after the CALL
/ RCALL
). The return address is loaded into the PC
by popping the stack.
RCALL & RETURN Example:
The following code that toggles all pins of PORTC
after every 250 msecs. RCALL
instruction is used to call a subroutine called DELAY_250MSEC
. DELAY_250MSEC
contains a nested loop generates a delay of 250 msec. RETURN
instruction is written as the end, to allow return from the subroutine.
CLRF TRISC ; Make PORTC an output by writing 0's to all bits of TRISC
MOVLW 0x55 ; Load a value into WREG
MOVWF PORTC ; Initialize PORTC by copying WREG to PORTC SFR
BACK
RCALL DELAY_250MSEC ; RCALL delay subroutine
COMF PORTC ; Toggle all pins of PORTC
BRA BACK ; Infinite loop
; Delay SUBROUTINE to generate a delay of 250 msecs
R1 EQU 0x1 ; Inner Loop Counter for DELAY_MSEC
R2 EQU 0x2 ; Main Loop Counter for DELAY_MSEC
DELAY_250MSEC
MOVLW D'250'
MOVWF R2
L_1 ; MAIN loop
MOVLW D'199'
MOVWF R1
L_2 ; inner loop
NOP
NOP
DECF R1, F
BNZ L_2
DECF R2, F
BNZ L_1
RETURN
RCALL
instruction can be used here, since the subroutine comes soon after the main loop of the program, and it is within 2048 bytes of the current PC
. CALL
instruction can also be used here, since it can jump to any where in PIC code ROM space. However, RCALL
should be preferred as it requires 2 bytes instead of 4 bytes in ROM.
CALL: Subroutine Call
Syntax: CALL label
{,s}
Length of the Instruction: 4 bytes
Instruction Cycles: 2 cycles are required since the previously fetched instruction is discarded and new instruction from target address must be fetched before execution.
Instruction Encoding: 1110 110s kkkk kkkk 1111 kkkk kkkk kkkk
Updated Flags: None
Target Address: The target label
is represented by a 20-bit absolute address k
in the opcode. Target address, i.e. the new value of PC where the code jumps, is 2k
.
Target Address = New PC
= 2k
Shadow Registers: If s = 1
, the contents of register W
, STATUS
and BSR
, are pushed into WS
, STATUSS
and BSRS
shadow registers respectively. If s = 0
, the WS
, STATUSS
and BSRS
registers are not updated. Default is s = 0
.
Description: CALL instruction calls a subroutine and jumps to the target address / label. First the return address (i.e. the address of the instruction immediately after the CALL
) is saved by pushing it onto the stack. Optionally, the W
, STATUS
and BSR
registers are pushed into their respective shadow registers. Then the target address is calculated and the new target address is loaded into the PC
.
CALL instruction is a long call
CALL instruction is a long call that can jump to any memory address of the 2M code space of PIC18 microcontroller. Target address i.e. the new 21-bit value of PC where the code jumps, is 2k
.
Note: PC points to the next instruction (after the conditional branch) while calculating the target address. PC is always ahead since it is used to fetch the next instruction.
CALL & RETURN Example:
The following code that toggles all pins of PORTC
after every 250 msecs. CALL
instruction is used to call a subroutine called DELAY_250MSEC
. DELAY_250MSEC
contains a nested loop generates a delay of 250 msec.
CLRF TRISC ; Make PORTC an output by writing 0's to all bits of TRISC
MOVLW 0x55 ; Load a value into WREG
MOVWF PORTC ; Initialize PORTC by copying WREG to PORTC SFR
BACK
CALL DELAY_250MSEC ; CALL delay subroutine
COMF PORTC ; Toggle all pins of PORTC
BRA BACK ; Infinite loop
ORG 0F00H
; Delay SUBROUTINE to generate a delay of 250 msecs
R1 EQU 0x1 ; Inner Loop Counter for DELAY_MSEC
R2 EQU 0x2 ; Main Loop Counter for DELAY_MSEC
DELAY_250MSEC
MOVLW D'250'
MOVWF R2
L_1 ; MAIN loop
MOVLW D'199'
MOVWF R1
L_2 ; inner loop
NOP
NOP
DECF R1, F
BNZ L_2
DECF R2, F
BNZ L_1
RETURN
Using ORG
directive, the subroutine code is placed far from the main loop, at ROM address 0xF00
. It means that the subroutine is more than 2048 bytes away from the previous PC
. RCALL
instruction cannot be used here, so CALL
instruction must be used. If you try to use RCALL
instruction then MPLAB will fail to assemble the code and it will throw an error “Symbol ‘DELAY_250MSEC
‘ out of range of relative branch instruction”.
Conclusion
CALL, RCALL and RETURN instructions for PIC microcontroller are used when working with subroutines. CALL
instruction must be used to call the subroutine when it is more than 2048 bytes away from the previous PC
. When the subroutine is within 2048 bytes of the previous PC
, we can use either of them. However, RCALL
should be preferred as it requires 2 bytes instead of 4 bytes in ROM. The subroutine must end with a RETURN
instruction to enable the code to “return” and continue onward from where it was called.