Introduction to Assembly Language Programming

October 21, 07 by admin

Assembly programming is low-level programming using some basic syntax to represent machine code for a specific CPU. An assembler is used to translate the assembly code into the machine code for the target computer.

A program created from assemblhy can be more efficient and faster than a program created with a compiler. One example of why this occurs is because a compiler will store intermediate values used in a calculation in memory whereas a program written in assembly can store the intermediate values in a register which is much faster. However, while there may be performance benefits to programming so close to the machine level, there is a great deal of added complexity which a high-level programming language can remove.

Table 5.1 Source Code Fields [1]

Label Field Opcode Field Operand(s) Field Comment Field
Example: ldaa #$64 ; Initialize A with hexadecimal 64
  • A label must start with an alphabetic character
  • The label must start in the first column of the source code line unless it ends with a colon.
  • Uppercase and lowercase characters are distinct by default but case sensitivity may be turned off.
  • A label may end with a colon (:)
  • A label may appear on a line by itself
  • The label is optional but when used it can provide a symbolic memory reference such as a branch instruction address, or a symbol for a constant.
  • The opcode field contains either a mnemonic for the operation, an assembler directive or pseudo-operation, or a macro name. For the opcode field, the assembler will convert all uppercase letters to lowercase so this field is not case sensitive.
  • The interpretation of the operand field depends on the opcode.
  • The operand must follow the opcode.
  • Operands can be the symbols, constants, or expressions that are evaluated by the assembler.
  • The operand field also specifies the addressing mode for the instruction.

Using Macros

A macro can be used to give a symbolic name to a group of instructions that are used often. In the source code the macro should be given a name using the label field and then two commands (MACRO & ENDM) are used to indicate the start and finish of the macro. The assembler will then replace every occurrence of the macro with the set of instructions.

Add_B_and_C: MACRO
  MOV A,C
ADD A,B
MOV C,A
ENDM

Macro vs Sub-Routine

A macro and a sub-routine are similar except for the following differences:

  • With a sub-routine the code is present only once. With a macro, the code is inserted in the place of the macro whenever it is used. Therefore, if macros are used instead of sub-routines, the code will end up being longer.
  • With a sub-routine a jump must occur in order to find and execute the sub-routine code. With a macro, this is not required because the code has already been inserted directly. Therefore, a sub-routine will be slightly slower than a macro.

Using either a sub-routine or a macro makes changing the code much easier because changes can be done in one place rather than in each specific location where the code would be used. They also make the code easier to understand.

Assembler Instructions

ORG – Set the program counter to the origin of the program

EQU – Associate the value of an expression with a symbol

SET – Can be used instead of equal. With set, the value can be redefined

DC – Define a constant value

DCB – Define a constant block

DS – Define storage

Example 5-9 ORG – Set Program Counter to Origin for Absolute Assembly [1]

0000 c000 ROM: EQU $c000 ; Location of ROM
0000 0800 RAM: EQU $0800 ; Location of RAM
0000 0A00 STACK: EQU $0a00 ; Location of stack
  ;      
    ORG ROM ; Set program counter to ROM
  ;      
00c000 CF0a 00   lds #STACK ; Initialize SP
00c003 B608 00   ldaa Data_1 ; Load from memory address RAM
  ;      
    ORG RAM ; set program counter
        ; to RAM for the data
000800 Data_1: DS.B $20 ; Set aside $20 bytes

Software Development Process

When programming in any language, following a good development process is necessary in order to deliver a successful product. It is important to resist the urge to jump right into the code immediately, especially when programming in assembly which is extremely complex.

The first step should always be to clearly identify the problem and define a solution to solve that problem. Create and understand the solution in diagrams or pseudo-code before beginning to code in assembly. Translating these diagrams into code will be much easier than trying envision the solution entirely in your mind.

Debugging and tracing through your assembly program will also be a very good way at finding and correcting bugs.

Typical Bugs Include:

  • Incorrect transfer to sub-routine
  • Forgetting to initialize the stack pointer
  • Not enough memory in the stack
  • Sub-routines corrupting registers
  • Forgetting to initialize index registers
  • Modifying the condition code registers before branching
  • Using the wrong branching instruction
  • Using the wrong addressing mode

D-Bug12
The D-Bug12 is the debugging tool stored in the EEPROM of our microcontroller that will be used for debugging as well as for downloading programs onto the card and controlling the assembler.

D-Bug12 Commands

ASM – Assemble/Dissasemble

BF – Block Fill Memory

BR – Set Breakpoint

CALL – Call and execute subroutine

G – Go, run program

GT – Go till an address

HELP – Prints summary of available commands

LOAD – Set in state ready to accept program download from MiniIDE

MD – Display Contents of Memory

MM – Modify Memory

MOVE – Copy block of memory

NOBR – Remove breakpoints

RD – Display register contents

T – Trace through program

UPLOAD – Upload memory to PC

USEHDB – Use EVB/Target hardware breakpoints

VERIF – Compare memory to download file

[1] Fredrick M. Cady, Software and Hardware Engineering: Assembly and C Programming for the Freescale HCS12 Microcontroller
[2] Prof. Gilbert Arbez, University of Ottawa CSI3531 Course Notes, Module 3

This entry no have comments... but you can be first.

Leave a Reply