PIC Instructions
Links Mentioned
None

Links
Home
AWC

Microchip
PicList


Home
Introducing the PIC
Selecting a PIC
A Programmer
Hardware Tools
Software Tools
Downloading
Fixing the Blink
A Numeric Example
The Details
Special Registers
PIC Instructions



The PIC has a very small instruction set. This is a good thing because it makes the PIC easy to learn. However, the downside is that you can't do very much with one instruction. Here is a summary of the most common instructions:

MOVLW

Example:

	MOVLW 10

Side effects: none

The W register is central to most programs. This instruction moves a constant into the W register. Be careful to note what radix the assembler is using by default if you don't specify a base explicitly (for example, MOVLW 0x33 specifies hex 33). You'll sometimes see numbers written with a period in front of them. This forces a decimal interpretation (for example, MOVLW .10).

MOVF, MOVWF

Examples:

    MOVF temp,W
    MOVF temp,F
    MOVWF temp

Side effects: Sets or clears Z flag (MOVF); none (MOVWF)

These instructions allow you to move data between registers and the W register. The first example moves the value in register temp into W. The third example moves W into temp. The second example moves the value of temp into temp. At first, that seems pointless, but it sets the Z condition flags without disturbing anything else, so it is useful for conditional jumps. If the number moved is 0, the Z flag is set. Otherwise it is cleared.

While you can use a number for a register is is more common to name them using EQU or the cblock directive. For example:

temp  equ  0x70
      movlw 0x10
      movwf temp

The cblock directive allows you to define several bytes together. For example:

	cblock 0x70
	temp
	x, y
	endc

This bit of assembler defines 3 bytes that will be at locations 0x70 (temp), 0x71 (x), and 0x72 (y). Note that if you put multiple items on the same line, you need a comma between them.

When using cblock, you can also specify an increment by using a colon after each name. So for example:

	cblock 0x70
	temp:0, temp_hi, temp_lo
	x, y
	endc

This snippet creates a variable called temp at 0x70. The variable temp_hi is also at 0x70 and temp_lo is at 0x71 (x and y are at 0x72 and 0x73). Presumably, we meant for temp to hold 16 bits in this example. You might write:

	cblock 0x70
	temp
	x, y
	arraybase:0x10
	ptr
	endc

This would put ptr 0x10 bytes after arraybase.

ADDWF, ANDWF, IORWF, SUBWF, XORWF

Example:

	ADDWF temp,W
	XORWF x,F

Side effect: Modifies C, DC, Z (ADDWF, SUBWF); modifies Z (ANDWF, IORWF, XORWF)

These instructions do the specified operation on the W register and another register of your choice. Add and subtract work as you'd expect. The logical AND, IOR (inclusive OR) and XOR functions are the classic boolean logic primitives.

The result can be placed in the W register or back in the original register depending on how you write the instruction. For example:

	MOVLW 1  	; put 1 in W
	ADDWF temp,F   	; add 1 to temp, store in temp
; w still equals 1 here
	ADDWF x,W	; W=x+W, x is unchanged

When adding, if the result won't fit in a single byte, the C flag is set.

The subtraction operation always computes F-W, so be careful that you don't mean W-F. So if W contains 3 and x contains 10, performing a subtraction will result in 7. When subtracting, the C bit is a borrow flag. If the result was negative, then C will equal 0. If the C flag is 1, no borrow occurred. So computing 10-3 leaves C=1. But computing 3-10 will clear C. The result, in this case will be 0xF9 which is the two's compliment representation of -7.

To compute the two's compliment of a negative number, write the magnitude as a binary number. So for 7, we have 00000111. Then invert all the bits (11111000) and add 1 (11111001). You can easily reverse the process, so if I tell you the subtraction yields 0xF9, you can write it as binary (11111001), subtract 1 (11111000) and then invert the bits (00000111) to know that it means -7. When using this scheme the topmost bit acts like a sign bit.

The only problem is you can't readily tell a positive overflow from a negative number. For  example, 0x70 is a positive number. Adding 0x70 to 0x70 yields 0xE0 which is correct, but is indistinguishable from a negative number. Therefore when performing signed arithmetic, you are limited to numbers from -128 to 127.

There is also a DC flag which acts like the C flag, but it is set or cleared based on the carry (or borrow) condition of the low 4 bits of the operation. This can be useful when performing binary coded decimal (BCD) operations.

All the instructions in this section set the Z flag if their result is zero. Otherwise, the Z flag is cleared.

ADDLW, ANDLW, IORLW, SUBLW, XORLW

Example:

	ADDLW .30
	XORLW 0x80

Side effect: Modifies C, DC, Z (ADDLW, SUBLW); modifies Z (ANDLW, IORLW, XORLW)

These instruction act just like the normal add, subtract, and, inclusive or, and exclusive or instructions except they operate on a literal. So:

	ADDLW 2

adds 2 to W (and, of course, leaves the result in W). All the flags are modified just as they are in the register-based versions of these instructions (see above). The subtract instruction computes literal-W which is often confusing. So instead of writing:

	SUBLW 2  ; computes 2-W

You probably meant to write:

	ADDLW -2  ; This is probably what you really want

Adding negative 2 will get you the result you want without having to do unnecessary steps.

CLRF, CLRW

Example:

	CLRF temp
	CLRW

Side effect: Sets the Z flag to 1

It is a very common operation to load a zero into a register and this instruction can do that in one step. The CLRW instruction clears W, which is odd since MOVLW 0 will do this also. Unlike some processors, the PIC stores the literal inside the instruction, so a CLRW and a MOVLW 0 take the same amount of program space. The only difference is MOVLW will not change the Z flag, while CLRW will.

COMF

Example:

	COMF temp,W

Side effect: Modifies Z

This instruction inverts the bits in the register specified. You can store the result in W (,W) or back to the register (,F). The Z flag will be set if the result is zero, or cleared otherwise. If you want to invert the bits in the W register, execute XORLW 0xFF which has the same effect.

INCF, DECF

Example:

	INCF temp,W
	DECF x,F

Side effect: Modifies Z

Another common operation is to add or subtract 1 from a register. These instructions do that (INCF is +1; DECF is -1). These operations affect the Z flag (setting it if the result is zero) but do not modify the C or DC flags. As usual, you can store the result in W or back to the register. If you want to increment or decrement W try ADDLW 1 or ADDLW -1.

INCFSZ, DECFSZ

Example:

	INCFSZ temp,W
	DECFSZ x,F

Side effect: May modify program counter

These instructions are similar to INCF and DECF. They add or subtract one from the indicated register and store the result as directed. However, these instructions don't set the Z flag. Instead, if the result is zero, they skip the next instruction. This is useful, of course, for loops. Here's an example:

	CLRF  y
	MOVLW .10  ; 
	MOVWF i	   ; i=10
	MOVF x,W   ; W=X
LOOP:	ADDWF y,F  ; Y=Y+X
	DECFSZ i,F
	GOTO LOOP
; Leave here with the answer in y

Can you guess what this loop does? Click here to find out!

NOP

Example:

	NOP

Side effect: None

This instruction does nothing. It is often used in timing loops to waste time. If you are using a lot of these, you might consider other ways to waste time. For example, GOTO $+1 is one instruction that wastes 2 cycles.

If you already have a return somewhere in your program, you can use it to get a single instruction to waste 4 instruction cycles. Suppose your code has a label WASTETIME that is in front of some existing RETURN instruction. Then you can execute CALL WASTETIME. This deep sixes 4 instruction cycles with one instruction.

RLF, RRF

Example:

	RLF temp,F

Side effect: Modifies C

These instructions move the bits in the register left by one bit (RLF) or right (RRF). The extra bit that is shifted in comes from the C flag, and the bit that is shifted out goes to the C flag. So if you set C=1 and perform an RLF on a register that contains 0x81, the result will be 0x03 and the C flag will be set.

This is often useful to manipulate bits, but there is another interesting property: shifting left multiplies a number by 2 and shifting right divides by 2! You can often combine this with adding to get easy multiplications. For example, suppose you want to compute y=10*x. Well, that is the same as y=8*x+2*x, right? So try this:

	BCF status,C  	; C=0
	RLF x,F  	; X=2*X
	BCF status,C
	RLF x,W		; W=2*X (so 4*X)
	MOVWF temp
	BCF status,C
	RLF temp,W	; W=2*X (so 8*X)
	ADDWF x,W	; W=8X+2X = 10X
	MOVWF y

There isn't an easy way to combine right shifts for division, but if you need to divide by 2, 4, 8, 16, etc. then you can simply combine shifts.

SWAPF

Example:

	SWAPF temp,w

Side effect: None

This peculiar command moves the low 4 bits of the register to the top 4 bits and the top 4 bits of the register to the bottom 4 bits. You can put the result back in the register or in W. So if a register contained, say, 0xA5 and you execute SWAPF, the result will be 0x5A.

This instruction can be useful when working with BCD or hex numbers. However, it is also useful when you want to move a register to or from W without affecting any flags:

	SWAPF temp,F
	SWAPF temp,W  ; move temp to W with no flag changes
; If you want temp back the way it was, you need one more instruction:
	SWAPF temp,F

BCF, BSF

Example:

	BCF status,Z

Side effect: None

These instructions clear (BCF) or set (BSF) the indicated bit in a register. The bit may have a name (like Z) or you can use a number from 0 to 7 (0 is the least significant bit and 7 is the most significant). Sometimes you can use these to save a few instructions. For example, suppose you had written:

	MOVLW 0x7F
	ANDWF temp,F

You could replace this with a single BCF temp,7 instruction. Not only is this faster and takes less space, but it doesn't destroy the W register either!

GOTO

Example:

	GOTO main

Side effect: None

As you'd expect, the GOTO instruction forces your program to resume execution at the label you indicate. The instruction only holds an 11  bit address, so the top bits of the new program counter come from the PCLATH register.

CALL, RETURN

Example:

	CALL hexout
	RETURN

Side effect: None

A CALL is similar to a GOTO with one big exception: the value of the program counter is saved on an internal stack. When the program later executes a RETURN, the program will resume executing after the CALL instruction. The internal stack of a PIC16F87x, for example, is 8 levels deep.

Like the GOTO, the CALL instruction takes the top part of the address from PCLATH.

You can save some stack depth, code space, and execution time by watching for subroutines that call another subroutine right before they are done. For example, suppose you program contains this:

suba:	CALL subb
	CALL subc
	RETURN

You could rewrite it more efficiently like this:

suba:	CALL subb
	GOTO subc

RETLW

Example:

	RETLW .99

Side effect: None

RETLW is exactly like RETURN except that it loads a literal value into the W register before it returns.

RETFIE

Example:

	RETFIE

Side effect: Sets GIE

RETFIE is exactly like a return, but it also sets the global interrupt enable (GIE). When a hardware interrupt occurs, it clears GIE and executes what amounts to a CALL instruction. Using RETFIE allows you to enable interrupts and return to the main program all in one step. If you don't want interrupts enabled again, just execute a RETURN instead.

BTFSC, BTFSS

Example:

	BTFSS temp,7

Side effect: May modify program counter

When you want to perform a conditional jump, you need one of these instructions. They test a bit and skip the next instruction if the bit is set (BTFSS) or clear (BTFSC). Most often the next instruction is a GOTO or a CALL, but it could be any single instruction. For example, this code tests temp to see if it is zero. If it is, it loads temp with 0x80. Otherwise, temp is unchanged:

	MOVF temp,F  	; set Z flag, no data really moved
	BTFSC status,Z  ; skip if not zero
	BSF temp,7 	; since temp was 0, now it is 0x80!  

CLRWDT

Example:

	CLRWDT

Side effect: None

This instruction informs the watchdog timer that your program is still executing. If you aren't using the watchdog, you don't need this instruction.

SLEEP

Example:

	SLEEP

Side effect: None

Putting the processor to sleep allows it to consume very little power, but you'll need an interrupt or a reset to wake it back up.

Notes!

Some PIC processors have slightly different instruction sets, but if you know the above, you'll be able to handle the differences with just a little study. In addition, some assemblers for the PIC use very different mnemonics for the same instruction set. This tutorial focuses on the Microchip standard mnemonics.

Back