EE 314 Microprocessor Systems Spring 2002 Laboratory Project #3 Arithmetic and Subroutines Overview and Introduction Review the information in your textbook (pp. 115 - 118) on ASCII and BCD arithmetic. This lab has two parts. In the first you will work with ASCII and BCD arithmetic. The lab takes a step-bystep logical progression. You will start by modifying a small program that adds unpacked BCD to instead add packed BCD in the pre-lab. In the lab session you will then write a program that converts ASCII numbers to packed BCD. This will be followed by a program that adds two packed BCD number of uniform length. The two programs you do in the lab session 1 will then be turned into sub-routines that are used by another program. In the second part, you will adapt the program you wrote to be called from another procedure using a stack frame to pass parameters. The idea of using a stack frame is a fundamental and very important concept. It is the mechanism that C and other languages use to pass parameters and provide space for local variables inside function calls. It is powerful idea that realizes independent, relocatable, generically-usable subroutines. An additional discussion of stack frames and parameter passing is included in Pre-lab Part 2. Reading it is not necessary to do part 1. Arithmetic calculations such as addition and subtraction are fundamental to computer software. When calculations are performed, numeric data is often translated from ASCII into binary format because the arithmetic computations are much faster in binary format than in ASCII or BCD. Unfortunately, the conversions from ASCII to binary and vice versa are fairly complex and require more computation. So whether you choose binary or ASCII representation depends a lot on the amount of arithmetic needed for each IO operation. If there is a small amount of IO and a lot of arithmetic, then binary is better. If there is a lot of IO and only a little arithmetic to do, then ASCII or BCD is better. Some applications, such as business computations for example, tend to do a lot of reading and writing of numbers, but relatively little computation. In these cases, it makes sense to do the arithmetic with decimal numbers in BCD or ASCII format. This project deals with decimal arithmetic and provides more experience in writing programs. An arithmetic calculation with two arrays containing multi-digit numbers can be written in a subroutine so that it can be re-used wherever needed. To work with any size array however, the number of digits (or array elements) must be indicated in some way. Two possible alternatives are: 1) use an end-marker appended after the last element of the digit-array (as is often done with character arrays in C), and 2) pass the value to the subroutine as a parameter. When using the first approach, the value represented by the end-marker must be unique: in other words, it cannot represent any BCD or ASCII number. Alternative 2 removes this restriction, but requires that an additional parameter be passed to the subroutine. Objectives 1. 2. To learn to use the stack for parameter passing. To practice working with decimal arithmetic in an assembly language program Note: This lab will take two laboratory sessions to complete. Pre-Lab Part 1 Decimal arithmetic (due at the beginning of the first lab period) This is a fairly in-depth and lengthy project, which means you will learn a lot from it. Therefore, it is recommended that you do it well ahead of time. The best way to answer these questions is to experiment with the steps using PWB and CodeView. Part 1. The 80x86 family instruction set provides several instructions to aid in performing decimal arithmetic. Among these are AAA (ASCII Adjust AL after Addition) and DAA (Decimal Adjust AL after Addition). AAA is used when adding ASCII digits or unpacked BCD digits, and DAA is used for adding packed BCD digits. Both work only with the AL register, so we can add only one-byte numbers in each step. In both cases, the adjust instruction is used after an ADD or ADC instruction to convert a 4 or 8 bit hex number to a 4 or 8 bit BCD number (with a possible carry). When adding unpacked BCD digits or ASCII digits and a number greater than 10 results, the AAA instruction will add 1 to AH, set the C flag, and clear the upper 4 bits of AL. This allows the programmer to convert the result back to ASCII by adding 3030H, or leave it in unpacked BCD form in AX. For adding multi-byte packed BCD numbers, you must take into account the value of the C flag when adding the digits to the left of the first 2. Here is an example of a program to add two 3-digit unpacked BCD numbers: U1 U2 DB DB 0H, 5H, 2H, 1H 0H, 4H, 8H, 4H MOV MOV AX,CS DS,AX MOV ADD AAA MOV MOV ADC AAA MOV MOV ADC MOV AAA MOV MOV AL,U1+3 AL,U2+3 ;the first 0H is to store the carry ; add U2+3 to U1+3 ; this makes ds equal to cs U1+3,AL AL,U1+2 AL,U2+2 ;add U2+2 to U1+2 U1+2,AL AL,U1+1 AL,U2+1 AH,0H ;add U2+1 to U1+1 U1+1,AL U1,AH ;note: use add with carry ;clear AH before adjustment ;set the leftmost digit of U1 Similar techniques can be used for adding multi-byte packed BCD numbers, with a few minor differences. First, you must use DAA instead of AAA. Second, you can process two digits at a time. Third, unlike AAA, DAA does not add 1 to AH if there is a carry out of AL. Thus, you must depend on the C flag to tell you if the last addition produced a carry that must be copied to the leading digit of the result. Modify the above program for adding two 3-digit packed BCD numbers such as the following: P1 DB 00H, 56H, 43H, 21H P2 DB 00H, 45H, 68H, 54H Lab Procedure Part 1 In both parts (a) and (b) or Part 1 the results will be verified using CodeView. No output to screen is necessary. You will demonstrate these programs the second week of lab (The week of Feb. 7 to Feb. 11). a) Write a program that converts a string of ASCII numbers (no letters allowed) into a packed BCD number. This program should be able to handle a number of any length. To achieve this use a separate variable that tells you the length of the ASCII number. An example of how to structure this is given below in Figure 1: .286c CODE CODE SEGMENT 'code' ENDS STACK SEGMENT STACK DW 100 STACK ENDS DATA DATA CODE DUP(0FFFFH) SEGMENT 'data' NUMBER DB '99918764' BUFFER DB 4 dup (0) LENGTH DB 8 ENDS SEGMENT 'code' ASSUME CS:CODE,DS:DATA,SS:STACK include macro.inc A2PBCD PROC NEAR ;(code goes here to convert the ASCII NUMBER ; to packed BCD and store it into BUFFER) A2BCD ENDP START: MOV MOV AX,DATA DS,AX ;Initialize the DS register. EXIT: CALL A2PBCD MOV AX,4C00H ;After the program runs, INT 21H ;return Figureto1.DOS. CODE ENDS Be sure to test this program with variable length numbers. Using this successfully in part 2 of the lab END upon START procedure relies being able to use this program with arbitary number. This program should be able to handle arbitrary length numbers by changing only the length of the NUBMER and BUFFER and the value in LENGTH. b) Write a program that takes 2 packed BCD numbers of arbitrary (but uniform) length, adds them, and writes them back to a buffer. This program will be very much like the program you modified in the pre-lab. However, like part (a) you need to use a separate variable to tell you the length of the numbers. Again, this program should be able to handle arbitrary length numbers by only changing the LENGTH, the size of BUFFER, and the numbers. For example (Figure 2): .286c CODE CODE SEGMENT 'code' ENDS STACK SEGMENT STACK DW 100 STACK ENDS DATA DATA CODE DUP(0FFFFH) SEGMENT 'data' PBCDNUM1 DB ,99h,99h,17h,33h PBCDNUM2 DB 91h,45h,81h,00h BUFFER DB 5 dup (0) LENGTH DB 4 ENDS SEGMENT 'code' ASSUME CS:CODE,DS:DATA,SS:STACK include macro.inc ADDBCD PROC NEAR ;(code goes that adds PBCDNUM1 to PBCDNUM2 and writes ;the result back into BUFFER) ADDBCD ENDP START: MOV MOV AX,DATA DS,AX ;Initialize the DS register. EXIT: CALL A2PBCD MOV AX,4C00H ;After the2. program runs, Figure INT 21H ;return to DOS. A couple of warnings: CODE ENDS You will have to use conditional logic to determine how many digits to add. However, using CMP ENDtheSTART will alter flags register and thus ADC may not work correctly. You'll have to think carefully about this problem and come up with a solution (PUSHF may come in handy). Notice that the length of BUFFER is 1 greater than the length of either packed BCD number. Why? Pre-Lab Part 2 In this part of the lab you will learn how to use a stack frame to pass parameters to a procedure call. You will do this by adapting your programs from part one to be functions called by another program. More on this in the Lab procedure. Stack frames are important because they are a generate method for parameter passing. Registers are limited in number, and simply pushing parameters onto the stack causes problems. This problem is demonstrated in question 1. You will need to use CodeView to observe the instructions in operation; Plan on spending some time in the Lab before your lab session. 1) Experiment with the stack and stack pointer with the following steps. a) Create a program and load the following registers with the following values. AX=0AAAAH, BX=5555H, CX = 00003h b) What is the content of SP initially. c) What is the content of SP and CX after executing each of the following statements? PUSH AX PUSH BX POP CX d) It may be useful to keep track of the data stored on the stack by using a diagram to represent memory drawn with SS at the bottom, the initial SP at the top, and the data filled in at each location as data is pushed and popped to/from the stack. Draw such a diagram for step c. e) Repeat steps c) and d) for the following sequence of statements (reload the registers with the values from step a) ): PUSH CX CALL proc1 POP CX Proc1PROC near POP CX PUSH AX RET Proc1 endp You will notice that the sequence of instruction probably doesn't behave the way you think they will. Expect to the value of SP change after the CALL and RET instructions. You should notice the value of CX is not restored by the POP CX within proc1. You will also notice that the RET doesn’t go back to the right place. Why? (Recall what happens during a CALL and RET instruction). As you can see, the storage of the return address creates a problem when trying to use the stack. Fortunately, there is a solution. You may recall from lecture that when you use the BP register to access memory BP uses SS as its base register instead of the default DS register. This tool gives us a very general procedure to pass parameters to and from PROC calls, while getting around the problem of the return address being stored in the stack. This procedure is enumerated in Figure 3. See sfexampl.asm to see this procedure in action. Steps to using To Enter a Stack Frame 1) Push args 2) Call proc 3) push bp 4) mov bp,sp 5) sub sp,n (n an even number: the number of bytes required to hold local variables) To Exit a Stack Frame 1) mov sp, bp 2) pop bp 3) ret 4) pop/clean-up args … possibly use returned values (you won't do this in this lab) All of these concepts are demonstrated in sfexampl.asm. If necessary, build this program and observe its operation in CodeView. Lab Procedure Part 2 Change your program from Lab Procedure Part 1 into two separate procedure. You must name these procedures ASC2PBCD (ASCII to Packed BCD) and ADDPBCD (Add packed BCD). Your demonstration will consist of supplying a file with the procedures only. This function will then be called by a driver program by the TA. The driver program will use each of your procedure calls multiple times. The TA's program will do the followin (several times with several sets of data): 1) Convert 2 equal but arbitrarily long string of ASCII decimal numbers to PBCD 2) Add these 2 packed BCD number (which are of arbitrary length) The program driver.asm has been provided for you to test your procedures. This file demonstrates the exact order procedures will be passed onto the stack. You must use the procedures passed on the stack, and you may NOT use any memory outside the stack frame for your local variables. A demonstration of multifile projects will be given, and the program sfexampl.asm will also be posted to the web as a multifile project. Lab report You will have to write a lab report for this lab summarizing the results of all parts of the lab.