Assembler Routines for beginners...

Just starting out? Need help? Post your questions and find answers here.
User avatar
Michael Vogel
Addict
Addict
Posts: 2797
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Assembler Routines for beginners...

Post by Michael Vogel »

I'm interested to find a small collection of tiny procedures, written in assembler to learn from it. I've searched around in the forum, but because of the differences of PB4 to older versions, it's not easy to find the "right" way for programming such snippets...

The most important target is to be able to write (reallly small) functions which could be usefull sometimes, like

* Bit operations: SetBit ClrBit CheckBit
* Math functions: Min(), Max(), Int(), Frac()

So if anyone can put here some nice code parts (working with PB4), that would be cool!
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

I have a good collection:

some small pieces:

Code: Select all

Procedure.f RoundASM(num.f)
  !fld dword[p.v_num]
  !frndint
  ProcedureReturn
EndProcedure

Code: Select all

Procedure.l rol12(n.l,b.l); <- rotate left the bits in a 12bit value
  !mov ecx,12
  !xor edx,edx
  !mov eax,dword[p.v_b]
  !div ecx
  !mov ecx,edx
  !mov ax,word[p.v_n]
  !mov bx,ax
  !shl bx,4
  !shld ax,bx,cl
  !and ax,$0fff
  ProcedureReturn
EndProcedure
Procedure.l ror12(n.l,b.l); <- rotate right the bits in a 12bit value
  !mov ecx,12
  !xor edx,edx
  !mov eax,dword[p.v_b]
  !div ecx
  !mov ecx,edx
  !add ecx,4
  !mov ax,word[p.v_n]
  !mov bx,ax
  !shl ax,4
  !shrd ax,bx,cl
  !and ax,$0fff
  ProcedureReturn
EndProcedure
Procedure.l rol24(n.l,b.l); <- rotate left the bits in a 24bit value
  !mov ecx,24
  !xor edx,edx
  !mov eax,dword[p.v_b]
  !div ecx
  !mov ecx,edx
  !mov eax,dword[p.v_n]
  !mov ebx,eax
  !shl ebx,8
  !shld eax,ebx,cl
  !and eax,$00ffffff
  ProcedureReturn
EndProcedure
Procedure.l ror24(n.l,b.l); <- rotate right the bits in a 24bit value
  !mov ecx,24
  !xor edx,edx
  !mov eax,dword[p.v_b]
  !div ecx
  !mov ecx,edx
  !add ecx,8
  !mov eax,dword[p.v_n]
  !mov ebx,eax
  !shl eax,8
  !shrd eax,ebx,cl
  !and eax,$00ffffff
  ProcedureReturn
EndProcedure

Code: Select all

Procedure.d ATan2(y.d,x.d)
  !fld qword[p.v_y]
  !fld qword[p.v_x]
  !fpatan
  ProcedureReturn
EndProcedure

Code: Select all

Procedure.l CountChars(a.s,s.b)
  !mov edi,dword[p.v_a]    ;pointer to the first character in string (first function parameter)
  ;firstly we must find the lenght of the string:
  !;cld              ;clear DF (Direction Flag). (normally not necessary; cleared by default)
  !xor ebx,ebx  ;init counter to NULL
  !mov al,bl       ;set NULL character in AL register
  !mov ecx,ebx    ;lets set 4294967295 ($FFFFFFFF) characters maximum
  !dec ecx
  !repnz scasb    ;repeat comparing AL CPU register content with byte[edi] 
  !jecxz near _CountCharsgo    ;if NULL byte is not found within those 4294967295 characters then exit returning 0 
  !not ecx     ;else, some adjusts. Now we have the lenght at ecx register
  !mov edi,dword[p.v_a]     ;point again to the first character in string (first function parameter)
  !mov al,byte[p.v_s]    ;al=character to find
  !@@:REPNZ scasb   ;repeat comparing AL CPU register content with byte[edi]
  !jecxz near _CountCharsgo     ;until ecx value is reached
  !inc ebx       ;or a match is found
  !jmp near @r       ;continue comparing next character
  !_CountCharsgo:MOV eax,ebx   ;output the matches counter
  ProcedureReturn
EndProcedure
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
Dare2
Moderator
Moderator
Posts: 3321
Joined: Sat Dec 27, 2003 3:55 am
Location: Great Southern Land

Post by Dare2 »

These appear to be a bit of a duplication of Pyschophanta's stuff, but may:

A: Be useful
B: Get some feedback from others that is useful to us both. :)

Code: Select all

Procedure LogicalShR(a,b)
 MOV eax,a
 MOV ecx,b
 SHR eax,cl
 ProcedureReturn
EndProcedure
Procedure LogicalShL(a,b)
 MOV eax,a
 MOV ecx,b
 SHL eax,cl
 ProcedureReturn
EndProcedure
Procedure LogicalRoR(a,b)
 MOV eax,a
 MOV ecx,b
 ROR eax,cl
 ProcedureReturn
EndProcedure
Procedure LogicalRoL(a,b)
 MOV eax,a
 MOV ecx,b
 ROL eax,cl
 ProcedureReturn
EndProcedure

v1=$01 : Debug Hex(v1) : v1 = LogicalRoR(v1,1) : Debug Hex(v1)
Requires inline ASM turned on.
@}--`--,-- A rose by any other name ..
Dare2
Moderator
Moderator
Posts: 3321
Joined: Sat Dec 27, 2003 3:55 am
Location: Great Southern Land

Post by Dare2 »

Some more, again smarter minds will have better stuff:

Code: Select all

Procedure SetBit(a,b)  ; Set bit 'b' of 'a' (bit 0 is rightmost bit)
 MOV eax,1
 MOV ecx,b
 SHL eax,cl
 OR eax,a
 ProcedureReturn
EndProcedure

Procedure ClrBit(a,b)  ; Clear bit 'b' of 'a' (bit 0 is rightmost bit)
 MOV eax,a
 MOV ecx,b
 ROR eax,cl
 AND al,$FE
 ROL eax,cl
 ProcedureReturn
EndProcedure

Procedure GetBit(a,b)  ; Get bit 'b' of 'a' (bit 0 is rightmost bit)
 MOV eax,1
 MOV ecx,b
 SHL eax,cl
 AND eax,a
 SHR eax,cl
 ProcedureReturn
EndProcedure

For i = 7 To 0 Step -1
  Debug RSet(Bin(SetBit($0,i)),8,"0")
Next
Debug "---"

For i = 7 To 0 Step -1
  Debug RSet(Bin(ClrBit($0FF,i)),8,"0")
Next
Debug "---"

For i = 7 To 0 Step -1
  w.s + Str(GetBit($55,i))
Next
Debug w
@}--`--,-- A rose by any other name ..
Pupil
Enthusiast
Enthusiast
Posts: 715
Joined: Fri Apr 25, 2003 3:56 pm

Post by Pupil »

Code: Select all

Procedure.l Min(a.l, b.l)
	MOV eax, a
	MOV ebx, b
	XOr edx, edx
	CMP eax, ebx
	SETLE dl
	SUB edx, 1
	And ebx, edx
	NOT edx
	And eax, edx
	Or eax, ebx
	ProcedureReturn
EndProcedure

Procedure.l Max(a.l, b.l)
	MOV eax, a
	MOV ebx, b
	XOr edx, edx
	CMP eax, ebx
	SETLE dl
	SUB edx, 1
	And eax, edx
	NOT edx
	And ebx, edx
	Or eax, ebx
	ProcedureReturn
EndProcedure

Procedure.l SetBit(a.l, bit.l)
	MOV eax, a
	MOV edx, bit
	BTS eax, edx
	ProcedureReturn
EndProcedure

Procedure.l ClearBit(a.l, bit.l)
	MOV eax, a
	MOV edx, bit
	BTC eax, edx
	ProcedureReturn
EndProcedure

Procedure.l GetBit(a.l, bit.l)
	XOr eax, eax
	MOV edx, bit
	BT  a, edx
	SETC al
	ProcedureReturn
EndProcedure
dagcrack
Addict
Addict
Posts: 1868
Joined: Sun Mar 07, 2004 8:47 am
Location: Argentina
Contact:

Post by dagcrack »

Those are some slow min/max routines you've posted :!: (no sarcasm, just saying this after a few benchmarks I did with my own routines).
! Black holes are where God divided by zero !
My little blog!
(Not for the faint hearted!)
dioxin
User
User
Posts: 97
Joined: Thu May 11, 2006 9:53 pm

Post by dioxin »

Code: Select all

'MIN
!mov eax,a
!mov ecx,b
!cmp eax,ecx
!cmovg eax,ecx
'min value is now in eax
 
'MAX
!mov eax,a
!mov ecx,b
!cmp ecx,eax
!cmovg eax,ecx
'max value is now in eax
but note that the CMOV instruction only came in with the PentiumPro so not all Pentiums have it.
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

dagcrack wrote:Those are some slow min/max routines you've posted :!: (no sarcasm, just saying this after a few benchmarks I did with my own routines).
Care to share yours so we can learn from them? :)

cheers
Dare2
Moderator
Moderator
Posts: 3321
Joined: Sat Dec 27, 2003 3:55 am
Location: Great Southern Land

Post by Dare2 »

Come on dagcrack, stop being a voyeur at a nudist beach. :) Show us what you've got!

Or keep everything zipped up. :) (no sarcasm <- and just saying that because it seems to mean that put-downs suddenly become acceptable behaviour)
@}--`--,-- A rose by any other name ..
Pupil
Enthusiast
Enthusiast
Posts: 715
Joined: Fri Apr 25, 2003 3:56 pm

Post by Pupil »

Actually i had not benchmarked the min max routines. My intention with the routines was to skip conditional jumps and hopefully avoid having the cpu flush the pipeline because of jump prediction misses. However this seemed a futile effort as even the following code will execute faster :)

Code: Select all

Procedure.l Min(a.l, b.l)
  If a < b
    Procedurereturn a
  Else
    Procedurereturn b
EndProcedure
dioxin
User
User
Posts: 97
Joined: Thu May 11, 2006 9:53 pm

Post by dioxin »

Pupil,
avoiding jumps is a useful technique but not when replacing one jump takes up so much extra code.

The simple way to do a MIN or MAX is:

Code: Select all

	
!mov eax,a
!mov ecx,b
!cmp eax,ecx
!jg skip
!mov eax,ecx

skip:
eax now contains the result

Comparing it to your code:

Code: Select all

you've replaced this:
!jg skip
!mov eax,ecx

with this:
   XOr edx, edx 

   SETLE dl 
   SUB edx, 1 
   And ebx, edx 
   NOT edx 
   And eax, edx 
   Or eax, ebx 
So you replaced a short 2 opcode/4 byte sequence with a 7 opcode/16 byte sequence.
Also, if you look at the code, almost every line is directly dependant on the result of the previous line (edx is used in 6 of the 7 lines) so the CPU is forced to execute every line in sequence, it has no opportunity to do things in parallel.

If you need to avoid the CMOV instruction (as not all CPUs have it) then here is a clip from the Athlon Optimisation manual on how to do MIN:

Code: Select all

Example 4  Unsigned integer min function (z = x < y ? x : y):
MOV EAX, [x] ;load x
MOV EBX, [y] ;load y
SUB EAX, EBX ;x < y ? CF : NC ; x - y
SBB ECX, ECX ;x < y ? 0xffffffff : 0
AND ECX, EAX ;x < y ? x - y : 0
ADD ECX, EBX ;x < y ? x - y + y : y
MOV [z], ECX ;x < y ? x : y
This one replaces a 2 opcode/4 byte sequence with a 4 opcode/8 bytes sequence to avoid the jump. Still not as good as using CMOV but in cases where the data is random (and therefore the CPU's jump prediction is only 50% effective) it can beat the version with a jump.

Paul.
thefool
Always Here
Always Here
Posts: 5875
Joined: Sat Aug 30, 2003 5:58 pm
Location: Denmark

Post by thefool »

a real pb procedure of Dioxin's code:

Code: Select all

Procedure.l Dioxi_Min(a.l, b.l)
!mov eax,dword[p.v_a]
!mov ecx,dword[p.v_b]
!cmp eax,ecx
!cmovg eax,ecx 

ProcedureReturn

EndProcedure
and this is the fastest method i've seen. Also one of the simplest :)
dioxin
User
User
Posts: 97
Joined: Thu May 11, 2006 9:53 pm

Post by dioxin »

TheFool,
ONE of the simplest? You mean there's another, equally simple method??

I do often wonder about the usefulness of placing such short code snippets in a procedure. The procedure overheads will dwarf the time taken by the code.

Paul.
thefool
Always Here
Always Here
Posts: 5875
Joined: Sat Aug 30, 2003 5:58 pm
Location: Denmark

Post by thefool »

dioxin wrote:TheFool,
ONE of the simplest? You mean there's another, equally simple method??

I do often wonder about the usefulness of placing such short code snippets in a procedure. The procedure overheads will dwarf the time taken by the code.

Paul.
Perhaps it IS the simplest :)

True, dioxin. You can always make a macro of it :)
dioxin
User
User
Posts: 97
Joined: Thu May 11, 2006 9:53 pm

Post by dioxin »

As it happens, depending on circumstances, MMX/SSE stuff can make it simpler and quicker but unless you're already using MMX/SSE then the overhead outweighs the gain.
Post Reply