So I was looking at the MMX and SSE opcodes the other day and thinking, wouldn't it be nice if I could use some of those nifty features with general-purpose registers? I'm sure someone has done this before, but I have an urge to show off how clever I am :-)

Saturation of unsigned values, it turns out, is easy, since the carry flag gets set whenever overflow or underflow occurs during an add or sub operation.


; Unsigned increment with saturation
macro IncUS regmem
add regmem,1
sbb regmem,0
endm

;Unsigned decrement with saturation
macro DecUS regmem
sub regmem,1
adc regmem,0
endm

That's so basic it's hardly worth posting. What about signed saturation? The overflow flag gets set on signed overflow (go figure), but to be perfectly honest that flag is pretty useless.


; Signed increment with saturation
macro IncSSWord regmem
add regmem,8000h
add regmem,1
sbb regmem,0
sub regmem,8000h
endm

Not bad. Translate the number to an unsigned value. Turns out this should work for saturation at any arbitrary value, as long as the number being incremented does not exceed the specified value.


; Increment with saturation at specified value
macro IncSaturate regmem,limit
add regmem, - (limit + 1)
add regmem,1
sbb regmem,0
sub regmem, - (limit + 1)
endm

macro IncSSWord regmem
IncSaturate regmem,7fffh
endm

The rest of the code here hasn't been tested, but it ought to work. ;-) It's pasted from a source file, so it might look a little ugly.

; Add unsigned saturated, needs a temp register

macro add_uss reg,val,temp
add reg,val
sbb temp,temp
or reg,temp
endm

; Add signed saturated byte, needs a temp register
macro add_ssb reg,val,temp
add reg,80h
add reg,val
sbb temp,temp
or reg,val
sub reg,80h
endm

macro add_ssw reg,val,temp
add reg,8000h
add reg,val
sbb temp,temp
or reg,val
sub reg,8000h
endm

macro add_ssd reg,val,temp
add reg,80000000h
add reg,val
sbb temp,temp
or reg,val
sub reg,80000000h
endm

; Subtract unsigned saturated
macro sub_uss reg,val,temp
sub reg,val
sbb temp,temp
not temp
and reg,temp
endm

; Subtract signed saturated byte
macro sub_ssb reg,val,temp
sub reg,80h
sub reg,val
sbb temp,temp
not temp
and reg,temp
add reg,80h
endm

macro sub_ssw reg,val,temp
sub reg,8000h
sub reg,val
sbb temp,temp
not temp
and reg,temp
add reg,8000h
endm

macro sub_ssd reg,val,temp
sub reg,80000000h
sub reg,val
sbb temp,temp
not temp
and reg,temp
add reg,80000000h
endm

; Multiply unsigned saturated byte, stores result or 0ffh in AL, sets AH to 0ffh if overflow, 0 if not
macro mul_ussb reg
mul reg
sbb ah,ah
or al,ah
endm

; Multiply unsigned saturated word, stores result or 0ffffh in AX, sets DX too 0ffffh if overflow, 0 if not
macro mul_ussw reg
mul reg
sbb dx,dx
or ax,dx
endm

; Multiply unsigned saturated dword, stores result or 0ffffffffh in EAX, sets EDX to 0ffffffffh if overflow, 0 if not
macro mul_ussd reg
mul reg
sbb edx,edx
or eax,edx
endm

; Multiply signed saturated byte, needs two temp registers, trashes AH
macro mul_ssb reg,tempc,tempnc
imul reg
sbb tempc
mov tempnc,tempc
not tempnc
shl ah,1
mov ah,7fh
adc ah,0
and ah,tempc
and al,tempnc
or al,ah
endm

macro mul_ssw reg,tempc,tempnc
imul reg
sbb tempc
mov tempnc,tempc
not tempnc
shl dx,1
mov dx,7fffh
adc dx,0
and dx,tempc
and ax,tempnc
or ax,dx
endm

macro mul_ssd reg,tempc,tempnc
imul reg
sbb tempc
mov tempnc,tempc
not tempnc
shl edx,1
mov edx,7fffffffh
adc edx,0
and edx,tempc
and eax,tempnc
or eax,edx
endm


...And from the preview it looks like I might want to enable formatting codes...
Posted on 2003-03-24 20:44:25 by PopeInnocent