Developing Software in Assembly Language
6812 Assembly Language Examples
By Jonathan W. Valvano
This article, which discusses assembly language programming,
accompanies the book Embedded Microcomputer Systems: Real Time Interfacing published by Brooks-Cole 1999. This document has four overall
parts
Overview
Syntax (fields, pseudo ops)
Local variables
Examples
Stack Usage and Interrupts on the 6812
parameter passing in C
stack initialization and overflow check
setting interrupt vectors
Other Examples
Arithmetic Examples on the 6812
Shift Examples on the 6812
FIFO Queue Examples on the 6812
Interpreters on the 6812
Control Structure Examples on the 6812
--------------------------------------------------------------------------------------
How parameters are passed in C
In order to understand both the machine architecture and the C
compiler, we can look at the assembly code generated. This example
shows a simple C program with three global variables x1,x2,x3, two local variables both called y and three function parameters z1,z2,z3.
int x1;
static int x2;
const int x3=1000;
int add3(int z1, int z2, int z3){ int y;
y=z1+z2+z3;
return(y);}
void main(void){ int y;
x1=1000;
x2=1000;
y=add3(x1,x2,x3);
The compiler we will study is the ImageCraft ICC12 version 5.1 for the Motorola 6812. The linker/loader allocates 3 segmented memory areas: code pointed to by the PC; global accessed with absolute addressing; and locals pointed to by the stack pointer SP. The global symbols, _x1 _x2_x3, will be assigned or bound by the linker/loader. The three instructions pshx tfr s,x and leas -8,sp allocates the local variable, and establishes a stack frame pointer, X. This compiler passes the first input parameter (z1) into the subroutine by placing it in register D. The remaining parameters (z2, z3 in this example) are pushed on the stack by the main program before the subroutine is called. The first operation the subroutine performs is to push the remaining parameter on the stack (pshd) so that all three parameters, z1 z2 z3, are on the stack. Also notice that the main program allocates space for the parameters it needs to push when it calls add3 at the beginning of main.
--------------------------------------------------------------------------------------
Stack initialization and overflow check on the 6812
InitialSP equ $0C00
StackSize equ 100
StackBoundary equ InitialSP-StackSize
;********* this is the regular stack initialization
main lds #InitialSP
;********* add this code to check for overflow*******
cps #StackBoundary
blo Overflow
; goes to Overflow if more than 100 bytes pushed
The following figure shows the stack before and after the bsr instruction is executed on the 6812.
The rts instruction will return to the program that called the subroutine.
The following figure shows the stack before and after the call instruction is executed on the 6812.
The rtc instruction will return to the program that called the subroutine.
--------------------------------------------------------------------------------------
Installing interrupt handlers
This first example places in ROM. The interrupt vectors
can not be changed at run time.
org $E000 ; ROM
main lds #$00FF ; initialize stack
bsr ritual ; initialization of hardware, data structures
loop
;* main program ******** foreground thread ********
bra loop ;repeat forever
;***called by software using SWI instruction ********
SWIhan
;SWI handler
rti
;***called periodically by clock hardware ********
RTIhan
;RTI handler
rti
;***called by external IRQ hardware or KeyWakeupD ********
IRQhan
;IRQ handler
rti
;***called by external XIRQ hardware********
XIRQhan
;XIRQ handler
rti
; Assume interrupt vectors are in protected ROM
; the ROM vectors can't be changed dynamically
org $FFF0
fdb RTIhan ; $FFF0 is RTI vector
fdb IRQhan ; $FFF2 is IRQ vector (key wakeup D)
fdb XIRQhan ; $FFF4 is XIRQ vector
fdb SWIhan ; $FFF6 is SWI vector
org $FFFE
fdb main ; reset vector
This second example places indirect jmp instructions in
RAM so that the interrupt vectors can be changed at run time.
org $0800 ; RAM locations
; $0800 to $0802 contain a jmp to the RTI interrupt handler
rmb 3
; $0803 to $0805 contain a jmp to the IRQ interrupt handler
rmb 3
; $0806 to $0808 contain a jmp to the XIRQ interrupt handler
rmb 3
; $0809 to $080B contain a jmp to the SWI interrupt handler
rmb 3
org $F000 ; EEPROM
; Set the SWI interrupt vector dynamically
; input RegX points to SWIhandler
SetSWI movb #$06,$0809 ; install jmp opcode (extended)
stx $080A ; operand field of the jmp instruction
rts
; Set the XIRQ interrupt vector dynamically
; input RegX points to XIRQhandler
SetXIRQ movb #$06,$0806 ; install jmp opcode (extended)
stx $0807 ; operand field of the jmp instruction
rts
; Set the IRQ interrupt vector dynamically
; input RegX points to IRQhandler
SetIRQ movb #$06,$0803 ; install jmp opcode (extended)
stx $0804 ; operand field of the jmp instruction
rts
; Set the RTI interrupt vector dynamically
; input RegX points to RTIhandler
SetRTI movb #$06,$0800 ; install jmp opcode (extended)
stx $0801 ; operand field of the jmp instruction
rts
main lds #$0C00 ; initialize stack
ldx #SWIhand
bsr SetSWI ; dynamically install vector
bsr ritual
loop bsr func1
bsr func2
bra loop ;repeat forever
SWIhan
;... handler
rti
; Assume interrupt vectors are in protected EEPROM
; the EEPROM vectors can't be changed dynamically
org $FFF0
fdb $0800 ; $FFF0 is RTI vector
fdb $0803 ; $FFF2 is IRQ vector (key wakeup D)
fdb $0806 ; $FFF4 is XIRQ vector
fdb $0809 ; $FFF6 is SWI vector
org $FFFE
fdb main ; reset vector
For more information on interrupts, see Chapter 4 in the book,
Embedded Microcomputer Systems: Real Time Interfacing by Jonathan W. Valvano, Brooks/Cole Publishing Co., December
1999.
The following figure shows the stack before and after the swi instruction is executed. A hardware interrupt will also push registers on the stack, and set the I bit.
The rti instruction is used to return from a hardware or a software interrupt.
This document has four overall parts
Overview
Syntax (fields, pseudo ops)
Local variables
Examples