This page was originally published by me on a site called pic-projects.net.
The Microchip PIC instruction set provides opcodes that will perform the addition or subtraction two 8-bit values but what if we need to add or subtract 16-, 24- or 32-bit values held in several bytes?
The following code illustrates how to perform 16-, 24- and 32-bit arithmetic on values held in multiple registers. The examples use a number of register areas with prefixes 'R', 'A' and 'B'. The input values to an arithmetic operation will either be in the 'R' and 'A' registers (for R += A and R -= A) or the 'A' and 'B' registers (for R = A + B and R = A - B). The result of the operation is always placed in the 'R' registers.
The number of 'R', 'A' and 'B' registers used depends on size of the values. A 16-bit operation will only use registers suffixed with a 0 or a 1 (e.g. R0 and R1), while a 24-bit operation will use 0, 1, 2 and a 32-bit operation will use 0, 1, 2 and 3. The bigger the suffix value, the more significant the byte it holds.
The all of the code assumes that A0-3, B0-3 and R0-3 are accessible simultaneously. This means that they must either be in the same bank of file registers or split between a single bank and the common shared (or access) file register area.
The ADDWF instruction provided on all PIC devices adds two 8-bit values but does not take into account the value of the carry flag in the STATUS register. Although the carry is not used in the calculation it will be set afterwards to indicate if the result was larger than 8-bits (e.g. h'c0' + h'40' = h'00' and C=1).
The following code implements addition for various size values held in registers A0-3 with the values in R0-3 leaving the result in R0-3 (e.g. R += A).
; 16-bit Addition (All Devices) movf A0,W addwf R0,F movf A1,W btfsc STATUS,C incfsz A1,W addwf R1,F ; 24-bit Addition (All Devices) movf A0,W addwf R0,F movf A1,W btfsc STATUS,C incfsz A1,W addwf R1,F movf A2,W btfsc STATUS,C incfsz A2,W addwf R2,F ; 32-bit Addition (All devices) movf A0,W addwf R0,F movf A1,W btfsc STATUS,C incfsz A1,W addwf R1,F movf A2,W btfsc STATUS,C incfsz A2,W addwf R2,F movf A3,W btfsc STATUS,C incfsz A3,W addwf R3,F
To understand how this code propagates the carry into the calculation let's break down series of instructions used for all the bytes other than the first pair.
movf Ax,W
This instruction simply copies the next Ax byte to be added into WREG. The MOVF instruction does not affect the carry bit generated from the last addition.
btfsc STATUS,C
This tests to see if a carry was generated by the previous stage of the addition. If there wasn't a carry then we can skip directly to the addition in step (4).
incfsz Ax,W
If there was a carry then we need to add Ax + 1 to Rx instead of just Ax but if Ax was h'ff' then incrementing it will cause it to overflow leaving h'00' in WREG. When this happens the there is no need perform an addition with Rx (i.e. Rx + h'00' = Rx) but we must pass the carry flag, which is unaffected by the INCFSZ instruction, on to the next stage by skipping step (4).
addwf Rx,W
This performs the addition of either Ax (when there was no carry) or Ax + 1 (if there was a carry but Ax wasn't h'ff') to Rx.
If we wanted to add two values and store the result in a different set of file registers (e.g. R = A + B) then the easiest way is to combine a value copy (e.g. R = A) and with the addition (e.g (R = A) += B).
; 16-bit Addition (All Devices) movf B0,W addwf A0,W movwf R0 movf A1,W movwf R1 movf B1,W btfsc STATUS,C incfsz B1,W addwf R1,F ; 24-bit Addition (All Devices) movf B0,W addwf A0,W movwf R0 movf A1,W movwf R1 movf B1,W btfsc STATUS,C incfsz B1,W addwf R1,F movf A2,W movwf R2 movf B2,W btfsc STATUS,C incfsz B2,W addwf R2,F ; 32-bit Addition (All devices) movf B0,W addwf A0,W movwf R0 movf A1,W movwf R1 movf B1,W btfsc STATUS,C incfsz B1,W addwf R1,F movf A2,W movwf R2 movf B2,W btfsc STATUS,C incfsz B2,W addwf R2,F movf A3,W movwf R3 movf B3,W btfsc STATUS,C incfsz B3,W addwf R3,F
The enhanced mid-range and high performance devices have an ADDWFC instruction that does include the carry flag in the calculation, making the code sequences simpler and faster.
; 16-bit Addition (Enhanced Mid-Range and High Performance devices) movf A0,W addwf R0,F movf A1,W addwfc R1,F ; 24-bit Addition (Enhanced Mid-Range and High Performance devices) movf A0,W addwf R0,F movf A1,W addwfc R1,F movf A2,W addwfc R2,F ; 32-bit Addition (Enhanced Mid-Range and High Performance devices) movf A0,W addwf R0,F movf A1,W addwfc R1,F movf A2,W addwfc R2,F movf A3,W addwfc R3,F
This also makes it much easier to handle the case where the result of the addition is stored in a separate area.
; 16-bit Addition (Enhanced Mid-Range and High Performance devices) movf B0,W addwf A0,W movwf R0 movf B1,W addwfc A1,W movwf R1 ; 24-bit Addition (Enhanced Mid-Range and High Performance devices) movf B0,W addwf A0,W movwf R0 movf B1,W addwfc A1,W movwf R1 movf B2,W addwfc A2,W movwf R2 ; 32-bit Addition (Enhanced Mid-Range and High Performance devices) movf B0,W addwf A0,W movwf R0 movf B1,W addwfc A1,W movwf R1 movf B2,W addwfc A2,W movwf R2 movf B3,W addwfc A3,F movwf R3
It should come as no surprise that a device that can't propagate a carry during addition, can't propagate a borrow during subtraction either. Fortunately the same approach of using a sequence of conditional instructions to adjust the data values can be applied.
The following code implements subtraction for various size values held in registers A0-3 with the values in R0-3 leaving the result in R0-3 (e.g. R -= A).
; 16-bit Subtraction (All Devices) movf A0,W subwf R0,F movf A1,W btfss STATUS,C incfsz A1,W subwf B1,F ; 24-bit Subtraction (All Devices) movf A0,W subwf R0,F movf A1,W btfss STATUS,C incfsz A1,W subwf R1,F movf A2,W btfss STATUS,C incfsz A2,W subwf R2,F ; 32-bit Subtraction (All devices) movf A0,W subwf R0,F movf A1,W btfss STATUS,C incfsz A1,W subwf R1,F movf A2,W btfss STATUS,C incfsz A2,W subwf R2,F movf A3,W btfss STATUS,C incfsz A3,W subwf R3,F
Again it is a re-occurring pattern of four instructions that handle the propagation of the borrow from one byte to the next during the calculation.
movf Ax,W
As in the addition pattern this instruction simply loads WREG with the next byte value that is going to be subtracted.
btfss STATUS,C
This instruction tests if the last stage of the subtraction generated a borrow (e.g. C == 0). If there is no borrow to be performed then we can skip directly to the subtraction in step (4).
incfsz Ax,W
If there is a borrow to be accounted for then we must subtract Ax + 1 from Rx instead of just Ax, but as with addition if Ax is h'ff' before the increment then it will overflow becoming h'00'. In this case there is no need to perform a subtraction from Rx, because we'd be subtracting zero, but we much pass the borrow on to the next stage instead, skipping step (4)
subwf Rx,F
This instruction subtracts either Ax (if there was no borrow) or Ax + 1 (if there was a borrow but Ax didn't overflow) held in WREG from Rx to generate the next result byte. If WREG contains a bigger value than Rx then a borrow will be generated for the next stage.
As with addition we can combine the subtraction with a value transfer to create a sequence for R = A - B
; 16-bit Subtract (All Devices) movf B0,W subwf A0,W movwf R0 movf A1,W movwf R1 movf B1,W btfss STATUS,C incfsz B1,W subwf R1,F
Again enhanced mid-range and high performance processors have a additional instruction, SUBWFB, that propagates the borrow as part of its operation making subtraction more efficient on these devices.
; 16-bit Subtraction (Enhanced Mid-Range and High Performance devices) movf A0,W subwf R0,F movf A1,W subwfb R1,F ; 24-bit Subtraction (Enhanced Mid-Range and High Performance devices) movf A0,W subwf R0,F movf A1,W subwfb R1,F movf A2,W subwfb R2,F ; 32-bit Subtraction (Enhanced Mid-Range and High Performance devices) movf A0,W subwf R0,F movf A1,W subwfb R1,F movf A2,W subwfb R2,F movf A3,W subwfb R3,F
And as with addition the sequences for R = A - B are also much simpler.
; 16-bit Subtraction (Enhanced Mid-Range and High Performance devices) movf B0,W subwf A0,W movwf R0 movf B1,W subwfb A1,W movwf R1 ; 24-bit Subtraction (Enhanced Mid-Range and High Performance devices) movf B0,W subwf A0,W movwf R0 movf B1,W subwfb A1,W movwf R1 movf B2,W subwfb A2,W movwf R2 ; 32-bit Subtraction (Enhanced Mid-Range and High Performance devices) movf B0,W subwf A0,W movwf R0 movf B1,W subwfb A1,W movwf R1 movf B2,W subwfb A2,W movwf R2 movf B3,W subwfb A3,W movwf R3
© Copyright 1999-2018 Andrew John Jacobs. All rights reserved.
All trademarks and service marks are the properties of their respective owners.