PICmicro® assembly code
Addressing modes
Addressing modes refers to how assemblers resolve and use instructions and their data. The mid-range PIC family generally supports two main addressing modes: immediate (for literal or constant operations), and direct (for register or data operations).
Immediate mode provides the data as part of the instruction. For example movlw 4 moves the data '4' into the W register.
Direct mode operations point to the register that contains the data. For example, addwf 25h tells the microcontroller to add the contents of W to the contents of the register at address 25h in the microcontroller's data memory.
A third, indirect, address mode is available through a hardware register operation. In this mode, the the instruction acts on a register that contains a pointer to the register containing the data. However, unlike in many other types of microcontrollers, indirect addressing in the PIC is not considered as a separate addressing mode since it can only be done using a direct mode operation on one specific hardware register.
Source and destination order
Although assembly code is similar for all microprocessors, there is one big difference between Micochip's format (and others, too) and that used by Intel in their desktop microprocessors. Micorchip assembly code follows a 'from-to' order, like this:
addwf 25h
Think of the instruction as a short form of 'add W to file register 25h'. It adds the number in W to the number in file register 25h, and leaves the result in file register 25h. The order of the 'wf' part of the instruction implies the order of the addition.
Intel format reverses the source and destination so that they are in a 'to-from' order. For demonstration purposes, this would be the equivalent (and, imaginary) Intel format instruction:
addfw 25h
The data in W and register 25h are still added together, as they were in the Microchip instruction. But now, instead of meaning 'add W to file register 25h', think of the instruction as meaning 'add to file register 25h from W'. It's a backward reference.
Of course, whichever way that you learn assembly code first is the one you'll consider to be the right way, and the other way just seems wrong! This is the stuff of 'religious wars' between programmers who grew up on different microprocessor architectures. But the to-from order that the PIC uses is right, of course!
What is assembly code?
Assembly code is a human-readable form of the machine code instructions that control microcontrollers and microprocessors, though assembly code is actually a hybrid program composed of more than just microcontroller instructions. Assembly code contains short instruction words, often in the form of acronyms called mnemonics, statements that control the assembler itself, called directives, and also comments used by programmers to describe the operation of their code to other humans.
Assembly code programs are created written in a text editor, and these programs are referred to as source code. The completed source code text file is read by an assembler, which is a program that normally runs on a personal computer and compiles the source code into machine code, also called hex code, for programming into the microcontroller. Got that? It's simple, really. Source code gets made into machine code by the assembler. We'll look at an example program shortly.
How do assembly and other languages compare?
Programming in assembly code is considered low-level programming because it is done at the level of the microprocessor's logic and hardware capabilities. Low-level programming languages require the programmer to be intimately familiar with the computer hardware, and to create their own program subroutines to accomplish higher-level functions such as writing charaters to an LCD, or reading keyboard input. The primary advantages of using assembly code are that programs can be easily modified to work with new or customized hardware, and that assembly code programs typically run very fast, making very efficient use of limited resources or processing power.
Assembly code is not without its drawbacks, however. The primary disadvantage of assembly code is increased code complexity, making it more difficult and time consuming for programmers to create, edit and debug assembly code programs than those written in a high-level language. Because assembly code is more complex, it becomes more difficult to write large programs in assembly code. That's why most desktop computer programs are written in higher-level languages like C++ or Java—it's easier to do, and desktop programmers don't need to concern themselves with the intimate details of the computer hardware (that's what drivers do, and drivers are often written in assembly code).
Why use assembly code?
Despite the challenges, assembly code has some big advantages in microcontroller circuits such as the ones on this site. Assembly code is ideal for controlling hardware, because its instructions relate directly to the hardware. Circuits such as the UFO are designed primarily to do one simple task, like flash LEDs. The UFO hardware is simple, and its task is simple, which makes programming the UFO in assembly code a reasonably straighforward excercise.
What does assembly code look like?
Although the assembly code mnemonics are unique to each family of microcontrollers, all assembly code shares some common characteristics. Assembly code programs are line-based, with each line of code divided into distinct fields, or columns. These columns are:
Label instruction data ;comments
Using actual assembly code instructions, a section of program code might look like this:
Count movlw 4 ;Load W with 4 and addwf 25h ;add to counter register goto Count ;Repeat forever
Let's examine each line in detail.
Count is a label—a name for a section of code. All comments must begin at the left-hand margin of the text file.
movlw is an instruction mnemonic representing the operation that moves a literal into W. W is an internal register in the processing unit of the PIC which, in this case, becomes loaded with the data, or literal, '4'. Some instructions require data, others operate without data.
Comments in Microchip code follow a semi-colon, and are important in describing the code an maintaining its readability. Comments usually appear after instructions and data, but can be located anywhere in the code as long as they follow a semi-colon.
Notice that the second line contains only and instruction, data, and comment. Labels are optional.
addwf is an instruction that adds the contents of the W register to the contents of a memory register, in this case the RAM address 25h. Whatever number was in register 25h will be higher by 4 after this instruction executes.
The goto on the third is a control instruction. Its data 'Count' is interpreted by the assembler at build time and converted into the numeric address of the Count label. In other words, the program loops back to Count and repeats forever.
Notice that the data field can represent a 'real' or immediate number, or a direct reference to a register that holds a number, or a relative reference to label.
All of the fields, or columns, in assembly code are commonly separated by tab characters.
Of course, there's more to an assembly code program than this simple code sample shows. Assembly code programs generally start with a program header that includes directives to set up the processor and programming environment, and continues with one or more subroutines and perhaps a data array.
What happens to the assembly code file?
Once the assembly source code for the microcontroller is written, it is 'assembled' (or built, compiled, or made) into machine code by an assembler program running on a desktop computer. As the assembler compiles the program, it checks for syntax errors, and resolves all of the references before turning the program into machine code. Some assemblers use a slightly different syntax for their references or directives. The examples on this site are designed for the free MPLAB IDE (Integrated Development Environment), which includes a source file editor, assembler, simulator and downloader. After the program is assembled, it is time to download it into the target microcontroller.
What is downloading?
Downloading is the process of transferring the compiled machine code into the microcontroller for operation or testing. This is generally accomplished by tethering your desktop computer to a stand-alone programmer, or to hardware that allows your microcontroller to be programmed in-circuit. Some downloaders also have in-circuit emulation and debugging facilities to assist in troubleshooting the program or hardware circuits.

