630 likes | 877 Views
Chapter 3: Data Structures and Subroutine Calls. The 68HC11 Microcontroller. Han-Way Huang. Minnesota State University, Mankato. Examples of Data Structures. 1. Strings . A sequence of characters. 2. Arrays . An ordered set of elements of the same type.
E N D
Chapter 3: Data Structures and Subroutine Calls The 68HC11 Microcontroller Han-Way Huang Minnesota State University, Mankato
Examples of Data Structures 1. Strings. A sequence of characters. 2. Arrays. An ordered set of elements of the same type. 3. Stacks. A data structure with a top and bottom. Elements can be added or removed only at the top of the stack. 4. Queues. A data structure to which elements can be added at only one end (called head) and removed only from the other end (called tail). 5. Dequeues. A data structure in which elements can be added and removed at both ends. 6. Trees. A data structure in which one element is called the root and the remaining elements are partitioned into m disjoint subtrees, each of which is itself a tree. 7. Graphs. A data structure that consists of a set of nodes and a set of arcs (or edges). Each arc in a graph is specified by a pair of nodes. 8. Linked lists. A data structure that consists of linked nodes. Each node consists of two fields, an information field and a next address field. The information field holds the actual element on the list, and the next address field contains the address of the next node in the list. Operations performed on data structures - adding and deleting elements - traversing and searching a data structure - etc.
The 68HC11 Stack SP low address top element . . . high address bottom - A 16-bit stack pointer (SP) points to the location above the top byte of the stack. - The 68HC11 CPU registers can be pushed into the stack. - The top element (s) of the stack can be pulled into a CPU register. - The stack grows from high addresses toward lower addresses. Push and Pull Instructions - PSHA: Push A onto the stack - PSHB: Push B onto the stack - PSHX: Push X onto the stack (low order byte is pushed first) - PSHY: Push Y onto the stack (low order byte is pushed first) - PULA: Pull A from the stack - PULB: Pull B from the stack - PULX: Pull X from the stack (high order byte is pulled first) - PULY: Pull Y from the stack (high order byte is pulled first)
Example 3.1 Suppose that [A] = $33, [B] = $20, [SP] = $00FF. What will be the contents of the top byte of the stack before and after the execution of PSHA? What will be the contents of the top two bytes of the stack if PSHB is executed? Solution: The contents of the stack before and after the execution of PSHA and PSHB are: XX [SP] = $00FD [SP] = $00FE $20 XX [SP] = $00FF XX $33 $33 after PSHA after PSHB original stack
Instructions Related to the Stack Pointer (SP) [<label>] DES [<comment>] decrements the contents of the stack pointer by 1 [<label>] INS [<comment>] increments the contents of the stack pointer by 1 [<label>] LDS <opr> [<comment>] loads the contents of a memory location or an immediate value into SP [<label>] STS <opr> [<comment>] stores the contents of the stack pointer in a memory location [<label>] TSX [<comment>] places the contents of SP plus one into X [<label>] TSY [<comment>] places the contents of SP plus one into Y [<label>] TXS [<comment>] places the contents of X minus one into SP [<label>] TYS [<comment>] places the contents of Y minus one into SP Example 3.2 Write down an instruction sequence to load the top element of the stack into A and the 9th element from the top of the stack into B. Solution: TSX ; points the index register X to the top element of the stack LDAA 0,X ; places the top element of the stack in A LDAB 9,X ; places the 9th element from the top of the stack in B
Indexable Data Structures - Vectors and matrices are indexable data structures - A vector is one dimensional and a matrix is two dimensional - The first element of a vector is associated with index 0 - Vectors and matrices can be defined by one or multiple FCB or FDB directives Example 3.3 Write a program to search an array with N 16-bit elements that are stored starting at $10 using the key stored at $00-$01 and save the address of the first matched element at $02-$03. Save the value $FFFF (-1) if no element matches the key. Solution: start i ¬ 0 result ¬ $FFFF yes array[i] = key? result ¬ address of array[i] i ¬ i + 1 no i = N - 1? yes Stop
N equ 10 ; array count notfound equ -1 org $00 key FDB xxxx ; the key to be used for searching result RMB 2 ; memory locations to store the address org $D000 array FDB $20,$40,$202,$1,$200,$10,$22,$21,$300,$101 org $C000 ldd #notfound ; store a -1 to result and result+1 std result ; “ ldd key ; get the key ldx #array ; get the starting address of the array ldy #0 ; initialize the loop count loop cpd 0,X ; compare with the key beq found ; found it? inx ; increment the pointer by 2 inx ; “ iny ; increment the loop count cpy #N-1 ; check the loop count bne loop jmp stop found stx result ; stop the search stop end
Matrices - can be stored in row major order or column major order - a matrix element can be accessed by specifying its row and column numbers The following matrix 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 mat = can be stored in row major order mat1 FCB 01, 02, 03, 04, 05 FCB 06, 07, 08, 09, 10 FCB 11, 12, 13, 14, 15 or FCB 16, 17, 18, 19, 20 FCB 21, 22, 23, 24, 25 in column major order mat2 FCB 01, 06, 11, 16, 21 FCB 02, 07, 12, 17, 22 FCB 03, 08, 13, 18, 23 FCB 04, 09, 14, 19, 24 FCB 05, 10, 15, 20, 25
Address Calculation for a N × M Matrix Elements - row major order address of mat1(i, j) = (i × M) + j + address of mat1(0,0) * Suppose memory locations i and j hold the row and column indices * The following instruction sequence computes the address of mat1(i, j) ldaa i ; place row index in A ldab #M ; place matrix dimension M in B mul ; compute i × M addb j ; compute i × M + j adca #0 ; “ addd #mat1 ; compute i × M+ j + mat1(0,0) xgdx ; place the address in X
- column major order address of mat2(i, j) = (j × N) + i + address of mat2(0, 0) * Suppose memory locations i and j hold the row and column indices * The following instruction sequence computes the address of mat2(i, j) ldaa j ; place row index in A ldab #N ; place matrix dimension N in B mul ; compute j × N addb i ; compute j × N + i adca #0 ; “ addd #mat2 ; compute j × N + i + mat2(0,0) xgdx ; place the address in X
Example 3.4 Write a program to compute the sum of two 8 × 8 matrices. The starting addresses of these two matrices are MA and MB and that the result matrix is MC. These matrices are stored in memory in row major order. Each element is one byte. Solution: N equ $8 ; dimension of the matrix org $00 MA fcb .... ; matrix MA is here .... MB fcb .... ; matrix MB is here .... MC rmb 64 ; matrix MC is here i rmb 1 ; row index j rmb 1 ; column index buf rmb 1 ; buffer to hold element disp rmb 2 ; memory to hold the value of i × N + j org $C000 ldaa #N ; start from the last row staa i ; initialize the index i out_lp dec i ldab #N ; start from the last column toward the 0th column stab j
* The following 10 instructions fetch MA(i, j) and place it at buf in_lp dec j ldaa i ; place row index in A ldab #N ; place N in B mul ; compute N × i addb j ; compute N × i + j adca #0 ; “ std disp ; save the value of N × i + j addd #MA ; compute MA(0,0) + N × i + j xgdx ldaa 0,X staa buf * The following 4 instructions fetch MB(i, j) into A ldd disp addd #MB xgdx ldaa 0,X adda buf ; compute MA(i, j) + MB(i, j) staa buf ; save the sum in buf
* The following 3 instructions compute the address of MC(i, j) and leave it in X ldd disp addd #MC xgdx ldaa buf ; get the sum staa 0,X ; save the sum in MC(i,j) dec j ; decrement the column number beq in_lp ; not reach the end of a column yet? dec i ; decrement the row number beq out_lp ; is this the end of all computation end Matrix Transpose The transpose MT of a matrix M is defined as a matrix obtained by writing the rows of M as the columns of MT. MT can be obtained by swapping the (i, j)th element with the (j, i)th element for each i and j from 0 to N-1. Example 3.4 Write a program to transpose an N × N matrix.
A breakdown of matrix a0,0 a0,1 a0,n-1 a1,0 a1,1 upper right lower left an-2,n-1 an-1,n-1 an-1,0 an-1,n-2 - swap each element in the upper right with an element in the lower left - row index i runs from 0 to n-2 for the upper right elements - for row i column index j runs from i+1 to n-1 -diagonalelements need not be swapped
Matrix Transpose Program N equ 8 ; matrix dimension ilimit equ N-2 ; upper limit of index i jlimit equ N-1 ; upper limit of index j org $00 i rmb 1 ; row index j rmb 1 ; column index ORG $D000 ; starting address of the matrix mat FCB ..... ; matrix to be transposed FCB .... ; “ . ; “ . ; “ ORG $C000 clr i ; initialize i to 0 row_loop ldaa i inca staa j ; initialize j to i + 1 * The following 7 instructions compute the address of mat(i,j) col_loop ldaa i ldab #N mul addb j adca #0
addd #mat xgdx * The following 7 instructions compute the address of mat(j,i) and leave address in Y ldaa j ldab #N mul addb i adca #0 addd #mat xgdy * The following 4 instructions swap mat(i,j) with mat(j,i) ldaa 0,X ldab 0,Y staa 0,Y stab 0,X ldab j inc j ; update index j cmpb #jlimit ; j = N - 1? bne col_loop ldaa i inc i ; update index i cmpa #ilimit ; i = N - 2? bne row_loop END
Strings Example 3.6 Write a program to append a string to the end of another string. Solution: There are two steps in this program: Step 1 Find the end of the first string. Step 2 Copy string 1. ORG $C000 LDX #string2 again LDAA 0,X BEQ copy INX BRA again copy LDY #string1 copy_loop LDAA 0,Y STAA 0,X BEQ done INX INY BRA copy_loop done NOP SWI
… ORG $D000 string1 FCC “….” FCB 0 string2 FCC “….” FCB 0 END Example 3.7 Write a program to count the number of characters and words contained in a string. Solution: The first non-white-space character to the right of one or more spaces is the beginning of a new word. Parameters used in the program: - char_cnt: character count - wd_cnt: word count - str_ptr: string pointer - curr_char: current character
Figure 3.7 Flowchart for character and word count program
tab equ $09 ; ASCII code for horizontal tab character sp equ $20 ; ASCII code for SPACE CR equ $0D ; ASCII code for carriage return LF equ $0A ; ASCII code for line feed org $00 char_cnt rmb 1 wd_cnt rmb 1 ORG $D000 string_X fcc “xxxxxxxxxxxxxxxx” ; the string to be processed fcb 0 ; the NULL character to terminate the previous string org $C000 ldx #string_X clr char_cnt ; initialize the character count to 0 clr wd_cnt ; initialize the word count to 0 string_lp ldab 0,X ; fetch the current character beq exit ; is this a NULL character? inx ; move to the next character inc char_cnt * The following 8 instructions skip the spaces between words cmpb #sp beq string_lp ; skip the space character cmpb #tab beq string_lp ; skip the tab character
cmpb #CR beq string_lp ; skip the carriage return character cmpb #LF beq string_lp ; skip the line feed character * A non-space character is the beginning of a new word inc wd_cnt wd_loop ldab 0,X beq exit ; null character is not included in character count inc char_cnt inx ; move the character pointer * The following 8 instructions check the end of a word cmpb #sp beq string_lp cmpb #tab beq string_lp cmpb #LF beq string_lp cmpb #CR beq string_lp * A non-space character is part of a word bra wd_loop exit swi end
Example 3.8 Write a program to search a certain word from a given string. Solution: The flowchart of the word search program is in Figure 3.8.
tab equ $09 ; ASCII code for horizontal tab sp equ $20 ; ASCII code for SPACE CR equ $0D ; ASCII code for carriage return LF equ $0A ; ASCII code for line feed NULL equ $00 ; ASCII code for NULL org $00 search rmb 1 ; flag to indicate if the given word is in the string string_X fcc “xxxxxxxxxxxxxxxx” ; a string terminated by NULL fcb 0 word_X fcc “yyyyyyy” ; a word terminated by NULL fcb 0 org $C000 clr search ; initialize the search flag to 0 ldx #string_X ; place the string address in X loop ldab 0,X inx * The following 10 instructions skip the white spaces to search for the next word * in the string tstb beq done ; is this the end of the string? cmpb #sp ; is the current character a space? beq loop ; skip the space cmpb #tab ; is the current character a tab?
beq loop ; skip the tab character cmpb #CR ; is this a carriage return? beq loop ; skip it cmpb #LF ; is this a line feed? beq loop ; skip it * The occurrence of the first non-white character indicates the beginning of a word, * and the comparison should be started ldy #word_X ; place the word address in Y ldaa 0,Y ; place the current character of word_X in A iny ; move the word pointer next_ch cba ; compare the character in A and B bne end_of_wd ; check the next word cmpa #NULL ; is this the end of a word? beq matched ; if yes, the word is found in the string ldaa 0,Y ; get the next character in word_X ldab 0,X ; get the next character in string_X inx iny bra next_ch ; check the next pair of characters * The following 10 instructions check to see if the end of the given word is reached end_of_wd cmpa #NULL bne next_wd ; if the not the end of the given word, then not matched cmpb #CR
beq matched cmpb #LF beq matched cmpb #tab beq matched cmpb #sp beq matched * The following twelve instructions skip the unmatched word in the string next_wd ldab 0,X ; get the next character in the string beq done ; stop if this is the end of the string inx cmpb #CR beq jmp_loop ; the label loop is too far away to use a conditional branch cmpb #LF beq jmp_loop cmpb #tab beq jmp_loop cmpb #sp beq jmp_loop bra next_wd jmp_loop jmp loop matched ldab #1 ; set the search flag to 1 stab search ; “ done swi ; return to monitor (buffalo)
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 Instructions related subroutine calls [<label>] BSR <rel> [<comment>] ; branch to subroutine [<label>] JSR <opr> [<comment>] ; jump to subroutine [<label>] RTS [<comment>] ; return from subroutine 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.
Program Structure Subroutine Processing
Issues in Subroutine Calls 1. Parameter passing - use registers - use the stack - use global memory 2. Returning results - use registers - use the stack (caller created a hole in which the result will be placed) - use global memory 3. Local variables allocation - allocated by the callee - use as many DES instructions when no more than 5 bytes are needed - use the following instruction sequence to allocate more than 5 bytes. TSX XGDX SUBD #N ; allocate N bytes XGDX TXS ; move the stack pointer up by N bytes
Issues in Subroutine Calls (continued) 4. Local variables deallocation - use as many INS instructions as needed when no more than 5 bytes are to be deallocated - use the following instruction sequence when more than 5 bytes are deallocated TSX XGDX ADDD #N ; deallocate N bytes XGDX TXS ; move down the stack pointer by N bytes Stack Frame 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 3.9 Draw the stack frame for the following program segment when the 9th instruction of the subroutine subx is executed. Solution: ldaa #N psha ldx #mat pshx bsr subx ... Subx: (1) pshb (2) psha (3) pshx (4) pshy (5) tsx (6) xgdx (7) subd #6 (8) xgdx (9) txs ...
Using Registers to Pass Parameters Example 3.10 Write a subroutine to compute the average of an array with N 8-bit elements and an instruction sequence to call the subroutine. The array starts at ARRAY. Use registers to pass parameters and return the average in B. Solution: The instruction sequence to call this subroutine is: LDX #ARRAY LDAA #N BSR average .... The subroutine saves array count A in the stack and also push a 0 into the stack so that 0 and N can be loaded into X when computing the average.
* The following subroutine computes the average of an array and returns it in B average psha ; save the array count clra psha ; clear the top byte of the stack to 0 tsy ; Y points to the top byte of the stack ldab 1,Y ; place the array count in B cmpb #1 ; check the array count blo exit ; is the array empty? bhi do ; does the array have more than one element? ldab 0,X ; get the single element and return bra exit ; “ do xgdy ; place N in Y and use Y as the loop count clra ; use D as the sum and initialize it to 0 clrb ; “ again addb 0,X ; add an element to the sum adca #0 ; add the carry to the upper 8 bits inx ; move the array pointer dey ; decrement the loop bne again ; is the end of the loop? tsy ; point Y to the top of the stack ldx 0,Y ; place N in X
idiv ; compute the average of the array xgdx ; exchange X and D so that D contains the quotient * ; in which A contains 0 and B contains the quotient exit pula ; restore registers pula ; “ rts
Using the Stack to Pass Parameters Example 3.11 Write a subroutine to find the largest element of an array and an instruction sequence to call this subroutine. The following parameters are passed to this subroutine in the stack: - array: the starting address of the given array - arcnt: the array count - amax: address of the memory location to hold the maximum element of the array Solution: The instruction sequence that calls this subroutine is: ldx #array pshx ldaa #arcnt psha ldx #armax pshx bsr max ; call the subroutine tsx ; clean up the stack ldab #5 ; “ abx ; “ txs ; “
array equ 11 ; array base address offset from the top of the stack arcnt equ 10 ; array count offset from the top of the stack armax equ 8 ; array max address offset from the top of the stack max pshx ; save al registers pshy ; “ pshb ; “ psha ; “ tsy ; point Y to the top of the stack ldx array,Y ; load the base address into X ldab arcnt,Y ; load the array count into B ldaa 0,X ; assign the first element as the temporary array max cmpb #1 ; check array count blo exit ; return if the array is empty bhi start ; look for the array max if the array count is larger than 1 bra done ; the array has only one element start inx ; set X to point to the second element of the array decb ; loop limit is arcnt - 1 again cmpa 0,X ; compare the next element with the array max bge noswap ; should array max be updated? ldaa 0,X ; update the array max noswap inx ; move to the next element
decb ; decrement the loop count bne again ; is it done? done ldx armax,Y ; get the address for the array max staa 0,X ; save the array max exit pula ; restore registers pulb ; “ puly ; “ pulx ; “ rts
Example 3.12 Write a program to compute the greatest common divisor (gcd) of two 16-bit integers. The caller pushes these two integers onto the stack and this subroutine returns the gcd in double accumulator D. Solution: Let these two integers be n1 and n2. Assume n1 n2. If not, swap them. Algorithm: Step 1 If n1 > n2 then swap n1 and n2. Step 2 i = 2, gcd = 1. Step 3 If (n1 = 1) or (n2 = 1) return. Step 4 If both n1 and n2 can be divided by i then gcd i. Step 5 If i = n1 then stop. Otherwise, i i + 1. Go to step 4.
Stack frame of gcd subroutine Instruction sequence to callfind_gcd … LDX <operand n1> PSHX LDX <operand n2> PSHX JSR find_gcd INS INS INS INS …
n1_dis EQU 8 ; offset of n1 from the top of the stack n2_dis EQU 10 ; offset of n2 from the top of the stack gcd_dis EQU 0 ; offset of gcd from the top of the stack i_dis EQU 2 ; offset of i from the top of the stack Find_gcd PSHY TSY DES DES DES DES LDX #1 STX gcd_dis,Y LDD n2_dis,Y ; if n2 = 1 then gcd = 1 CPD #1 ; “ BEQ done ; “ LDD n1_dis,Y ; if n1 = 1 then gcd = 1 CPD #1 ; “ BEQ done ; “ CPD n2_dis,Y BLS start ; if n1 is smaller then start to compute gcd LDX n2_dis,Y ; n1 is larger than n2, so swap them
done INS INS INS INS RTS STD n2_dis,Y STX n1_dis,Y start LDX #2 ; initialize i to 2 STX i_dis,Y ; “ again LDD n1_dis,Y IDIV CPD #0 ; can i divide n1? BNE next_i ; “ LDD n2_dis,Y LDX i_dis,Y ; can i divide n2? IDIV ; “ CPD #0 ; “ BNE next_i LDD i_dis,Y ; use current i as STD gcd_dis,Y ; the temporary gcd next_i LDX i_dis,Y ; have we done with CPX n1_dis,Y ; all the test yet? BEQ done INX STX i_dis,Y JMP again
Example 3.13 Write a subroutine that can divide a 32-bit number into another 32-bit number. Solution: Use repeated subtraction method to implement the division. Assume we have the hardware shown in Figure 3.0.
Algorithm of Division Using Repeated Subtraction Step 1 Shift the register pair (R, Q) one bit to the left. Step 2 Subtract register P from register R, put the result back to R if the difference is nonnegative. Step 3 If the result in step 2 is negative, set the least significant bit of Q to 0. Otherwise, set it to 1. Step 4 Repeat Step 1 to 4 for 31 times. The caller allocates 8 bytes in the stack to hold the remainder and quotient. Both the dividend and the divisor are pushed into the stack. The subroutine allocates 13 bytes for local variables. The calling instruction sequence is TSX XGDX SUBD #8 XGDX TXS LDX divsor ; push divisor PSHX ; “ LDX didend ; push dividend PSHX ; “ JSR div32
buf EQU 0 ; space used as a buffer R EQU 5 ; offset of register R from the top of the stack Q EQU 9 ; offset of register Q from the top of the stack divisor EQU 21 ; offset of divisor from the top of the stack dividend EQU 25 ; offset of dividend from the top of the stack i EQU 4 ; offset of variable i from the top of the stack local EQU 13 ; number of bytes of local variables div32 PSHA PSHB PSHX PSHY TSX ; allocate local variables XGDX ; “ SUBD #local ; “ XGDX ; “ TXS ; “ TSY ; Y points the top byte of the stack LDD #0 ; initialize R to 0 STD R,Y ; “ STD R+2,Y ; “ LDD dividend,Y ; transfer dividend to Q STD Q,Y ; “ LDD dividend+2,Y ; “
STD Q+2,Y ; transfer dividend to Q LDAA #32 ; initialize loop count to 32 STAA i,Y ; “ loop LSL Q+3,Y ; shift register pair (R, Q) to the left one place ROL Q+2,Y ; “ ROL Q+1,Y ; “ ROL Q,Y ; “ ROL R+3,Y ; “ ROL R+2,Y ; “ ROL R+1,Y ; “ ROL R,Y ; “ LDD R+2,Y ; subtract the divisor P from R SUBD divisor+2,Y ; “ STD buf+2,Y ; “ LDAA R+1,Y ; “ SBCA divisor+1,Y ; “ STAA buf+1,Y ; “ LDAA R,Y ; “ SBCA divisor,Y ; “ BCS smaller ; is [R] – divisor < 0? STAA R,Y ; store the difference back to R when the difference is positive LDD buf+2,Y ; “ STD R+2,Y ; “