Experiment 3 1. Objectives In this experiment, you will learn more AVR instructions by writing AVR assembly programs to do string-to-number conversion, positional multiplication, positional division, and matrix multiplication. 2. Preparation You need to write most of your programs at home in order to finish Experiment 3 in time. Read the sample program (pages 21-23) in the lecture notes on Data Transfer Instructions before you start writing AVR code. 3. Tasks There are four tasks in this experiment. 3.1 Task A: String to Integer Conversion The program atoi.c in Figure 1 converts a string into a number. Write an AVR assembly program with the same function as atoi.c. Your program must satisfy the following requirements: a. The string 212121 is stored in the program memory. b. The result is stored in the data memory. int main(void) char s[] = "212121"; char i; long int n; n = 0; for(i=0;(s[i]>= 0 ) && (s[i]<= 9 );i++) n = 10 * n + (s[i]- 0 ); return n; Figure 1: Program atoi.c
Checkpoint A: Signature: 3.2 Task B: Matrix Multiplication. A two-dimensional array in C is stored in row-majored order. In row-major order, a twodimensional array is stored as an array of rows and the row i+1 is stored after the row i. For example, a 3*3 array A is stored at 0xF0 in the memory as shown in Figure 2, where each element of A is one byte long. Assume that the size of each element in an m*n array A is c bytes. The address X of A[i][j] is computed as follows: X = Y + (i*n+j)c Where Y is the starting address of A. The program matrix-product.c in Figure 3 computes the product of two 5*5 matrices A and B and stores the result in the array C. Assume that all elements of the arrays A, B and C are ONE byte long. Write an AVR assembly program to implement the C program. All the variables in the C program must be stored in the data memory. Checkpoint B: Signature: 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7 0xF8 A[0][0] A[0][1] A[0][2] A[1][0] A[1][1] A[1][2] A[2][0] A[2][1] A[2][2] Figure 2: The layout of A[3][3] in the memory
int main(void) int i, j, k; int A[5][5], B[5][5], C[5][5]; for (i=0; i<5; i++) for (j=0; j<5; j++) A[i][j]=i+j; B[i][j]=i-j; C[i][j]=0; for(i=0;i<5;i++) for(j=0;j<5;j++) for(k=0;k<5;k++) C[i][j]+= A[i][k] * B[k][j]; return 0; Figure 3: matrix-product.c 3.3 Task C: Positional Multiplication. Hand-multiplication uses a series of multiplication shifts and additions to get the final answer. Multiplication using binary arithmetic is much simpler as each multiplier bit is either 0 or 1. So there is no multiplication at all: just shift and add if the multiplier bit is 1, or just shift with no add if the multiplier bit is 0. The C program in Figure 4 is an example of a multiplier that works on positional basis. Assume that the register pair r16:r15 store the multiplicant, r18:r17 store the multiplier and r21:r20:r19 store the result. Write an AVR assembly program to implement the C program pos-mul.c. Your assembly program CANNOT use any AVR multiplication instruction. Checkpoint C: Signature:
int main(void) unsigned int multiplicand, multiplier; unsigned int product; int m1, m2, m3, m4, m5, m6, m7; m1 = 2 * multiplicand; m2 = 4 * multiplicand; m3 = 8 * multiplicand; m4 = 16 * multiplicand; m5 = 32 * multiplicand; m6 = 64 * multiplicand; m7 = 128 * multiplicand; if(multiplier > 255) product = 0; else product = 0; if (multiplier >= 128) product = product + m7; multiplier = multiplier - 128; if (multiplier >= 64) product = product + m6; multiplier = multiplier - 64; if (multiplier >= 32) product = product + m5; multiplier = multiplier - 32; if (multiplier >= 16) product = product + m4; multiplier = multiplier - 16; if (multiplier >= 8) product = product + m3; multiplier = multiplier - 8; if (multiplier >= 4) product = product + m2; multiplier = multiplier - 4; continues on the next page...
if (multiplier >= 2) product = product + m1; multiplier = multiplier - 2; if (multiplier >= 1) product = product + multiplicand; multiplier = multiplier - 1; return product; Figure 4: pos-mul.c 4.4 Task D: Positional Division. Hand-division uses a series of left shifts, magnitude checks and multiple substractions to get the final answer. For example, 3217/16 can be calculated as: 1. Shift the divisor 16 to the left as many times as possible, until just before it becomes greater than the dividend 3217. This means it is left-shifted by two digits; the shifted divisor is 1600. 2. Subtract a multiple of this shifted divisor (2 1600 = 3200) from the dividend, leaving 17 as the partial quotient of 200. 3. In the second iteration, shift the new divisor 1600 right by one digit to become 160. This is greater than the partial remainder 17, so do not subtract anything. 4. In the third iteration, shift the new divisor 160 right by one digit to become 16. 5. Subtract a multiple of this shifted divisor (1 16 = 16) from the new dividend (the previous partial remainder) 17, leaving 1 as the new partial remainder. Add the multiple 1 to the previous partial quotient of 200, giving 201. 6. Finally, stop the iteration here, as no more right shifts are possible. The old partial quotient of 201 becomes the actual quotient (result); the old partial remainder becomes the actual remainder. The program in Figure 5 is an implementation of this positional division algorithm in C. Assume that the register pair r16:r15 store the dividend, r18:r17 store the divisor and r20:r19 store the quotient. Write an AVR assembly program to implement the C program pos-div.c. Checkpoint D: Signature:
int posdiv(unsigned int dividend, unsigned int divisor) unsigned int quotient; unsigned int bit_position = 1; quotient = 0; while ((dividend > divisor) &&!(divisor & 0x8000)) divisor = divisor << 1; bit_position = bit_position << 1; while (bit_position > 0) if (dividend >= divisor) dividend = dividend - divisor; quotient = quotient + bit_position; divisor = divisor >> 1; bit_position = bit_position >> 1; return quotient; Figure 5: pos-div.c