How does sign contraction work from 16 bit to 8 bit?

Solution 1:

How does sign contraction work from 16 bit to 8 bit?

It doesn't (the highest 8 bits, including the sign bit if the value is too large to fit in 8 bits, are simply discarded).

Instead, you have to implement it yourself.

If "contraction" is "preserve as many bits as possible" then it might become something like:

    add ax,ax   ;carry flag = sign bit, al = lowest 7 bits shifted left
    rcr al,1    ;al = original sign bit with original lowest 7 bits

For your test value 0xFF12 (or -238 in decimal), this becomes "0xFE24 with carry flag set" after the add, then 0x92 (or -110 in decimal) after the rcr.

More examples (including corner cases):

0xFF80 (or -128) -> "0xFF00 with carry flag set" = 0x80 (or -128)

0xFF00 (or -256) -> "0xFE00 with carry flag set" = 0x80 (or -128)

0x0000 -> "0x0000 with carry flag clear" = 0x00

0x007F (or +127) -> "0x00FE with carry flag clear" = 0x007F (or +127)

0x00FF (or +255) -> "0x01FE with carry flag clear" = 0x007F (or +127)

If "contraction" is "with saturation" (clamping values) then it might be something like:

    mov bx,ax    ;bx = original 16-bit value
    cbw          ;ax = 16-bit extension of original value in AL
    cmp ax,bx    ;Did the original value fit in 8 bits?
    je .done     ; yes, AL is correct (no saturation needed)

    add bx,bx    ;carry flag = original sign bit
    mov al,0x7F
    adc al,0     ;al = 0x80 (if value was negative) or 0x7F (if value was positive)
.done:

I'm not sure if there's a better way (it looks awful and I suspect my brain isn't working today).