Assembler Directives
Assembler directives are commands inserted in PIC source code that control the operation of the assembler. They are not part of the program itself and are not converted into machine code. Many assembler directives will only be used when a good knowledge of the programming language has been achieved, so we will refer to a small number of the more useful ones at this stage. Some of these are demonstrated in Program 6.5, ASD1. In order that the effect of the directives can be seen, the list file is reproduced here rather that just the source code, which can be seen in the right-hand columns.
The assembler directives are placed in the second column of the source code. They are not case sensitive, but are conventionally written in upper case to distinguish them. We have already met some of the most commonly used directives, but END is the only one that is essential. All the others are simply available to make the programming process more efficient. For definitive information refer to the documentation and help files supplied with your current assembler version. Some of the more useful directives are explained below.
PROCESSOR
This directive specifies the PIC processor for which the program has been designed, and allows the assembler to check that the syntax is correct for that processor. In MPLAB, the MCU type can also be specified via the menu items Configure, Select Device. It is therefore not essential to use this directive in MPLAB, but it is required if using the bare assembler in the Proteus VSM simulator. The include file also specifies the processor, if used (see INCLUDE directive below).
CONFIG
In MPLAB, the menu selection Configure, Configuration Bits opens a window where the configuration bits can be set up prior to downloading, but this will be overridden by the source code CONFIG directive if the ‘Configuration Bits set in code’ box is checked. The double underscore that starts the directive indicates an operation on the MCU registers. The significance of each bit is shown in the MCU data sheet. The configuration bits for two sample chips are shown in Table 6.1.
In the 16F84A, only clock type, power-up timer, watchdog and code protection need configuring. There are more options in the 16F690, reflecting the more extensive range of peripheral features. Bits 0, 1 and 2 set the clock type (111 ¼ RC, 001 ¼ XT, 010 ¼ HS, 101 ¼ INTOSC), bit 2 disables the watchdog timer if cleared and bit 3 enables the power-up timer if cleared. All the other bits are set to 1 to disable code protection, brownout protection and other clock options. In the list file ASD1.LST (Program 6.5), the bits are specified in binary, and the hex equivalent code and destination register (2007) are listed in the left column.
ORG
This sets the code ‘origin’, referring to the address to which the first instruction following this directive will be assigned. We have already seen (Program 6.2) how it is necessary to set the origin of the interrupt service routine as 004. The default origin is 000, the first program memory location, so if ORG is not specified, the program will be placed at the bottom of the memory. This is the reset address where the processor always starts on power-up or reset. If using interrupts, an unconditional jump ‘GOTO label’ must be used at the reset address 000, as the first instruction to take the execution point to the main program starts higher up the memory, above the ISR vector location. For in-circuit debugging, a NOP may be necessary in the second location (001).
LIST
A text file PROGNAME.LST is produced by the assembler, which contains the source code (with line numbers), machine code, memory allocation and symbol (label) table. This can be studied for error checking or reference using any text editor, or printed out. The LIST directive has a number of options which allow the format and content of the List File to be modified, e.g. number of lines and columns per page, error levels reported, processor type and so on. These can be selected in the MPLAB build output options. The three main elements of the list file are seen in Program 6.5, ASD1.LST: the main program, label definitions and memory map. In the main program section, the machine code and corresponding memory locations are listed in the left-hand columns. The memory map (Program 6.5c) summarizes the program memory usage and the assembler messages.
EQU
This is a commonly used directive for representing numerical values with a more memorable label (symbol in the list file). It is used in the include file (see below) to define standard symbols for the special function registers for a specific processor (e.g. PORTA), and by the user for
additional file register labels. The numerical value can be specified as hexadecimal, binary, decimal or ASCII (see Section 6.8, below). In the list file, all the user-defined labels’ values (constants, equates, addresses) are listed after the include file label values.
INCLUDE
This directs the assembler to include a block of source code from a named file on disk. If necessary, the full file path must be given, but if the file is copied into the application folder with the source code and the files generated by the assembler, only the file name is needed. In the example ASD1.LST (Program 6.5), the file P16F84A.INC provided by Microchip is included at line 18, but the listing has been suppressed, as it is 134 lines long. It defines labels for all the special function registers and individual control bits in this device, which can be seen in the label value listing (Program 6.5b). The file also includes directive codes for setting the configuration bits individually, e.g. directive _PWRTE_ON will switch on the power-up timer if used in the program header.
These standard header files, which use labeling that is consistent with the data sheet register names, are supplied with the development system files for all processors. They are currently found in the folder ‘MPASM Suite’ in the ‘Microchip’ system folder alongside the MPASMWIN.EXE file. The text file is included as though it had been typed into the source code editor, so it must conform to the usual assembler syntax; any program block,
subroutine or macro can be included in this way. This allows separate source code files to be combined together, and opens the way for the user to create libraries of reusable program modules.
MACRO …. ENDM
A macro is a block of source code that is inserted into the program by using its label as an instruction. In ASD1 (Program 6.5), for example, DELAY is the name of the macro, and its insertion in the main program can be seen in the list file. Using a macro is equivalent to creating a new instruction from standard instructions, or an automatic copy and paste operation. The directive MACRO defines the start of the block with a label, and ENDM terminates it. The advantage of a macro over a subroutine to perform the same function is that it is reduces overall execution time by eliminating the extra instruction cycle required by CALL and RETURN. It is therefore most suitable for short sequences or where speed is important. Subroutines, on the other hand, will use less memory, as they are only assembled once.
BANKSEL
This directive allows access to register banks other than the default, zero, which contains the main SFRs. In ASD1 (Program 6.5), it is used to access and initialize the port B data direction register. The operand is the register required (TRISB) and the effect is to set the register select bit(s) in the status register. Remember that bank 0 must be reselected before using the main SFRs. See Section 6.4.2 above for more details.
END
The END directive informs the assembler that the end of the source code has been reached.
This is the one directive that must be present; an error message will be generated if it is missing.
Pseudo-Instructions
These additional instructions are essentially macros that are predefined in the assembler. An example is shown in the program ASD1 (Program 6.5), ‘BNZ down’, which stands for ‘Branch if Not Zero to label’. It is replaced by the assembler with the instruction sequence Bit Test and Skip if Set and GOTO:
BNZ down ¼ BTFSS 3,2
GOTO down
The zero flag (bit 2) in the status register (register 3) is tested, and the GOTO skipped if it is set (as a result of the previous operation being zero). If the result was not zero, the GOTO is executed, and the program jumps to the address label specified (down).
Other examples are BZ (Branch if Zero), BC (Branch if Carry), BNC (Branch if no Carry). This type of instruction is included in the main instruction set of the more
powerful PICs. Other pseudo-instructions are simply alternative forms of standard instructions, such as SETC (¼BSF 3,0). LGOTO and LCALL are long jumps that
automatically adjust PCLATH for branch over program memory page boundaries (see PCLATH, Section 6.4.5 above).