Chapter 4
top element
bottom element low address
high address
Stack pointer
Figure 4.1 Diagram of the HCS12 stack
Introduction
• Program = data structures + algorithm
• Data structures to be discussed
– Stacks: a first-in-last-out data structure
– Arrays: a set of elements of the same type
– Strings: a sequence of characters terminated by a
special character
Table 4.1 HCS12 push and pull instructions and their equivalent load and store instructions
Mnemonic psha pshb pshc pshd pshx pshy pula pulb pulc puld pulx puly Function
push A into the stack push B into the stack push CCR into the stack push D into stack
push X into the stack push Y into the stack pull A from the stack pull B from the stack pull CCR from the stack pull D from the stack pull X from the stack pull Y from the stack
Equivalent instruction staa 1, -SP
stab 1, -SP none
std 2, -SP stx 2, -SP sty 2, -SP ldaa 1, SP+ ldab 1, SP+ none
ldd 2, SP+ ldx 2, SP+ ldy 2, SP+
HCS12 Support for the Stack Data Structure
• A 16-bit stack pointer (SP)
-Indexable Data Structures
• Vectors and matrices are
indexable data structures.
• The first element of a vector is
associated with the index 0 in
order to facilitate the address
calculation.
• Assemblers directives
db
,
dc.b
,
dc.b
are used to define
arrays of 8-bit elements.
• Assemblers directives
dw
,
dc.w
, and
fdb
are used to
define arrays of 16-bit
elements.
• Example 4.2
– Write a program to find out if
the array vec_x contains a
value key.
– The array has 16-bit elements
and is not sorted.
• Solution:
– Use the double accumulator to
hold the key.
– Use the index register X as a
pointer to the array.
– Use the index register Y to
hold the loop count.
• Need to compare key with
Start
i = 0 result = -1
vec_x[i] = key?
i = N - 1?
i = i + 1 result = address of vec_x[i]
Stop
Figure 4.3 Flowchart for sequential search yes
N equ 30 ; array count
notfound equ -1
key equ 190 ; define the searching key
org $1000
result rmw 1 ; reserve a word for result
org $1500 ; starting point of the program
ldy #N ; set up loop count
ldd #notfound
std result ; initialize the search result
ldd #key
ldx #vec_x ; place the starting address of vec_x in X
loop cpd 2,X+ ; compare the key with array element & move pointer
beq found
dbne Y,loop ; have we gone through the whole array?
bra done
found dex ; need to restore the value of X to point to the
dex ; matched element
stx result
done swi
vec_x dw 13,15,320,980,42,86,130,319,430,4, 90,20,18,55,30,51,37
Binary Search
• Step 1
– Initialize variables max and min to n -1 and 0, respectively.
• Step 2
– If max < min, then stop. No element matches the key.
• Step 3
– Let mean = (max + min)/2
• Step 4
– If key = arr[mean], then key is found in the array, exit.
• Step 5
– If key < arr[mean], then set max to mean - 1 and go to step 2.
• Step 6
Example 4.3
Write a program to implement the binary search algorithm
and also a sequence of instructions to test it.
Solution:
n equ 30 ; array count
key equ 69 ; key to be searched
org $1000
max ds.b 1 ; maximum index value for comparison
min ds.b 1 ; minimum index value for comparison
mean ds.b 1 ; the average of max and min
result ds.b 1 ; search result
org $1500
clra
staa min ; initialize min to 0
staa result ; initialize result to 0
ldaa #n-1
staa max ; initialize max to n-1
ldx #arr ; use X as the pointer to the array
loop ldab min
cmpb max lbhi notfound
addb max ; compute mean
stab mean ; save mean
ldaa b,x ; get a copy of the element arr[mean]
cmpa #key
beq found
bhi search_lo
ldaa mean
inca
staa min ; place mean+1 in min to continue
bra loop
search_lo ldaa mean
deca
staa max
bra loop
found ldaa #1
staa result
notfound swi
arr db 1,3,6,9,11,20,30,45,48,60
db 61,63,64,65,67,69,72,74,76,79
Strings
• A sequence of characters terminated by a NULL (ASCII code 0) or
other special character such as EOT (ASCII code 4).
• A number in the computer is represented as a binary number.
• A number must be converted to ASCII code before output so that it
can be understood.
• To convert a binary into an ASCII string, we divide the binary
number by 10 repeatedly until the quotient is zero. For each
remainder, the number $30 is added.
•
Example 4.4
Write a program to convert the unsigned 8-bit binary
number in accumulator A into BCD digits terminated by a NULL
character. Each digit is represented in ASCII code.
•
Solution:
test_dat equ 34 org $1000
buf ds.b 4 ; to hold the decimal string temp ds.b 2 ; "
org $1500 ldab #test_dat
lds #$1500 ; initialize stack pointer ldy #buf
tstb
bne normal movb #$30,buf
clr buf+1 ; terminate the string bra done
normal movb #0,1,-sp ; push a NULL into the stack clra
loop ldx #10
idiv
addb #$30 ; convert to ASCII code pshb ; push into stack
cpx #0 beq reverse
bra loop reverse tst 0,sp
beq done
movb 1,sp+,1,y+ bra reverse done swi
•
Example 4.5
Write a program to convert the
16-bit signed integer in D into a string of BCD digits.
•
Solution
– A signed 16-bit integer is in the range of -32768 to
+32767.
– A NULL character is needed to terminate the
converted BCD string.
test_dat equ -2478 org $1000
buf ds.b 7 ; to hold the decimal string org $1500
ldd #test_dat
lds #$1500 ; initialize stack pointer ldy #buf
cpd #0
bmi negate ; branch if the value is negative bne normal ; branch if the value is positive movb #$30,buf
clr buf+1 ; terminate the string bra done
negate coma ; when negative, complement the number comb ; "
addd #1 ; "
movb #$2D,1,y+ ; add minus sign and move pointer normal movb #0,1,-sp ; push a NULL into the stack
loop ldx #10
idiv
cpx #0 ; is the quotient zero? beq reverse
xgdx ; put quotient back to B bra loop
reverse tst 0,sp beq done
movb 1,sp+,1,y+ ; pop one byte and store it in buffer bra reverse
Algorithm to convert from ASCII string that represents a BCD number to a binary number
Step 1
sign 0
error 0
number 0
Step 2
If the character pointed to by in_ptr is the minus sign, then
sign 1
in_ptr in_ptr + 1
Step 3
If the character pointed to by in_ptr is the NULL character, then go to step 4.
else if the character is not a BCD digit, then
error 1; go to step 4;
else
number number * 10 + m[in_ptr] - $30;
in_ptr in_ptr + 1;
go to step 3; Step 4
If sign = 1 and error = 0 ,then
number two’s complement of number;
else
Example 4.6 Write a program to convert a BCD ASCII string to a binary number.
Solution:
minus equ $2D ; ASCII code of minus sign
org $1000
in_buf fcc "9889" ; input ASCII to be converted
dc.b 0 ; null character
out_buf ds.b 2 ; holds the converted binary value
buf2 ds.b 1 ; holds a zero
buf1 ds.b 1 ; holds the current digit value
sign ds.b 1 ; holds the sign of the number
error ds.b 1 ; indicates the occurrence of illegal character
org $1500
clr sign
clr error
clr out_buf
clr out_buf+1
clr buf2
ldx #in_buf
ldaa 0,x
cmpa #minus ; is the first character a minus sign?
bne continue ; branch if not minus
inx ; move the pointer
continue ldaa 1,x+ ; is the current character a NULL character? lbeq done ; yes, we reach the end of the string
cmpa #$30 ; is the character not between 0 to 9? lblo in_error ; "
cmpa #$39 ; "
lbhi in_error ; "
suba #$30 ; convert to the BCD digit value
staa buf1 ; save the digit temporarily
ldd out_buf
ldy #10
emul ; perform 16-bit by 16-bit multiplication
addd buf2 ; add the current digit value
std out_buf ; Y holds 0 and should be ignored
bra continue
in_error ldaa #1
staa error
done ldaa sign ; check to see if the original number is negative
beq positive
ldaa out_buf ; if negative, compute its two’s complement
ldab out_buf+1 ; “
coma ; “
addd #1 ; “
std out_buf
Character and Word Counting
• A string is terminated by the NULL character.
• A new word is identified by skipping over the
white space characters.
• When a new word is identified, it must be
Example 4.7 Write a program to count the number of characters and words contained in a given string.
Solution:
tab equ $09
sp equ $20
cr equ $0D
lf equ $0A
org $1000
char_cnt ds.b 1
word_cnt ds.b 1
string_x fcc "this is a strange test string to count chars and words."
dc.b 0
org $1500
ldx #string_x
clr char_cnt
clr word_cnt
string_lp ldab 1,x+ ; get one character and move string pointer lbeq done ; is this the end of the string?
inc char_cnt
; the following 8 instructions skip white space characters between words
cmpb #sp
beq string_lp
beq string_lp
cmpb #cr
beq string_lp
cmpb #lf
beq string_lp
; a non-white character is the start of a new word
inc word_cnt
wd_loop ldab 1,x+ ; get one character and move pointer
beq done
inc char_cnt
; the following 8 instructions check the end of a word
cmpb #sp
lbeq string_lp
cmpb #tab
lbeq string_lp
cmpb #cr
lbeq string_lp
cmpb #lf
lbeq string_lp
bra wd_loop
done swi
Start
Skip the white spaces to look for the next word in the string
Is the current word in the string equal to the word
to be searched?
Is this the end of the string?
Stop
yes
no
no
yes
Figure 4P.8 Flowchart of the word search program
Start
[str_ptr] = NULL? str_ptr string_x
match_flag 0
[str_ptr] = space, tab, CR, or lf? wd_ptr word_x
[str_ptr] = [wd_ptr] ?
[wd_ptr] = NULL?
[str_ptr] = NULL?
[str_ptr] = space, tab, CR, or lf? str_ptr str_ptr + 1
Stop no no Stop no yes str_ptr str_ptr + 1
yes
no
[str_ptr] = NULL?
match_flag 1 Stop wd_ptr wd_ptr + 1
str_ptr str_ptr + 1
str_ptr str_ptr + 1 yes yes yes yes no no no
[str_ptr] = space, tab, CR, lf, or punctuation
mark?
no yes
yes (matched) move to the next word
to be compared
compare two words
skip the unmatched
word
tab equ $09 ; ASCII code of tab
sp equ $20 ; ASCII code of space character
cr equ $0D ; ASCII code of carriage return
lf equ $0A ; ASCII code of line feed
period equ $2E ; ASCII code of period
comma equ $2C ; ASCII code of comma
semicolon equ $3B ; ASCII code of semicolon
exclamation equ $21 ; ASCII code of exclamation
null equ $0 ; ASCII code of NULL character
org $1000
match ds.b 1
org $1500 clr match ldx #string_x
loop ldab 1,x+
; the following 10 instructions skip white spaces to look for the next word in string_x tstb
beq loop
cmpb #lf
beq loop
; the first nonwhite character is the beginning of a new word to be compared
ldy #word_x
ldaa 1,y+
next_ch cba
bne EndOfWd
cmpa #null ; check to see if the end of word is reached
beq matched ; "
ldaa 1,y+ ; get the next character from the word
ldab 1,x+ ; get the next character from the string
bra next_ch
; the following 10 instructions check to see if the end of the given word is reached
EndOfWd cmpa #null
bne next_wd
cmpb #cr
beq matched
cmpb #lf
beq matched
cmpb #tab
beq matched
beq matched
cmpb #period
beq matched
cmpb #comma
beq matched
cmpb #semicolon
beq matched
cmpb #exclamation
beq matched
; the following 11 instructions skip the remaining characters in the unmatched word
next_wd ldab 1,x+
beq done
cmpb #cr
lbeq loop
cmpb #lf
lbeq loop
cmpb #tab
lbeq loop
cmpb #sp
lbeq loop
bra next_wd
matched ldab #1
done swi
string_x fcc "This string contains certain number of words to be matched."
dc.b 0
word_x fcc "This"
dc.b 0
String Insertion
(1 of 2)
• The pointers to the string and the substring to be
inserted are given.
• The insertion point is given.
insertion point
string
to be moved to the right Step
1 find out how many
characters need to be moved
count the # of characters to be inserted 2
make room for the substring to be inserted 3
4
insert the substring
Figure 4.6 Major steps of substring insertion
Example 4.9
Write a program to implement the string
insertion algorithm.
org $1000
ch_moved ds.b 1 ; number of characters to be moved
char_cnt ds.b 1 ; number of characters of the substring to be
inserted
sub_strg fcc "the first and most famous "
dc.b 0
string_x fcc "Yellowstone is national park."
dc.b 0
offset equ 15
ins_pos equ string_x+offset ; insertion point
org $1500
; the next 7 instructions count the number of characters to be moved
ldaa #1
staa ch_moved
ldx #ins_pos ; x points to the insertion point
cnt_moved ldaa 1,x+
beq cnt_chars
inc ch_moved
bra cnt_moved
cnt_chars dex ; subtract 1 from x so it points to the NULL character
ldy #sub_strg ; y points to the substring
clr char_cnt
; the following 3 instructions count the move distance
beq mov_loop
inc char_cnt
bra char_loop
mov_loop tfr x,y ; make a copy of x in y
ldab char_cnt
aby ; compute the copy destination
ldab ch_moved ; place the number of characters to be moved in B
again movb
1,x-,1,y-dbne b,again ; make room for insertion
ldx #ins_pos ; set up pointers to prepare insertion ldy #sub_strg ; "
ldab char_cnt
insert_lp movb 1,y+,1,x+ dbne b,insert_lp swi
[<label>] bsr <rel> [<comment>] ; branch to subroutine [<label>] jsr <opr> [<comment>] ; jump to subroutine
[<label>] rts [<comment>] ; return from subroutine
[<label>] call <opr> [<comment>] ; to be used in expanded memory
rtc ; return from CALL
where
<rel> is the offset to the subroutine
<opr> is the address of the subroutine and is specified in the DIR, EXT, or INDexed addressing mode.
Subroutines
• A sequence of instructions that can be called from various places in
the program
• Allows the same operation to be performed with different
parameters
• Simplifies the design of a complex program by using the
divide-and-conquer approach
main program
subroutine 1 subroutine 2 subroutine 3
Subroutine 1.1
Subroutine 1.2 Subroutine 1.2.1
Subroutine 2.1 Subroutine 2.1.1
Subroutine 3.1 Subroutine 3.1.1
Subroutine 3.2 Subroutine 3.2.1
Figure 4.7 A structured program
. . .
<call> subroutine_x
. . . . . . . .
<return> caller
subroutine_x
Figure4.8 Program flow during a subroutine call
Issues in Subroutine Calls
• Parameter passing
– Use registers
– Use the stack
– Use global memory
• Returning results
– Use registers
– Use the stack (caller created a
hole in which the result will be
placed)
– Use global memory
• Local variables allocation
– Allocated by the callee
– Use the following instruction is
the most efficient way for local
variable allocation
–
leas -n,sp
;
– allocate n bytes in the stack
for local variables
• Local variables deallocation
– Performed by the subroutine
– Use the following instruction is
the most efficient way
–
leas
n,sp
;
Local variables
Saved registers
Return address
Incoming parameters
SP
Figure 4.9 Structure of the 68HC12 stack frame
Stack Frame
(1 of 2)
• The region in the stack that holds incoming parameters, the
subroutine return address, local variables, and saved registers is
referred to as stack frame.
Example 4.10
Draw the stack frame for the following program segment
after the
leas –10,sp
instruction is executed:
ldd #$1234
pshd
ldx #$4000
pshx
jsr sub_xyz
…
sub_xyz pshd
pshx pshy
leas -10,sp
…
Solution: The stack frame is shown in Figure 4.10. $1234
$4000 return address
$1234 $4000 contents of y 10 bytes for local
variables
SP
Figure 4.10 Stack frame of example 4.10
Examples of Subroutines
•
Algorithm
for
finding the greatest common divisor of Integers
m
and
n
– Step 1
If m = n then
gcd m;
return;
– Step 2
If n < m then swap m and n.
– Step 3
gcd 1.
If m = 1 or n = 1 then return.
– Step 4
p = n % m;
– Step 5
if (p == 0) then m is the gcd. else
n m;
m p;
Example 4.11
Write a subroutine to compute the greatest
common divisor of two 16-bit unsigned integers.
Solution:
The two 16-bit incoming parameters are passed in
index register X and double accumulator D. The stack frame of
this subroutine is shown below.
return address contents of X
m_local n_local
SP 2 bytes
2 bytes 2 bytes 2 bytes
m equ 3575
n equ 2925
m_local equ 6 ; stack offset from SP for local variable m
n_local equ 4 ; stack offset from SP for local variable n
org $1000
gcd ds.w 1 ; hold the gcd of m and n
org $1500
lds #$1500 ; set up stack pointer ; set up stack pointer
ldd #m ; pass m in the stack ; push m in stack
pshd ; “
ldd #n ; pass n in the stack ; push n in stack
pshd ; “
jsr find_gcd
std gcd
leas 4,sp ; deallocate space used by parameters
swi find_gcd pshx
gcd_loop ldd n_local,sp ; compute p = n % m
ldx m_local,sp ; "
idiv ; "
cpd #0
movw m_local,sp,n_local,sp ; n m
std m_local,sp ; m p
bra gcd_loop
done ldd m_local,sp ; retrieve gcd
pulx ; restore X
Multi-Byte Division
(1 of 2)
• The HCS12 provides instructions for performing
16-bit by 16-bit or 32-bit by 16-bit division
• The HCS12 does not have division instructions
for larger numbers.
• Larger number divisions must be implemented
by repeated subtraction method.
ALU
P register
R register Q register
set lsb shift left
write R
32-bit
32-bit 32-bit C
Controller
msb lsb
Figure 4.12 Conceptual hardware for implementing repeated subtraction method
Example 4.12
Write a subroutine to
implement the division algorithm that uses
a repeated subtraction algorithm for the
unsigned 32-bit dividend and divisor. The
dividend and divisor are pushed into the
stack. Space is allocated in the stack for
this subroutine to return the quotient and
remainder.
Solution:
The stack frame is shown
in Figure 4.13.
remainderquotient dividend divisor return address
[D] [x] [y] Q R i
buf SP SP+4
SP+5 SP+
9
SP+21 SP+25 SP+29 SP+33
buf equ 0 ; distance of buf from the top of the stack
i equ 4 ; distance of i from the top of the stack
R equ 5 ; distance of R from the top of the stack
Q equ 9 ; distance of Q from the top of the stack
divisor equ 21 ; distance of divisor from the top of the stack
dividend equ 25 ; distance of dividend from the top of the stack
quotient equ 29 ; distance of quotient from the top of the stack
remainder equ 33 ; distance of remainder from the top of the stack
local equ 13 ; number of bytes for local variables
dvdend_hi equ $42 ; dividend to be tested
dvdend_lo equ $4c15 ; "
dvsor_hi equ $0 ; divisor to be tested
dvsor_lo equ $64 ; "
org $1000
quo ds.b 4 ; memory locations to hold the quotient
rem ds.b 4 ; memory locations to hold the remainder
org $1500 ; starting address of the program
lds #$1500 ; initialize stack pointer
leas -8,sp ; make a hole of 8 bytes to hold the result
ldd #dvdend_lo
pshd
ldd #dvdend_hi
ldd #dvsor_lo pshd
ldd #dvsor_hi
pshd
jsr div32 ; call the divide subroutine
leas 8,sp
; the following 4 instructions get the quotient from the stack puld
std quo
puld
std quo+2
; the following 4 instructions get the remainder from the stack puld
std rem
puld
std rem+2
swi
div32 pshd ; 32-bit divide subroutine
pshx pshy
leas -local,sp
ldd #0
std R,sp ; initialize register R to 0
ldd dividend,sp
std Q,sp ; place dividend in register Q
ldd dividend+2,sp
std Q+2,sp
ldaa #32
staa i,sp ; initialize loop count
loop lsl Q+3,sp ; shift register pair Q and R to the right
rol Q+2,sp ; by 1 bit
rol Q+1,sp ; "
rol Q,sp ; "
rol R+3,sp ; "
rol R+2,sp ; "
rol R+1,sp ; "
rol R,sp ; "
; the following 8 instructions subtract the divisor from register R
ldd R+2,sp
subd divisor+2,sp
std buf+2,sp
ldaa R+1,sp
sbca divisor+1,sp
staa buf+1,sp
ldaa R,sp
sbca divisor,sp
; the following 6 instructions store the difference back to R register
staa R,sp
ldaa buf+1,sp
staa R+1,sp
ldd buf+2,sp
std R+2,sp
ldaa Q+3,sp
oraa #01 ; set the least significant bit of Q register to 1
staa Q+3,sp
bra looptest
smaller ldaa Q+3,sp
anda #$FE ; set the least significant bit of Q register to 0
staa Q+3,sp
looptest dec i,sp
lbne loop
; the following 4 instructions copy the remainder into the hole
ldd R,sp
std remainder,sp
ldd R+2,sp
std remainder+2,sp
; the following 4 instructions copy the quotient into the hole
ldd Q,sp
ldd Q+2,sp
std quotient+2,sp
leas local,sp ; deallocate local variables puly
array_x N return address
B A Y X buf in_order
inner
iteration SP
Figure 4.15 Stack frame for bubble sort SP+1
SP+2 SP+3
SP+12 SP+13
• Sorting is useful for improving the
searching speed when an array or a
file needs to be searched many
times.
• Bubble sort is a simple, but inefficient
sorting method.
• Example 2.13
– Write a subroutine to implement the
bubble sort algorithm and a sequence of
instructions for testing the subroutine.
– Pass the base address of the array and
the array count in the stack.
– Four bytes are needed for local
variables.
St ar t it er at io n N 1 in _o rd er 1 in ne r it er at io n ye s sw ap a rr ay [i ] & a rr ay [i + 1] ar ra y[ i] > a rr ay [i + 1] ? in _o rd er 0 in ne r in ne r - 1 in ne r = 0 ? i 0 i i +
1 yes
arr equ 13 ; distance of the variable arr from stack top
arcnt equ 12 ; distance of the variable arcnt from stack top
buf equ 3 ; distance of local variable buf from stack top
in_order equ 2 ; distance of local variable in_order from stack top
inner equ 1 ; distance of local variable inner from stack top
iteration equ 0 ; distance of local variable iteration from stack top
true equ 1
false equ 0
n equ 30 ; array count
local equ 4 ; number of bytes used by local variables
org $1000
array_x db 3,29,10,98,54,9,100,104,200,92,87,48,27,22,71 db 1,62,67,83,89,101,190,187,167,134,121,20,31,34,54
org $1500
lds #$1500 ; initialize stack pointer
ldx #array_x
pshx
ldaa #n
psha
jsr bubble
leas 3,sp ; deallocate space used by outgoing parameters
bubble pshd pshy pshx
leas -local,sp ; allocate space for local variables
ldaa arcnt,sp ; compute the number of iterations to be performed
deca ; "
staa iteration,sp ; "
ploop ldaa #true ; set array in_order flag to true before any iteration
staa in_order,sp ; "
ldx arr,sp ; use index register X as the array pointer ldaa iteration,sp ; initialize inner loop count for each iteration
staa inner,sp ; "
cloop ldaa 0,x ; compare two adjacent elements
cmpa 1,x ; "
bls looptest
; the following five instructions swap the two adjacent elements
staa buf,sp ; swap two adjacent elements
ldaa 1,x ; "
staa 0,x ; "
ldaa buf,sp ; "
staa 1,x ; "
ldaa #false ; reset the in-order flag
looptest inx
dec inner,sp
bne cloop
tst in_order,sp ; test array in_order flag after each iteration
bne done
dec iteration,sp
bne ploop
done leas local,sp ; deallocate local variables
i = 0 n - 1
i = n(n - 1)2 (4.1)
i = 0 n - 1
(2i + 1) (4.2)
n2 =
Finding the Square Root
(1 of 2)
• One of the methods for finding the square root of an
integer is based on the following equation:
– Equation 4.1 can be transformed into
Start
i 0 sum 0
sum sum + (2i + 1)
sum < q? i i + 1
yes
sq_root i
Stop
Figure 4.16 Algorithm for finding the square root of integer q. no
q_val return address
[Y] i_local
sum
SP SP+2
SP+10 Figure 4.17 Stack frame of example 4.14
•
Example 4.14
Write a
subroutine to implement the
square root algorithm. This
subroutine should be able to
find the square root of a 32-bit
unsigned integer. The
parameter is pushed onto the
stack and the square root is
returned in accumulator D.
•
Solution:
The stack frame is
shown in Figure 4.17. The
subroutine and the instruction
sequence for testing the
q_hi equ $000F ; upper word of q
q_lo equ $4240 ; lower word of q
i_local equ 0 ; distance of local variable i from the top of the stack
sum equ 2 ; distance of local variable sum from the top of the stack
q_val equ 10 ; distance of incoming parameter q from the top of stack
local equ 6 ; number of bytes allocated to local variables
org $1000
sq_root ds.b 2 ; to hold the square root of q
org $1500
lds #$1500
ldd #q_lo
pshd
ldd #q_hi
pshd
jsr findSqRoot
std sq_root
leas 4,sp
swi findSqRoot
pshy ; save y in the stack
leas -local,sp ; allocate local variables
std i_local,sp ; "
std sum,sp ; initialize local variable sum to 0
std sum+2,sp ; "
loop ldd i_local,sp
ldy #2
emul ; compute 2i
addd sum+2,sp ; add 2i to sum
std sum+2,sp
tfr y,d
adcb sum+1,sp
stab sum+1,sp
adca sum,sp
staa sum,sp
; add 1 to sum (need to propagate carry to the most significant byte of sum)
ldaa #1
adda sum+3,sp
staa sum+3,sp
ldaa sum+2,sp
adca #0
staa sum+2,sp
ldaa sum+1,sp
staa sum+1,sp
ldaa sum,sp
adca #0
staa sum,sp
ldd i_local,sp ; increment i by 1
addd #1 ; “
std i_local,sp
; compare sum to q_val by performing subtraction (need consider borrow)
ldd sum+2,sp
subd q_val+2,sp
ldaa sum+1,sp
sbca q_val+1,sp
ldaa sum,sp
sbca q_val,sp
lblo loop
ldd i_local,sp ; place sq_root in D before return ; deallocate space used by local variables
exit leas local,sp
Table 4.2 D-Bug12 monitor (version 4.x.x) routines
Subroutine Function pointer address far main ( )
getchar ( ) putchar ( ) printf ( )
far GetCmdLine ( ) far sscanhex ( ) isxdigit ( ) toupper ( ) isalpha ( ) strlen ( ) strcpy ( ) far out2hex ( ) far out4hex ( ) SetUserVector ( ) far WriteEEByte( ) far EraseEE ( ) far ReadMem ( ) far WriteMem ( )
Start of D-Bug12
Get a character from SCI0 or SCI1 Send a character out to SCI0 or SCI1
Formatted string output-translates binary values to string Get a line of input from the user
Convert ASCII hex string to a binary integer Check if a character (in B) is a hex digit Convert lower-case characters to upper-case Check if a character is alphabetic
Returns the length of a NULL-terminated string Copy a NULL-terminated string
Output 8-bit number as 2 ASCII hex characters Output a 16-bit number as 4 ASCII hex characters Setup a vector to a user's interrupt service routine Write a byte to the on-chip EEPROM memory Bulk erase the on-chip EEPROM memory Read data from the HCS12 memory map Write data to the HCS12 memory map
$EE80 $EE84 $EE86 $EE88 $EE8A $EE8E $EE92 $EE94 $EE96 $EE98 $EE9A $EE9C $EEA0 $EEA4 $EEA6 $EEAA $EEAE $EEB2
Using the D-Bug12 Functions
int getchar (void)
Pointer address: $EE84
Returned value: 8-bit character in accumulator B
• All functions listed in Table 4.2 are written in C language.
• The first parameter to the function is passed in accumulator D. The
remaining parameters are pushed onto the stack in the reverse
order they are listed in the function declaration.
• Parameters of type
char
will occupy the lower order byte of a word
pushed onto the stack.
• Parameters pushed onto the stack before the function is called
remain on the stack when the function returns. It is the responsibility
of the caller to remove passed parameters from the stack.
• All 8- and 16-bit values are returned in accumulator D. A returned
value of type
char
is
returned in accumulator B.
• Adding the following instruction sequence will read a character
from SCI0 port:
getchar equ $EE84
…
jsr [getchar,PCR]
int putchar(int)
Pointer address: $EE86
Incoming parameter: character to be output in accumulator B Returned vale: the character that was sent (in B)
- This function outputs a character to serial communication port SCI0. - The character to be output should be placed in accumulator B.
- The following instruction sequence will output the character A to serial port SCI0 when the program is running on the SSE256 or Dragon12 demo board.
putchar equ $EE86
…
ldab #$41 ; place the ASCII code of A in accumulator B
jsr [putchar,PCR]
…
•
int printf(char *format,…
)
– Pointer address:
$EE88
– Incoming parameters: zero or more integer data to be output on the
stack, D contains the address of the format string. The format string
must be terminated with a zero.
– Returned value: number of characters printed in D.
• This function is used to convert, format, and print its argument as
standard output under the control of the format string pointed to by
format
.
• All except floating-point data types are supported.
• The format string contains two basic types of objects:
1. ASCII characters which will be copied directly to the display device.
2. Conversion specifications. Each conversion specification begins with
a percent sign (%).
3. Optional formatting characters may appear between the percent sign
and ends with a single conversion character in the following order:
Table 4.3 Optional formatting characters
Character Description
-(minus sign) FieldWidth
. (period) Precision
h
l(letter ell)
Left justifies the converted argument.
Integer number that specifies the minimum field width for the converted arguemnt. The argument will be displayed in a field at least this wide. The displayed argument will be padded on the left or right if necessary. Separates the field width from the precision.
Integer number that specifies the maximum number of characters to display from a string or the minimum number of digits for an intger. To have an integer displayed as a short.
To have an integer displayed as a long.
Table 4.4 Printf() conversion characters d, i
o x X u c s p %
character Argument type; displayed as int; signed decimal number
int; unsigned octal number (without a leading zero) int; unsigned hex number using abcdef for 10...15 int; unsigned hex number using ABCDEF for 10...15 int; unsigned decimal number
int; single character
char *; display from the string until a '\0' (NULL)
void *; pointer (implementation-dependent representation) no argument is converted; print a %
Example for outputting a message (Flight simulation):
CR equ $0D
LF equ $0A
printf equ $EE88
…
ldd #prompt
jsr [printf,PCR]
…
prompt db “Flight simulation”,CR,LF,0
Example
for outputting three numbers
m, n,
and
gcd
along
with a message:
CR equ $0D
LF equ $0A
printf equ $F686
…
ldd gcd
pshd
ldd n
pshd
ldd m
pshd
ldd #prompt
jsr [printf,PCR]
leas 6,sp
…
•
int far GetCmdLine(char *CmdLineStr, int CmdLineLen)
– Pointer address:
$EE8A
– Incoming parameters: a pointer to the buffer where the input string is
to be stored and the maximum number of characters that will be
accepted by this function.
• This function is used to obtain a line of input from the user.
• The reception of an ASCII carriage return ($0D) terminates the reception
of characters from the user.
printf equ $EE88
GetCmdLine equ $EE8A
cmdlinelen equ 100
CR equ $0D
LF equ $0A
…
prompt db “Please enter a string: “,CR,LF,0
…
inbuf ds.b 100
…
ldd #prompt ; output a prompt to remind the user to jsr [printf,PCR] ; enter a string
ldd #cmdlinelen ; push the CmdLineLen
pshd ; “
ldd #inbuf
call [GetCmdLine,PCR] ; read a string from the keyboard
•
Example 4.15
Write a program that invokes appropriate functions to
find the prime number between 1000 and 2000. Output eight prime
numbers in one line. To do this, you will need to
– Write a subroutine to test if an integer is a prime.
– Invoke the printf() function to output the prime number.
– Write a loop to test all the integers between 1000 and 2000.
•
Solution:
The logic structure of the program is
–
Step 1
• Output the message “The prime numbers between 1000 and 2000 are as follows:”.
–
Step 2
• For every number between 100 and 1000
– call the test_prime() function to see if it is a prime. – output the number (call printf()) if it is a prime.
S P
num return address
[X] prime_flag
ilimit i SP + 2
SP + 4
SP + 9
Figure 4.18 Stack frame for the prime test subroutine
• Step 1
– Let
num
,
i
, and
isprime
represent
the number to be tested, the loop
index, and the flag to indicate if
num
is prime.
• Step 2
– isprime ¬ 0;
• Step 3
– For i = 2 to num/2 do if num % i =
0 then return; isprime ¬ 1; return;
– The Stack frame of the function
test_prime ():
CR equ $0D
LF equ $0A
i equ 0 ; distance of variable i from stack top
ilimit equ 2 ; distance of variable ilimit from stack top
prime_flag equ 4 ; distance of variable isprime from stack top
num equ 9 ; distance of variable num from the stack top
plocal equ 5 ; number of bytes allocated to local variables
upper equ 2000 ; upper limit for testing prime
lower equ 1000 ; lower limit for testing prime
printf equ $EE88 ; location where the address of printf() is stored
org $1000
out_buf ds.b 10
prime_cnt ds.b 1
k ds.b 2
temp ds.b 2
org $1500
ldx #upper
stx temp
pshx
ldx #lower
stx k ; initialize k to 100 for prime testing
ldd #format0
jsr [printf,PCR]
leas 4,sp
clr prime_cnt
again ldd k
cpd #upper
bhi stop ; stop when k is greater than upper
pshd
jsr prime_tst ; test if k is prime
leas 2,sp ; deallocate space used by outgoing parameters
tstb
beq next_k ; test next integer if k is not prime
inc prime_cnt ; increment the prime count
ldd k
pshd
ldd #format1
jsr [printf,PCR] ; output k
leas 2,sp
ldaa prime_cnt
cmpa #8 ; are there 8 prime numbers in the current line?
blo next_k
ldd #format2
jsr [printf,PCR]
clr prime_cnt
ldx k
inx
stx k
bra again
next_k ldx k
inx
stx k
jmp again
stop swi
prime_tst pshx
leas -plocal,sp ; allocate local variable
ldaa #1
staa prime_flag,sp; set the flag to true
ldd num,sp
cpd #1
beq not_prime ; 1 is not a prime number
cpd #2
beq is_prime ; 2 is a prime number
lsrd ; compute num/2 as the test limit
ldd #2
std i,sp ; set first test number to 2
test_loop ldx i,sp
ldd num,sp
idiv
cpd #0 ; if num can be divided by i, then
beq not_prime ; it is not a prime
ldd i,sp
cpd ilimit,sp
beq is_prime ; num is prime at the end of test loop
ldx i,sp
inx
stx i,sp
bra test_loop
not_prime clr prime_flag,sp
is_prime ldab prime_flag,sp ; put the result in B leas plocal,sp
pulx
formmat0 db CR,LF,"The prime numbers between %d and %d are as follows: db ",CR,LF,CR,LF,0
format1 db " %d ",0 format2 db " ",CR,LF,0
>g 1500
The prime numbers between 1000 and 2000 are as follows: 1009 1013 1019 1021 1031 1033 1039 1049 1051 1061 1063 1069 1087 1091 1093 1097 1103 1109 1117 1123 1129 1151 1153 1163 1171 1181 1187 1193 1201 1213 1217 1223 1229 1231 1237 1249 1259 1277 1279 1283 1289 1291 1297 1301 1303 1307 1319 1321 1327 1361 1367 1373 1381 1399 1409 1423 1427 1429 1433 1439 1447 1451 1453 1459 1471 1481 1483 1487 1489 1493 1499 1511 1523 1531 1543 1549 1553 1559 1567 1571 1579 1583 1597 1601 1607 1609 1613 1619 1621 1627 1637 1657 1663 1667 1669 1693 1697 1699 1709 1721 1723 1733 1741 1747 1753 1759 1777 1783 1787 1789 1801 1811 1823 1831 1847 1861 1867 1871 1873 1877 1879 1889 1901 1907 1913 1931 1933 1949
1951 1973 1979 1987 1993 1997 1999 User Bkpt Encountered PP PC SP X Y D = A:B CCR = SXHI NZVC
30 1560 1500 07D1 15DE 07:D1 1001 0000 xx:1560 34 PSHX
>
Tips for Program Debugging
Involving Subroutine Calls
• What to do when the program gets stuck?
– Step 1
• Find out which subroutine gets stuck by setting a breakpoint
immediately after the jsr or bsr instruction.
– Step 2
• Find out why the subroutine gets stuck.
• Forgetting to restore registers pushed onto the stack before
return.
• Forgetting to deallocate local variables before return.
• There are some infinite loops in the subroutine.
General Debugging Strategy
• Make sure all leaf subroutines work correctly by
using the methods described in Section 2.9.
• Debug intermediate subroutines. Make sure no