I\'m writing a C subroutine in assembler that needs to find the 2 largest values out of 4 values passed in and multiplies them together. I\'m working on finding the largest val
This is my first solution to process the maximum number between four 16 Bit unsigned integer input numbers (80x86+ processors compatibile):
Procedure Max4; Assembler;
{ Input: AX, BX, CX, DX
Output: AX= MAX(AX,BX,CX,DX).
Temp: DI}
Asm
{ Input: AX, BX
Output: AX= MAX(AX,BX).
Temp: DI}
Sub AX,BX
CmC
SbB DI,DI
And AX,DI
Add AX,BX
{ Input: CX, DX
Output: CX= MAX(CX,DX).
Temp: DI}
Sub CX,DX
CmC
SbB DI,DI
And CX,DI
Add CX,DX
{ Input: AX, CX
Output: AX= MAX(AX,CX).
Temp: DI}
Sub AX,CX
CmC
SbB DI,DI
And AX,DI
Add AX,CX
End;
My procedure Max4(), that is equivalent to AX=Max4(AX,BX,CX,DX), works great to a AX=Max(AX,BX) sub-routine that return a maximum value between two numbers and it is used three time:
AX=Max(Max(AX,BX),Max(CX,DX))
The AX=Max(AX,BX) sub-routine works as follow:
1) Diff=AX-BX.
2) If Diff>=0 then AX is the greatest number,
Output= Diff+BX= AX-BX+BX= AX.
3) If Diff<0 then BX is the greatest number,
must set Diff to 0,
Output= Diff+BX= 0+BX= BX.
In ASSEMBY:
{ Input: AX, BX
Output: AX= MAX(AX,BX).
Temp: DI}
Sub AX,BX
{Diff= AX-BX}
CmC
{If Diff>=0 -> FCarry=1 else FCarry=0}
SbB DI,DI
{If Diff>=0 -> DI=DI-DI-1==-1 else DI=DI-DI-0==0}
And AX,DI
{If Diff>=0 -> Diff=(Diff & -1)==Diff else Diff=(Diff & 0)==0}
Add AX,BX
{AX= Diff+BX}
But this solution works with unsigned 16 Bit numbers only and process only one largest number (don't do the multiplication). The next solution works correctly on 80x86+ processors (works with signed integer numbers; process two largest numbers):
Function Max42R(A,B,C,D:Integer):LongInt; Assembler;
Asm
Mov AX,A
Mov BX,B
Mov CX,C
Mov DX,D
{1ø swap (when needed), 1ø scan}
Cmp AX,BX
JLE @01
XChg AX,BX
{2ø swap (when needed), 1ø scan}
@01:Cmp BX,CX
JLE @02
XChg BX,CX
{3ø swap (when needed), 1ø scan}
@02:Cmp CX,DX
JLE @03
XChg CX,DX
{1ø swap (when needed), 2ø scan}
@03:Cmp AX,BX
JLE @04
XChg AX,BX
{2ø swap (when needed), 2ø scan}
@04:Cmp BX,CX
JLE @05
XChg BX,CX
{DX is the first greatest number;
CX is the second greatest number}
@05:Mov AX,DX
Mul CX
End;
It is a variation of bubble-sort algorithm. In the bubble-sort yo must compare each pair of adjacent numbers in the array and swap them if the first is greater than the second; repeat the array scan if a swap is occurred until the array is sorted. But after the first scan the last value of the array is always the greatest number. Supposing that the four input values are as in a virtual array, I swap the first three pairs of registers, only when needed, to get the first greatest value,
that is in the last register. After, I swap the first two pairs of registers, only when needed, to get the second greatest value, that is in the penultimate register.
Max4() procedure can be written on 80386+ processor as follow (support 32 Bit signed integer numbers; process one largest number):
Function Max4I(A,B,C,D:Integer):Integer; Assembler;
{ Input: EAX, EBX, ESI, EDI
Output: EAX= MAX(EAX,EBX,ESI,EDI).
Temp: CX.
EAX EDX ECX are 1°, 2° AND 3° PARAMETERs.
Can freely modify the EAX, ECX, AND EDX REGISTERs. }
Asm
Push EBX
Push EDI
Push ESI
{------------------------}
Mov EAX,A
Mov EBX,B
Mov ESI,C
Mov EDI,D
{ Input: EAX, EBX
Output: EAX= MAX(EAX,EBX).
Temp: ECX}
Sub EAX,EBX
Mov ECX,0
SetL CL
Dec ECX
And EAX,ECX
Add EAX,EBX
{ Input: EAX, ESI
Output: EAX= MAX(EAX,ESI).
Temp: ECX}
Sub EAX,ESI
Mov ECX,0
SetL CL
Dec ECX
And EAX,ECX
Add EAX,ESI
{ Input: EAX, EDI
Output: EAX= MAX(EAX,EDI).
Temp: ECX}
Sub EAX,EDI
Mov ECX,0
SetL CL
Dec ECX
And EAX,ECX
Add EAX,EDI
{------------------------}
Pop ESI
Pop EDI
Pop EBX
End;
Finally the definitive solution that get the two greatest numbers between four 32 Bit signed integer numbers (80386+ processors). It works as Max42R() function:
Function Max42(A,B,C,D:Integer):Integer; Assembler;
{ Input: EAX, EBX, ESI, EDI
Output: EDI= 1° MAX(EAX,EBX,ESI,EDI).
ESI= 2° MAX(EAX,EBX,ESI,EDI).
Temp: ECX, EDX.
EAX EDX ECX are 1°, 2° AND 3° PARAMETERs.
Can freely modify the EAX, ECX, AND EDX REGISTERs. }
Asm
Push EBX
Push EDI
Push ESI
Mov EAX,A
Mov EBX,B
Mov ESI,C
Mov EDI,D
{ Input: EAX, EBX
Output: EAX= MIN(EAX,EBX).
EBX= MAX(EAX,EBX).
Temp: ECX, EDX}
Sub EAX,EBX
Mov EDX,EAX
Mov ECX,0
SetGE CL
Dec ECX
And EAX,ECX
Add EAX,EBX
Not ECX
And EDX,ECX
Add EBX,EDX
{ Input: EBX, ESI
Output: EBX= MIN(EBX,ESI).
ESI= MAX(EBX,ESI).
Temp: ECX, EDX}
Sub EBX,ESI
Mov EDX,EBX
Mov ECX,0
SetGE CL
Dec ECX
And EBX,ECX
Add EBX,ESI
Not ECX
And EDX,ECX
Add ESI,EDX
{ Input: ESI, EDI
Output: ESI= MIN(ESI,EDI).
EDI= MAX(ESI,EDI).
Temp: ECX, EDX}
Sub ESI,EDI
Mov EDX,ESI
Mov ECX,0
SetGE CL
Dec ECX
And ESI,ECX
Add ESI,EDI
Not ECX
And EDX,ECX
Add EDI,EDX
{ Input: EAX, EBX
Output: EAX= MIN(EAX,EBX).
EBX= MAX(EAX,EBX).
Temp: ECX, EDX}
Sub EAX,EBX
Mov EDX,EAX
Mov ECX,0
SetGE CL
Dec ECX
And EAX,ECX
Add EAX,EBX
Not ECX
And EDX,ECX
Add EBX,EDX
{ Input: EBX, ESI
Output: EBX= MIN(EBX,ESI).
ESI= MAX(EBX,ESI).
Temp: ECX, EDX}
Sub EBX,ESI
Mov EDX,EBX
Mov ECX,0
SetGE CL
Dec ECX
And EBX,ECX
Add EBX,ESI
Not ECX
And EDX,ECX
Add ESI,EDX
{EDI contain the first maximum number;
ESI contain the second maximum number}
Mov EAX,EDI
{------------------------}
Pop ESI
Pop EDI
Pop EBX
End;
How to swap two register only if the first is greater then the second ?
This is the code (on the 80386+):
{ Input: EAX, EBX
Output: EAX= MIN(EAX,EBX).
EBX= MAX(EAX,EBX).
Temp: ECX, EDX}
Sub EAX,EBX (* Diff= EAX-EBX; set Overflow flag and Sign flag *)
Mov EDX,EAX (* EDX= Diff; flags not altered *)
Mov ECX,0 (* ECX= 0; flags not altered *)
SetGE CL (* If Sign flag == Overflow flag ECX= 1 else ECX=0 *)
Dec ECX (* If Diff>=0, ECX=0 else ECX=-1 *)
And EAX,ECX (* If Diff>=0, EAX=(EAX & 0)=0 else EAX=(EAX & -1)=EAX *)
Add EAX,EBX (* EAX= Minimum value between input n. *)
Not ECX (* If Diff<0, ECX=0 else ECX=-1 *)
And EDX,ECX (* If Diff<0, EDX=(EDX & 0)=0 else EDX=(EDX & -1)=EDX *)
Add EBX,EDX (* EBX= Maximum value between input n. *)
Function Max42 can be written also as the next code for 80686+ processors, that require only 20 fast ASM registers' instructions:
Function Max42B(A,B,C,D:Integer):Integer; Assembler;
{ Input: EAX, EBX, ESI, EDI
Output: EDI= 1° MAX(EAX,EBX,ESI,EDI).
ESI= 2° MAX(EAX,EBX,ESI,EDI).
Temp: ECX.
EAX EDX ECX are 1°, 2° AND 3° PARAMETERs.
Can freely modify the EAX, ECX, AND EDX REGISTERs. }
Asm
Push EBX
Push EDI
Push ESI
Mov EAX,A
Mov EBX,B
Mov ESI,C
Mov EDI,D
{ Input: EAX, EBX
Output: EAX= MIN(EAX,EBX).
EBX= MAX(EAX,EBX).
Temp: ECX}
Mov ECX,EAX
Cmp EAX,EBX
CMovGE EAX,EBX
CMovGE EBX,ECX
{ Input: EBX, ESI
Output: EBX= MIN(EBX,ESI).
ESI= MAX(EBX,ESI).
Temp: ECX}
Mov ECX,EBX
Cmp EBX,ESI
CMovGE EBX,ESI
CMovGE ESI,ECX
{ Input: ESI, EDI
Output: ESI= MIN(ESI,EDI).
EDI= MAX(ESI,EDI).
Temp: ECX}
Mov ECX,ESI
Cmp ESI,EDI
CMovGE ESI,EDI
CMovGE EDI,ECX
{ Input: EAX, EBX
Output: EAX= MIN(EAX,EBX).
EBX= MAX(EAX,EBX).
Temp: ECX}
Mov ECX,EAX
Cmp EAX,EBX
CMovGE EAX,EBX
CMovGE EBX,ECX
{ Input: EBX, ESI
Output: EBX= MIN(EBX,ESI).
ESI= MAX(EBX,ESI).
Temp: ECX}
Mov ECX,EBX
Cmp EBX,ESI
CMovGE EBX,ESI
CMovGE ESI,ECX
{EDI contain the first maximum number;
ESI contain the second maximum number}
Mov EAX,EDI
{------------------------}
Pop ESI
Pop EDI
Pop EBX
End;
Hi!