I am sorting 3 numbers in HLA Assembly Language in Ascending order. I am not getting the right answer. What is wrong with my logic in HLA. For Example, if I enter 12, 1, 50, it should sorted 1, 12, 50. Instead,I am getting following result:
Gimme X: 12
Gimme Y: 1
Gimme Z: 50
swapXandY swapXandZ swapYandZ After Sorting, X = 50, Y = 1, Z = 12
Here is the code in C++
#include <iostream>
void Sort(int &a, int &b, int &c){
if(a>b){
int tmp = a;
a = b;
b = tmp;
}
if(a>c){
int tmp = a;
a=c;
c = tmp;
}
if(b>c){
int tmp = b;
b=c;
c=tmp;
}
return;
}
Here is my HLA code:
program SwapperProgram;
#include ("stdlib.hhf");
static
iValue1 : int16;
iValue2 : int16;
iValue3 : int16;
//-------------------------------------------
procedure swapper (var x : int16; var y : int16; var z : int16); @nodisplay; @noframe;
static
dReturnAddress : dword;
iTemp : int16;
dEDXRegister : dword := 0; // preserve EDX
dECXRegister : dword := 0; // preserve ECX
dEBXRegister : dword := 0; // preserve EBX
dEAXRegister : dword := 0; // preserve EAX
begin swapper;
mov (EAX, dEAXRegister);
mov (EBX, dEBXRegister);
mov (ECX, dECXRegister);
mov (EDX, dEDXRegister);
pop( dReturnAddress ); // This is the return address
pop (ECX); // This is the address of z
pop (EBX); // This is the address of y
pop (EAX); // This is the address of x
push (dEAXRegister);
push (dEBXRegister);
push (dECXRegister);
push (dEDXRegister);
cmp (EAX, EBX); // if (x > y)
jg swapXandY; // swap x and y
cmp (EAX, ECX);
jg swapXandZ;
cmp (EBX, ECX);
jg swapYandZ;
swapXandY:
stdout.put ("swapXandY ");
mov ([EAX], EDX);
mov (DX, iTemp);
mov ([EBX], EDX);
mov (DX, [EAX]); // *EAX = DX
mov (iTemp, DX);
mov (DX, [EBX]);
swapXandZ:
stdout.put ("swapXandZ ");
mov ([EAX], EDX);
mov (DX, iTemp);
mov ([ECX], EDX);
mov (DX, [EAX]);
mov (iTemp, DX);
mov (DX, [ECX]);
swapYandZ:
stdout.put ("swapYandZ ");
mov ([EBX], EDX);
mov (DX, iTemp);
mov ([ECX], EDX);
mov (DX, [EBX]);
mov (iTemp, DX);
mov (DX, [ECX]);
jmp ExitSequence;
ExitSequence:
pop (EDX);
pop (ECX);
pop (EBX);
pop (EAX);
push (dReturnAddress);
ret();
end swapper;
//---------------------------------------------------------------------------------
begin SwapperProgram;
stdout.put ("Gimme X: ");
stdin.get (iValue1);
stdout.put ("Gimme Y: ");
stdin.get (iValue2);
stdout.put ("Gimme Z: ");
stdin.get (iValue3);
lea( EAX, iValue1 ); // get address of iValue1
push( EAX );
lea( EAX, iValue2 ); // get address of iValue2
push( EAX );
lea( EAX, iValue3 ); // get address of iValue3
push( EAX );
call swapper;
stdout.put ("After Sorting, X = ", iValue1);
stdout.put (", Y = ", iValue2);
stdout.put (", Z = ", iValue3);
end SwapperProgram;
//---------------------------------------------------------------------------------
Where in my code is wrong? I know I am missing a logic
Your control flow is messed up.
The first thing I think you need to appreciate is that labels do not exist in machine code, so the processor doesn't see them — they don't stop execution or change control flow — only instructions do that.
Among other things, labels are used by the assembler to compute the numeric offsets needed in machine code instructions like branches.
Let's take a very methodical approach to translation of the control flow of your pseudo code:
Translating this into the if-goto-label style of assembly, but still in C so you can really read it:
Can you see how when the first if-statement is completed, it runs the next if-statement, whether or not the first if-statement fires/runs its then part.
This is how the control flow works in high level language, and if replicated using this methodical translation-by-pattern approach, the control flow will work the same in assembly language as it does in C.
I recommend the above methodical approach, which translates based on control statement pattern matching, and, keeps the assembly code blocks in the same order as the C code blocks. In this approach, the label names relate to the control structures, not to the nature of the code that comes after the label.
(Even though the labels are not seen by the processor in machine code, they are critical parts to translation of pseudo code in an assembly language version.)
The only real downside of this approach is that conditional tests sometimes (here always) need to be reversed/negated, since we tell the processor when to skip around a then-part, i.e. skip ahead to the next statement — rather than when to execute a then-part (as we do in C).
However, in assembly, we have additional choices, as we can gotos as we like, so other translations are possible. For example, here's one.
This is also a valid translation of the control flow structures of the pseudo code. (Here I also use label names that relate to the control flow rather than to operations being performed after the label.)
Though this works, I generally don't care for this out of line form, especially when translating from pseudo code, since it breaks up statements into piece parts that are separated from each other and distributed around the function. One advantage, of course, is that the conditional operations do not have to be reversed as they are with the more methodical pattern match approach I recommend above.