neilobremski
Experienced Member
I was reading a StackOverflow post on writing an absolute value function in assembler [SUP][1][/SUP] and while the no-branching idea is exciting, I was sad that no 16-bit version was listed. The problem with converting the 32-bit assembler had to do with all of the crazy shifting, which is quite slow on the 8088 if you're doing more than a couple of bits in either direction. The no-branching concept is thus:
Where y = 0xFFFF if x is negative and y = 0x0000 if x is positive. The problem here is obviously how to get y. I mean this still sounds like branching is required in 16-bit. But then I disassembled the MSVC 5.1 code for abs() with /Ox and it revealed the following for ABS(AX):
Voila! By the way, what I did (for future reference to myself) to DEBUG this was to raise interrupt 3 (breakpoint) directly from within the C code and then trace from there ...
Somehow I was under the impression that CWD wasn't even supported until the 286 ... whoops.
Using CBW and CWD can also be used to get the sign of a number as -1 or 1 (with zero counting as positive). The following tests the sign of the byte AL and puts a -1 or 1 into AH:
It's too bad I couldn't somehow use OR AL, 01 because that machine code instruction is only two bytes instead of three. If AL is to contain the result then an extra MOV AL, AH is needed.
To count zero as its own thing (so results could be -1, 0, or 1) then I don't see a clear way to do it besides adding a JZ branch. Maybe someone could enlighten me? Yes! See this thread: 16-bit X86 Trick to Multiply by a Number's Sign?
Footnotes:
[SUP][1][/SUP]. https://stackoverflow.com/questions/2639173/x86-assembly-abs-implementation
Code:
abs(x) = (x XOR y) - y
Where y = 0xFFFF if x is negative and y = 0x0000 if x is positive. The problem here is obviously how to get y. I mean this still sounds like branching is required in 16-bit. But then I disassembled the MSVC 5.1 code for abs() with /Ox and it revealed the following for ABS(AX):
Code:
CWD
XOR AX, DX
SUB AX, DX
Voila! By the way, what I did (for future reference to myself) to DEBUG this was to raise interrupt 3 (breakpoint) directly from within the C code and then trace from there ...
Code:
#include <dos.h>
#include <math.h>
int main(void) {
union REGS regs;
int x = 0xDEAD, y = 0xBEEF;
int86(3, ®s, ®s);
x = abs(y);
return 0;
};
Somehow I was under the impression that CWD wasn't even supported until the 286 ... whoops.
Using CBW and CWD can also be used to get the sign of a number as -1 or 1 (with zero counting as positive). The following tests the sign of the byte AL and puts a -1 or 1 into AH:
Code:
CBW
OR AH, 01
It's too bad I couldn't somehow use OR AL, 01 because that machine code instruction is only two bytes instead of three. If AL is to contain the result then an extra MOV AL, AH is needed.
To count zero as its own thing (so results could be -1, 0, or 1) then I don't see a clear way to do it besides adding a JZ branch. Maybe someone could enlighten me? Yes! See this thread: 16-bit X86 Trick to Multiply by a Number's Sign?
Footnotes:
[SUP][1][/SUP]. https://stackoverflow.com/questions/2639173/x86-assembly-abs-implementation