Question
Assembly Language Help. Please any help would be appreciated Programming Assignment 5 (Due Wednesday April 4 at Midnight) In this assignment you will write a
Assembly Language Help. Please any help would be appreciated
Programming Assignment 5 (Due Wednesday April 4 at Midnight) In this assignment you will write a program to evaluate a series of expressions that use signed numbers that are stored in parallel arrays. This will give you some practice with arrays in assembly and assembly language math operations (*,/,+,-,%).
You will also get some practice writing functions that perform math operations using stack parameters. You are to modify the given DspDword (DspDwordSP18.asm) to work with signed numbers. You should use DspDword instead of WriteDec to print out signed decimal numbers which could include a negative sign (-). Required Constants (using "equ")
You should define a constant for linefeed (LF). You should also declare the ARRAY_SIZE constant in the data section right after the declaration of the 2 dword arrays (see variables below).
Please use the constant in the code section of your code and not hard code the number otherwise points will be taken off. You should also define the following constants to work with parameters on the stack in a function:
$parm1 EQU DWORD PTR [ebp + 8] ;parameter 1 $parm2 EQU DWORD PTR [ebp + 12] ;parameter 2 See paramPassing.asm on the class web site for an example of using the above constants. Variables (.data) You should declare the zero terminated strings necessary to generate the output shown in the sample output below including embedding LF as necessary for line spacing. You should use the text as given in the sample output section below. You should declare the zero terminated string necessary for the output title including embedding LF as necessary for line spacing. You should copy the overflow messages from the given data file, prog5OperSP18.asm. Your overflow messages must match the above messages exactly including case. Download data file - prog5OperSP18.asm IMPORTANT Download data file from the class web site and load it into Visual Studio to copy the overflow messages, operands, operators and ARRAY_SIZE constant. Do not display the data file on a web page and use copy and paste otherwise you will get compile errors. You must download the file and then load it into Visual Studio to copy the data to your program. This file does not contain all the data you must declare but only the overflow messages, operands, operators and ARRAY_SIZE constant. Expressions An expression consists of operand1 operator operand2.
When you are done you should have evaluated all the expressions. You should use the modified DspDword to print the numbers in the expressions. To access the data in the arrays you should use the following indexing notation: nameOfArray[offset] Please note: since the array of operators is define as byte and the arrays of operands are defined as dwords, you cannot use the same offset to index into all the arrays. See DisplayDecArray.asm for examples of accessing an array using an offset. The operator tells you which operation to perform on the 2 operands. For example: 135,'/',56 means 135 divided by 56. You may also declare other variables as needed but points may be deducted for any unnecessary variables. Warning: in this program it is not efficient to make strings out of the operators except for "space equals space"(" = "). Global Variables Unless directed otherwise, do not use global variables (variables declared in the .data section) in your functions. MACROS - use mPrtStr and mPrtChar You should use the mPrtStr macro to print strings and the mPrtChar macro to print single characters. You should use the mPrtChar macro at the top of the DspDwordSP18.asm file. Do not define or use any other macros. Accessing the stack in the main procedure You should not access data on the stack in the main procedure except through push and pop (no "mov eax, [esp + 8]" etc). Accessing the stack in a user defined function In a user defined function (a function you write or a given function you modify) you should only access the stack as an offset to ebp not esp with the following exception: you may subtract an integer from esp if you wish to allocate memory for a local variable. Also you should not access any data that is pushed onto the stack within a function as an offset to ebp or esp. This program should not require any local variables in a function except in DspDword in which a local variable was declared for you. Your functions should use the following $parm1 and $parm2 constants to access parameters on the stack in a function:
$parm1 EQU DWORD PTR [ebp + 8] ;parameter 1
$parm2 EQU DWORD PTR [ebp + 12] ;parameter 2
Program specification In the main procedure you should have a while loop that will keep going until all the data in both arrays is processed. You will know when all the data has been processed when the number of bytes processed equals or exceeds the totals bytes of the operand 2 array. The constant ARRAY_SIZE contains the total bytes of the operand2 array. See DisplayDecArray.asm on the class web site for an example of iterating through a dword array. Each time through the loop you are to evaluate and print one expression. You should not hardcode the data but must access the data in the arrays using the following indexing notation: nameOfArray[offset]. See DisplayDecArray.asm for an example of iterating through a dword array. Before you call a math function to perform a math operation you should push the operands onto the stack in the following order: operand2 then operand1. Then you should examine the operator to determine which math function to call per the following series of if/elses: if '-' - call the doSub procedure else if '+' - call the doAdd procedure else if '* - call the doMult procedure else (/ and % only items left) - call doDiv then take appropriate action depending on whether the operator was / or % It is up to you to figure out the most efficient way to print out the equation including the answer. You should print the numbers in the equation by calling DspDword.
Detect Overflow after calling doSub, doAdd or doMult There are three kinds of overflow you should detect: positive overflow, , negative overflow and multiplication overflow where the product does not fit in eax alone. If the overflow is positive overflow, you should print the positive overflow message and go on to evaluating the next expression. If the overflow is negative overflow, you should print the negative overflow message and go on to evaluating the next expression. Hint: if there is overflow after sub or add, look at the sign of the answer. If the answer is positive then there was negative overflow, otherwise it was positive overflow (answer was negative). Multiplication overflow If overflow is detected after calling doMult it means the product did not fit in eax alone and that the upper part of the product is in edx. Strictly speaking this is not an error condition for the 1 operand version of imul. It just means with the current program we do not have a way to print an 8 byte number contained in EDX:EAX. An overflow condition would indicate an error for the 2 and 3 operand versions of imul where the product did not fit in operand 1. If overflow is detected after calling doMult, print the "**Multiplication Overflow** message and go on to evaluating the next expression. No overflow after division Overflow cannot occur after division so you should not check for overflow after calling doDiv. It is up to you to figure out the most efficient way to print the overflow messages and go on to evaluating the next expression. You should not repeat code except code to print the different overflow message. When you are comparing the operator you should use the character not the ascii value. For example use '*' not 2Ah. Procedures You are to write the doMult, doAdd, doSub and doDiv procedures as specified below. Please define the procedures in the below order. Be sure and copy the comment block before each of the functions below and put the comment block before each of the corresponding function in your code otherwise points will be taken off. You may add to the comment block if you wish. Do not use the following directives in your functions: USES, LOCAL, ENTER or LEAVE or any other directive that automatically generates code. In order to learn assembly we want to wrote all the code ourselves without the use of directives. Each function should only have one ret in it and that should be at the bottom of the function. Each function that accesses parameters on the stack should have the following code at the top and bottom of the function: AnyFunc PROC ;required code at top push ebp mov ebp,esp ;add code to save registers if any ;and the following code at the bottom; ;add code to restore saved registers if any pop ebp ret AnyFunc ENDP You should use ebp not esp to reference parameters on the stack. Note: None of the procedures below print any messages. All messages or numbers should be printed in the main function. The only exception is you will use DspDword to print signed decimal numbers. You must use the register(s) specified in the EXIT section of the comment block before the function to return the return value if any. For example the EXIT section of the doMult function specifies that the return value is in EDX:EAX. The EXIT section of doAdd and doSub specifies that the return value must be in EAX. The EXIT section of doDiv specifies that the quotient is in EAX and the remainder is in EDX. Saving Registers that are Changed in a function Except for main you should save any registers whose values you change in a function on the stack by calling push at the beginning of the function and you should restore the values in the registers by calling pop at the end of the function. Do not save registers that do not change. Exception: do not save or restore a register that returns a value. For example in the doDiv function the quotient is returned in eax and the remainder is returned in edx so do not save or restore eax or edx in doDiv. doAdd, doSub and doMult return a value in eax so do not save or restore eax in those functions. Use ret 8 To clean up the stack after pushing parameters onto the stack and after calling a function, use ret 8 in your function. Do not use use add ESP, 4 or add ESP, 8 back in main after you call the function. Comment blocks before functions and function names Every function must have a comment block before the function describing the function. I have provided comment blocks for the functions in this program below. Just copy the comment blocks to your program. Points will be deducted if your program does not have comment blocks before the functions. Do not change the names of the functions as given. 1. doSub ;************** doSub - dword subtraction ; ; ENTRY - operand 1 and operand 2 are pushed on the stack ; ; EXIT -EAX = result (operand 1 - operand 2) ; REGS - List registers changed in this function ; ; note: Before calling doSub push operand 2 onto the stack and then push operand 1. ; ; to call doSub in main function: ; push 2 ;32 bit operand2 ; push 11 ;32 bit operand1 ; call doSub ;10 2 = 8 (answer in eax) ; ; Remove parameters by using ret 8 rather than just ret at the end of this function ;-------------- ;The same circuits can be used for addition and subtraction because negative numbers are stored in 2s complement form ;You can do a subtraction by doing a twos complement and then addition. ;To prove that this is true do not use the sub instruction in doSub but use the following method to do the subtraction: ; do a twos complement (neg instruction) on operand 2 then add operand 1 + operand 2 and store the answer in EAX. 2. doAdd ;************** doAdd - dword addition ; ; ENTRY operand 1 and operand 2 are on the stack ; ; EXIT - EAX = result (operand 1 + operand 2) (any carry is ignored so the answer must fit in 32 bits) ; REGS - List registers changed in this function ; ; note: Before calling doAdd push operand 2 onto the stack and then push operand 1. ; ; ; to call doAdd in main function: ; push 8 ;32 bit operand2 ; push 2 ;32 bit operand1 ; call doAdd ;1 + 9 = 10 (answer in eax) ; ; Remove parameters by using ret 8 rather than just ret at the end of this function ; ;-------------- ;Add operand1 to operand2 and store the answer in EAX ;Note: any carry is ignored so the answer must fit in 32 bits ;Note you must keep the operands in the correct order: op1+op2 not op2+op1. 3. doMult ;************** doMult - signed dword multiplication ; ; ENTRY - operand 1 and operand 2 are on the stack ; ; EXIT - EDX:EAX = result (operand 1 * operand 2) ; (for this assignment the product is assumed to fit in EAX and EDX is ignored) ; ; REGS - List registers changed in this function ; ; note: Before calling doMult push operand 2 onto the stack and then push operand 1. ; ; to call doMult in main function: ; push 3 ;32 bit operand2 ; push 4 ;32 bit operand1 ; call doMult ; 6 * 2 = 12 (answer in eax) ; ; Remove parameters by using ret 8 rather than just ret at the end of this function ;-------------- ;Take operand1 times operand2 using signed multiplication and the result is returned in EDX:EAX. ;Note: this function does signed multiplication not unsigned. See imul.asm on the class web site. ;Only use the single operand version of imul. ;Please note that this program assumes the product fits in EAX. If part of the produce is in EDX, it is ignored. ;Note you must keep the operands in the correct order: op1*op2 not op2*op1. (continued on next page) 4. doDiv ;************** doDiv - signed dword / dword division ; ; ENTRY - operand 1(dividend) and operand 2(divisor) are on the stack ; ; EXIT - EAX = quotient ; EDX = remainder ; REGS - List registers changed in this function ; ; note: Before calling doDiv push operand 2(divisor) onto the stack and then push operand 1(dividend). ; ; to call doDiv in main function: ; push 4 ;32 bit operand2 (Divisor) ; push 21 ;32 bit operand1 (Dividend) ; call doDiv ;19/ 4 = 4 R3(4 = quotient in eax, 3 = remainder in edx ) ; ; Remove parameters by using ret 8 rather than just ret at the end of this function ;-------------- ;Take operand1 /operand 2 and the quotient is returned in EAX and the ; remainder is returned in EDX. ;doDiv does signed division. See idiv.asm on the class web site. ;Note: since we are doing signed division you should sign extend parameter 1 into edx using CDQ instead of zeroing out edx ;Note: after calling doDiv for the modulus operation (%) look at the value that is returned in edx which is the remainder. doDiv does not process the modulus operator. Modify DspDword (DspDwordSP18.asm) Copy DspDword from DspDwordSP18.asm including its comment block to your program (comment block required). Change DspDword to work with signed numbers and then call it rather than WriteDec in main to print signed numbers. To modify DspDword to print signed numbers you only have to add some code above the first loop to check if the number is negative and if it is a negative number add some code to print a dash ('-') and do a twos complement on the number(neg instruction). To check if the number is negative use AND to check the sign bit. Do not use the TEST instruction. If you AND a number with itself the sign flag will be set to 1 or cleared to 0 depending on whether the sign bit (leftmost bit) of the number you are ANDing is set or clear. If you AND a number with itself the number will not change but the sign flag will be set or cleared. After you AND the number with itself you can do a js (jump sign) if you wish to jump if the number is negative or a jns (jump no sign) if the number is positive. For example: and eax, eax js negative ;jump taken if number in eax is negative If the number to print is negative you should print a dash '-' for a negative sign then do a two's complement (neg instruction) on the negative number to make it a positive one. If the number is positive then do not print a dash and do not do a two's complement. After you turn the negative number into a positive one the rest of the given code should work fine to print it out. The test for a negative number, the printing of the '-' and the code for the twos complement should be done before any loops. Before using DspDword in the main part of your program test it to make sure it is working: call it with positive and negative numbers. mov eax, -234568 call DspDword mov eax, 78345 call DspDword You may also want to test it with the maximum positive number and the minimum negative number. Once you have DspDword working properly and it correctly displays positive and negative numbers, then use it instead of WriteDec. Do not make any other changes to the program until you get DspDword working properly. Are my answers correct? You should use a calculator to determine if your answers are correct. Efficiency Please note as usual points will be taken off for inefficient or convoluted code or for code that has no effect. In this assignment pay particular attention to the following possible inefficiency: if code is repeated in a series of if/else it can be moved outside the if/else. For example take the following C++ code: if(x > 9) { cout << "hello"; cout << x - y; cout << x; } else { cout << "hello" cout << x + y; cout << x; } Since cout << "hello" and cout << x are repeated in the if/else they will always print no matter what the condition is and can be moved outside the if/else: cout << "hello"; if(x > 9) cout << x - y; else cout << x + y; cout << x; Another inefficiency to watch out for: in a procedure you can work with values directly on the stack without moving them to a register first. See paramPassing.asm for an example. Do not make a string to print a single character. To print a single character use the mPrtChar macro. If you want to access a value that is in memory and at the same time is in a register, it is more efficient to access the value in the register and not access the value in memory. Program Flow Control should flow from top to bottom Please note that the flow of a program should be from top to bottom. The only time you should jump back towards the top should be to repeat a loop. If you violate program flow, points will be taken off. Organization of code In general code should flow from top to bottom. You should only jump back towards the top to repeat a loop. Loops should flow from top to bottom. If your code does not flow from top to bottom as described above, points will be taken off. Input Input is hard coded into the program in the form of expressions to evaluate. See the Variables section above. Output The output of your program should be formatted as follows: Sample output (no color required for your output but you should match the spacing). Substitute your name for my name. Your output will be different since the expressions you are evaluating are different but you should match the format of the output below. Program 5 by Fred Kennedy 0000000056 + 0000000003 = 0000000059 -2147483647 * 0000000100 = **multiplication overflow** 0000000023 % -0000000005 = 0000000003 Please note the following about the above output: - there is no blank line before the title - there is one blank line between the title and the first expression - there are no blank lines between the expressions - there is no space before operand1 - overflow messages print after the equal sign - there is a single space between operators (including '=') and numbers: "5 + 3 = 8" should print not "5+3=8". - there is a single space between the = and the overflow message. - You should print the numbers in the expressions using the modified DspDword instead of WriteDec. - The expression on one line of output does not have to line up with the expression on the next line. Do not put in extra spaces. I will be using a comparison program to compare your output to my output and they should match exactly. Points will be taken off if you do not match the format of the above output exactly (except for your name of course). Strategy for writing the program Please do not try and write the entire program at once. I suggest the following steps: First write the math functions one at a time and make sure each one works before going on to the next one. You can test a math function by calling it in the main procedure with hard coded values. For example to test the doAdd function you could call it at the top of the main procedure as follows: push 13 push 7 call doAdd You can step through your program with F10, but to step into a function call you can hit F11. After calling doAdd and you are back in the main procedure eax should contain the correct answer of 14h (20 decimal). After you are through debugging your code you should delete all the extra code you entered to debug your program otherwise points will be taken off.
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started