News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

How to saturate a value?

Started by QvasiModo, May 17, 2005, 08:21:13 PM

Previous topic - Next topic

QvasiModo

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

Randall Hyde

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

MazeGen

I use


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

AeroASM


MazeGen

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.

MichaelW

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_.

eschew obfuscation

Posit

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

Posit

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?

MichaelW

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

eschew obfuscation

Mirno

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

AeroASM

So cmovx is like the second bit of cmpxchg? (emphasise like)?

Mirno

Aero, it's a conditional move. In other words the move only occurs if the condition is met.

Mirno

MazeGen

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 :(

dioxin


;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.

Randall Hyde

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