Hi I am working on an assembly, technically HLA(High Level Assembly) assignment and I am a bug that I need help with. Here is the assignment:
Write an HLA Assembly language program that implements a function which correctly identifies whether all the parameters are different, returning either 0 or 1 in EAX depending on whether this condition has been met. This function should have the following signature:
procedure allDifferent( x: int16; y : int16; z : int16 ); @nodisplay; @noframe;
Shown below is a sample program dialogue.
Feed Me X: 205
Feed Me Y: 170
Feed Me Z: 91
allDifferent returns true!
Feed Me X: 0
Feed Me Y: 0
Feed Me Z: 0
allDifferent returns false!
Feed Me X: 121
Feed Me Y: 121
Feed Me Z: 121
allDifferent returns false!
Here is the code I have. My problem is that regardless of what numbers I put in, it always returns "allDifferent returns false!" Thanks you for the help.
program allDifferent;
#include( "stdlib.hhf" );
static
iDataValue1 : int16 := 0;
iDataValue2 : int16 := 0;
iDataValue3 : int16 := 0;
iDataValue4 : int16 := 0;
procedure allDiff( x: int16; y : int16; z : int16 ); @nodisplay; @noframe;
static
returnAddress : dword;
temp : int16;
begin allDiff;
pop(returnAddress);
pop(z);
pop(y);
pop(x);
pop(temp);
push(returnAddress);
push(AX);
push(BX);
mov(x, AX);
cmp(y, AX);
je xyequal;
jmp notequal;
xyequal:
mov(y, BX);
cmp(z, BX);
je equal;
jmp notequal;
equal:
mov(0, EAX);
jmp ExitSequence;
notequal:
mov(1, EAX);
jmp ExitSequence;
ExitSequence:
pop(BX);
pop(AX);
ret();
end allDiff;
begin allDifferent;
stdout.put( "Gimme a X:" );
stdin.get( iDataValue1 );
stdout.put("Gimme a Y:");
stdin.get(iDataValue2);
stdout.put("Gimme a Z:");
stdin.get(iDataValue3);
push( iDataValue1 );
push( iDataValue2 );
push( iDataValue3 );
push( iDataValue4 );
call allDiff;
cmp(EAX, 1);
je ISDIFFERENT;
jmp NOTDIFFERENT;
ISDIFFERENT:
stdout.put("allDifferent retursn true",nl);
jmp EndProgram;
NOTDIFFERENT:
stdout.put("allDifferent retursn false",nl);
jmp EndProgram;
stdout.newln();
EndProgram:
end allDifferent;
notequal:
mov(1, EAX); <<- good.
jmp ExitSequence;
:
ExitSequence:
pop(BX);
pop(AX); <<- not so good.
ret();
Have a close look at what's happening to AX
in the above sequence. Even though you set it to something within the code, you overwrite that value with the pop
instruction, reverting AX
to whatever it was when you entered the function.
Assembler functions should generally preserve and restore registers that may be being used by the callers, but not when you want to use that register to return some useful piece of information.
In addition, your parameters are not being treated correctly. You push them in the order {p1, p2, p3, junk}
(not sure why you have a fourth parameter since you don't use it for anything).
But, within the function, you pop in the order {x, y, z, temp}
. Now, because the stack is a LIFO (last in, first out) structure, the mappings will be:
junk -> x
p3 -> y
p2 -> z
p1 -> temp
That means the x
variable will be set to some arbitrary value rather than one of the "real" parameters you passed in.
If you're not going to use that fourth parameter, I'd suggest getting rid of it. If you do want to use it at some point, you'll need to correlate your push and pop operations so you get the correct values.
As an aside, you could probably also make your code a lot cleaner in a couple of ways.
First, there's no real need to use (or save/restore) BX
since AX
is used locally (in a small mov/cmp
block). You could use AX
both for the xy
check and the yz
check.
Second, you could get rid of quite a few of the jumps that aren't actually needed. The pseudo-code for your algorithm can boil down to a very simple:
if x and y are same, go to NOTDIFF.
if y and z are same, go to NOTDIFF.
DIFF:
set AX to 1
go to END
NOTDIFF:
set AX to 0
END:
return