The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: QvasiModo on May 17, 2005, 08:21:13 PM

Title: How to saturate a value?
Post by: QvasiModo on May 17, 2005, 08:21:13 PM
Hi, just a quick question: does anyone know how to saturate a numeric value in a register, to the range 0-255? I don't want to use MMX or SSE stuff. Thanks in advance! :U
Title: Re: How to saturate a value?
Post by: Randall Hyde on May 17, 2005, 11:50:18 PM
Quote from: QvasiModo on May 17, 2005, 08:21:13 PM
Hi, just a quick question: does anyone know how to saturate a numeric value in a register, to the range 0-255? I don't want to use MMX or SSE stuff. Thanks in advance! :U

add al, someValue
jnc noSaturate
or al, $ff
noSaturate:

Okay, it's ugly...

In the dim recesses of my mind, I seem to recall that there was some tricky code to replicate the carry flag through all the bits of a register. But for the life of me I can't remember it now. Maybe someone else can share?
Cheers,
Randy Hyde
Title: Re: How to saturate a value?
Post by: MazeGen on May 18, 2005, 06:12:06 AM
I use


add   eax, someValue
mov   ebx,-1
cmovc eax,ebx
Title: Re: How to saturate a value?
Post by: AeroASM on May 18, 2005, 07:38:57 AM
WHat is cmovc?
Title: Re: How to saturate a value?
Post by: MazeGen on May 18, 2005, 07:48:28 AM
It is the same like MOV, but Conditional. CMOVC means MOV if CARRY, CMOVA means MOV if ABOVE etc.

For more, check for instance

http://www.x86.org/secrets/opcodes/cmov.htm

BTW, you have to use .686 directive in your header.
Title: Re: How to saturate a value?
Post by: MichaelW on May 18, 2005, 08:41:49 AM
Thanks for the link MazeGen. I actually had it in my older links but I had completely forgotten it.

So perhaps Randall was trying to remember SBB AL,AL or perhaps SALC.


; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .686                       ; create 32 bit code
    .model flat, stdcall       ; 32 bit memory model
    option casemap :none       ; case sensitive

    include \masm32\include\windows.inc
    include \masm32\include\masm32.inc
    include \masm32\include\kernel32.inc
    includelib \masm32\lib\masm32.lib
    includelib \masm32\lib\kernel32.lib
    include \masm32\macros\macros.asm

    ; Sets AL=FFh if CF=1, or AL=00 if CF=0
    ; Unlike SBB AL,AL does not affect the flags
    ; All Intel processors, AMD ??
    salc MACRO
      db  0D6h
    ENDM
    SALC EQU salc
   
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
    .code
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««« 
    xor   eax,eax
    clc
    salc
    print uhex$(eax)
    print chr$(13,10)
    xor   eax,eax
    stc
    salc
    print uhex$(eax)
    print chr$(13,10)

    xor   ebx,ebx
    mov   eax,1
    clc
    cmovc ebx,eax
    print uhex$(ebx)
    print chr$(13,10)

    xor   ebx,ebx
    mov   eax,1
    stc
    cmovc ebx,eax
    print uhex$(ebx)
    print chr$(13,10)

    mov   eax,1
    xor   ebx,ebx
    cmovnz ebx,eax
    print uhex$(ebx)
    print chr$(13,10)

    mov   eax,1
    xor   ebx,ebx
    cmovz ebx,eax
    print uhex$(ebx)
    print chr$(13,10)
   
    fcmovb  st(0),st(1) ; Just to see if supported by MASM   

    mov   eax,input(13,10,"Press enter to exit...")
    exit   
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start


Result on P3:

00000000
000000FF
00000000
00000001
00000000
00000001


My AMD K5 supports SALC but chokes on the CMOV_.

Title: Re: How to saturate a value?
Post by: Posit on May 18, 2005, 08:45:04 AM
Quote from: MazeGen on May 18, 2005, 06:12:06 AM
I use


add   eax, someValue
mov   ebx,-1
cmovc eax,ebx


The cmovx and setxx instructions are very handy for saving short jumps.

You could even save an instruction in this code (and keep ebx free) by having a variable that's set to 0xffffffff (e.g. -1). Call it neg_one. Then the code looks like


add   eax,someValue
cmovc eax,neg_one
Title: Re: How to saturate a value?
Post by: Posit on May 18, 2005, 08:56:16 AM
Quote from: MichaelW on May 18, 2005, 08:41:49 AM
My AMD K5 supports SALC but chokes on the CMOV_.

Do you mean it does not recognize the opcode?
Title: Re: How to saturate a value?
Post by: MichaelW on May 18, 2005, 09:15:01 AM
Sorry, 'choked' was not a good choice for an international forum. I meant it faulted. I am assuming it was an invalid op-code fault, but I didn't actually check.

If you don't mind the flags being affected, these should work:

mov  al,somevalue
sbb  al,al


mov  eax,somevalue
sbb  eax,eax

Title: Re: How to saturate a value?
Post by: Mirno on May 18, 2005, 09:50:17 AM
Michael your code is almost there, but it'll result in either 0 or 0xFF, not a saturated value.


add al, someValue
sbb ah, ah
or  al, ah


Mirno
Title: Re: How to saturate a value?
Post by: AeroASM on May 18, 2005, 10:41:38 AM
So cmovx is like the second bit of cmpxchg? (emphasise like)?
Title: Re: How to saturate a value?
Post by: Mirno on May 18, 2005, 11:43:44 AM
Aero, it's a conditional move. In other words the move only occurs if the condition is met.

Mirno
Title: Re: How to saturate a value?
Post by: MazeGen on May 18, 2005, 02:46:08 PM
Aero:


cmovc eax,ebx


is equal to


jnc @f
  mov eax,ebx
@@:


and also equal to


.IF CARRY?
   mov eax,ebx
.ENDIF


MichaelW: the site is long time dead unfortunately :(
Title: Re: How to saturate a value?
Post by: dioxin on May 18, 2005, 04:31:59 PM

;on entry eax= the value to saturate

test eax,&hffffff00     ;check range
setz bh                 ;create saturation masks
sets bl
dec bh
dec bl
or al,bh                ;apply masks to range limit al to 0-FF
and al,bl

;al now = the 0-255 saturated value.


Paul.
Title: Re: How to saturate a value?
Post by: Randall Hyde on May 18, 2005, 08:44:15 PM
Quote from: MichaelW on May 18, 2005, 08:41:49 AM
Thanks for the link MazeGen. I actually had it in my older links but I had completely forgotten it.

So perhaps Randall was trying to remember SBB AL,AL or perhaps SALC.


Definitely not SALC, as this is an undocumented opcode that isn't available on all processors.
There was a trick with SBB, it was something along the lines of


mov ah, 0
add al, somevalue
sbb ah, ah
or al, ah


But I don't remember if this was the exact sequence.
It is worth pointing out that this trick only works for unsigned values. If you want to clip at -128 and +127, this isn't the code for you.  In such a case, the conditional move instructions are the best bet (but only valid on PPro's and later, and a few other processors; though I suspect that we're finally to the point we can assume we can use these instructions, even though I personally stick to 486/Pentium instruction sets for most of my coding).

Cheers,
Randy Hyde