525 lines
14 KiB
NASM
525 lines
14 KiB
NASM
;
|
|
; Copyright (c) Mix Software 1988
|
|
;
|
|
; ---------------------------------------
|
|
; LONG ABSOLUTE VALUE
|
|
; ---------------------------------------
|
|
;
|
|
IDT LABS
|
|
DEF LABS
|
|
DEF labs
|
|
labs equ $
|
|
LABS MOV BX,SP
|
|
MOV AX,[BX][%PARM1-2] ; GET L1
|
|
MOV DX,[BX][%PARM2-2] ; GET H1
|
|
TEST DX,DX
|
|
JNS POS
|
|
NEG DX
|
|
NEG AX
|
|
SBB DX,%0
|
|
POS RETSEG
|
|
END
|
|
;
|
|
;----------------------------------------------------
|
|
; LONG MULTIPLY
|
|
;----------------------------------------------------
|
|
IDT $_LMUL
|
|
DEF $_LMUL
|
|
$_LMUL PUSH BP
|
|
MOV BP,SP
|
|
MOV AX,[BP][%PARM1] ; LSW OF MULTIPLIER
|
|
MOV BX,[BP][%PARM2] ; MSW OF MULTIPLIER
|
|
MOV CX,[BP][%PARM3] ; LSW OF MULTIPLICAND
|
|
MOV DX,[BP][%PARM4] ; MSW OF MULTIPLICAND
|
|
PUSH BX
|
|
XOR BX,DX ; SIGN OF RESULT
|
|
ROL BX ; SAVE IN CARRY
|
|
POP BX
|
|
PUSHF
|
|
TEST BX,BX ; CHECK SIGN
|
|
JNS MUL01
|
|
NEG BX
|
|
NEG AX
|
|
SBB BX,%0
|
|
MUL01 TEST DX,DX ; CHECK SIGN
|
|
JNS MUL02
|
|
NEG DX
|
|
NEG CX
|
|
SBB DX,%0
|
|
MUL02 PUSH DX
|
|
PUSH AX
|
|
MUL CX ; LSW*LSW
|
|
MOV SI,AX ; SAVE LSW OF RESULT
|
|
MOV DI,DX ; MSW PARTIAL
|
|
POP AX
|
|
POP DX
|
|
MUL DX ; L1*H1
|
|
ADD DI,AX
|
|
MOV AX,BX
|
|
MUL CX ; L2*H1
|
|
ADD AX,DI
|
|
MOV DX,SI
|
|
POPF
|
|
JNB MUL03 ; NOT NEGATIVE
|
|
NEG AX
|
|
NEG DX
|
|
SBB AX,0
|
|
MUL03 XCHG AX,DX
|
|
POP BP
|
|
RETSEG
|
|
END
|
|
;
|
|
;----------------------------------------------------
|
|
; unsigned long multiply
|
|
;----------------------------------------------------
|
|
IDT $_LUMUL
|
|
DEF $_LUMUL
|
|
$_LUMUL PUSH BP
|
|
MOV BP,SP
|
|
MOV AX,[BP][%PARM1] ; LSW OF MULTIPLIER
|
|
MOV BX,[BP][%PARM2] ; MSW OF MULTIPLIER
|
|
MOV CX,[BP][%PARM3] ; LSW OF MULTIPLICAND
|
|
MOV DX,[BP][%PARM4] ; MSW OF MULTIPLICAND
|
|
PUSH DX
|
|
PUSH AX
|
|
MUL CX ; LSW*LSW
|
|
MOV SI,AX ; SAVE LSW OF RESULT
|
|
MOV DI,DX ; MSW PARTIAL
|
|
POP AX
|
|
POP DX
|
|
MUL DX ; L1*H1
|
|
ADD DI,AX
|
|
MOV AX,BX
|
|
MUL CX ; L2*H1
|
|
ADD AX,DI
|
|
MOV DX,SI
|
|
XCHG AX,DX
|
|
POP BP
|
|
RETSEG
|
|
END
|
|
;
|
|
;-----------------------------------------
|
|
; DIVIDE LONG
|
|
;-----------------------------------------
|
|
;
|
|
;
|
|
DIVBY0 EQU >85
|
|
IDT $_LDIV
|
|
DEF $_LDIV
|
|
DREF $$ARTERM
|
|
DREF errno
|
|
FREF $_FATAL
|
|
$_LDIV PUSH BP
|
|
MOV BP,SP
|
|
MOV BX,[BP][%PARM1] ;BX=LSW OF DIVISOR
|
|
MOV AX,[BP][%PARM2] ;AX=MSW OF DIVISOR
|
|
MOV DX,[BP][%PARM3] ;DX=LSW OF DIVIDEND
|
|
MOV CX,[BP][%PARM4] ;CX=MSW OF DIVIDEND
|
|
CALL DIVIDE
|
|
MOV DX,BX
|
|
XCHG AX,DX
|
|
POP BP
|
|
RETSEG
|
|
;
|
|
;-----------------------------------------
|
|
; MOD LONG
|
|
;-----------------------------------------
|
|
;
|
|
;
|
|
DEF $_LMOD
|
|
DEF $_LBENCO
|
|
$_LBENCO EQU $
|
|
$_LMOD PUSH BP
|
|
MOV BP,SP
|
|
MOV BX,[BP][%PARM1] ;BX=LSW OF DIVISOR
|
|
MOV AX,[BP][%PARM2] ;AX=MSW OF DIVISOR
|
|
MOV DX,[BP][%PARM3] ;DX=LSW OF DIVIDEND
|
|
MOV CX,[BP][%PARM4] ;CX=MSW OF DIVIDEND
|
|
CALL DIVIDE
|
|
MOV AX,CX
|
|
XCHG AX,DX
|
|
POP BP
|
|
RETSEG
|
|
;
|
|
DEF $_LUDIV
|
|
$_LUDIV PUSH BP
|
|
MOV BP,SP
|
|
MOV BX,[BP][%PARM1] ;BX=LSW OF DIVISOR
|
|
MOV AX,[BP][%PARM2] ;AX=MSW OF DIVISOR
|
|
MOV DX,[BP][%PARM3] ;DX=LSW OF DIVIDEND
|
|
MOV CX,[BP][%PARM4] ;CX=MSW OF DIVIDEND
|
|
CALL UDIVIDE
|
|
MOV DX,BX
|
|
XCHG AX,DX
|
|
POP BP
|
|
RETSEG
|
|
;
|
|
;-----------------------------------------
|
|
; MOD LONG
|
|
;-----------------------------------------
|
|
;
|
|
;
|
|
DEF $_LUMOD
|
|
$_LUMOD PUSH BP
|
|
MOV BP,SP
|
|
MOV BX,[BP][%PARM1] ;BX=LSW OF DIVISOR
|
|
MOV AX,[BP][%PARM2] ;AX=MSW OF DIVISOR
|
|
MOV DX,[BP][%PARM3] ;DX=LSW OF DIVIDEND
|
|
MOV CX,[BP][%PARM4] ;CX=MSW OF DIVIDEND
|
|
CALL UDIVIDE
|
|
MOV AX,CX
|
|
XCHG AX,DX
|
|
POP BP
|
|
RETSEG
|
|
;
|
|
; ---------------------------------------
|
|
; ldiv - divide and return both
|
|
; quotient and reamainder
|
|
; ---------------------------------------
|
|
; typedef struct {
|
|
; long quot; /* quotient */
|
|
; long rem; /* remainder */
|
|
; } ldiv_t;
|
|
;
|
|
; ldiv_t div(long numer, long denom)
|
|
; {
|
|
; ldiv_t s;
|
|
; s.quot = numer/denom;
|
|
; s.rem = numer%denom;
|
|
; return s;
|
|
; }
|
|
;
|
|
IDT ldiv
|
|
DEF ldiv
|
|
NUMER EQU PARM1+4
|
|
DENOM EQU PARM3+4
|
|
STRUC EQU PARM1+2
|
|
;
|
|
ldiv PUSH BP
|
|
MOV BP,SP
|
|
MOV BX,[BP][%DENOM] ;BX=LSW OF DIVISOR
|
|
MOV AX,[BP][%DENOM+2] ;AX=MSW OF DIVISOR
|
|
MOV DX,[BP][%NUMER] ;DX=LSW OF DIVIDEND
|
|
MOV CX,[BP][%NUMER+2] ;CX=MSW OF DIVIDEND
|
|
CALL DIVIDE
|
|
MOV SI,[BP][%STRUC]
|
|
MOV [SI],BX
|
|
MOV [SI][%2],AX
|
|
MOV [SI][%4],DX
|
|
MOV [SI][%6],CX
|
|
MOV AX,SI
|
|
POP BP
|
|
RETFAR
|
|
;
|
|
;-------------------------------------------
|
|
; LONG DIVIDE ROUTINE
|
|
; -------------------
|
|
; INPUT : CXDX=DIVIDEND
|
|
; AXBX=DIVISOR
|
|
; OUTPUT: AXBX=QUOTIENT
|
|
; CXDX=REMAINDER
|
|
;--------------------------------------------
|
|
DIVIDE MOV SI,AX
|
|
XOR SI,CX ; MSBit of SI = sign of result
|
|
DIV04 TEST CX,CX
|
|
JNS DIV05 ; DIVIDEND IS POSITIVE
|
|
NEG CX
|
|
NEG DX
|
|
SBB CX,%0
|
|
DIV05 TEST AX,AX
|
|
JNS DIV06
|
|
NEG AX
|
|
NEG BX
|
|
SBB AX,0
|
|
DIV06 CALL UDIVIDE
|
|
TEST SI,SI
|
|
JNS DONE
|
|
NEG AX
|
|
NEG BX
|
|
SBB AX,0
|
|
NEG CX
|
|
NEG DX
|
|
SBB CX,%0
|
|
DONE RET
|
|
;
|
|
;-------------------------------------------
|
|
; UNSIGNED LONG DIVIDE ROUTINE
|
|
; -------------------
|
|
; INPUT : CXDX=DIVIDEND
|
|
; AXBX=DIVISOR
|
|
; OUTPUT: AXBX=QUOTIENT
|
|
; CXDX=REMAINDER
|
|
;--------------------------------------------
|
|
UDIVIDE TEST AX,AX
|
|
JNZ UDIV01
|
|
TEST BX,BX
|
|
JZ DIVZERO
|
|
UDIV01 TEST DX,DX
|
|
JNZ UDIV04
|
|
TEST CX,CX
|
|
JNZ UDIV04
|
|
XOR AX,AX
|
|
XOR BX,BX
|
|
RET
|
|
UDIV04 TEST AX,AX
|
|
JNZ UDIV32
|
|
; ; MS 16 bits of divisor = 0
|
|
MOV AX,CX ; Upper word of dividend
|
|
MOV CX,DX
|
|
XOR DX,DX
|
|
DIV BX ; Divide 0:upper by bx
|
|
XCHG AX,CX ; CX = quotient, AX = lsw
|
|
DIV BX ; Divide remainder:lower by bx
|
|
MOV BX,AX ; CX = quotient MSW, AX = LSW
|
|
MOV AX,CX
|
|
XOR CX,CX ; remainder is 0:DX
|
|
EXIT RET
|
|
;
|
|
; Divisor is 32 bits long
|
|
; since msw of the divisor is non-zero, the upper 16 bits of the
|
|
; quotient must be zero, and only 16 cycles are needed to divide.
|
|
;
|
|
UDIV32 XOR DI,DI
|
|
MOV BP,16
|
|
DIVLOOP SHL DX
|
|
RCL CX
|
|
RCL DI
|
|
CMP DI,AX ; Fits in msw?
|
|
JB NEXTBIT
|
|
JNZ TOOMUCH
|
|
CMP CX,BX ; upper words equal, check lower
|
|
JB NEXTBIT
|
|
TOOMUCH SUB CX,BX
|
|
SBB DI,AX
|
|
INC DX ; Quotient gets a 1 bit
|
|
NEXTBIT DEC BP
|
|
JNZ DIVLOOP
|
|
;
|
|
; Quotient is 0:DX, remainder is DI:CX
|
|
;
|
|
XOR AX,AX
|
|
MOV BX,DX
|
|
MOV DX,CX
|
|
MOV CX,DI
|
|
JMPS EXIT
|
|
DIVZERO MOV AX,DIVBY0
|
|
MOV %[errno],AL
|
|
TEST %[$$ARTERM],%>01
|
|
JZ IGNORE
|
|
PUSH AX
|
|
CALLFAR $_FATAL
|
|
POP AX
|
|
IGNORE MOV AX,>FFFF
|
|
MOV BX,>FFFF
|
|
POS RET
|
|
END
|
|
;
|
|
; -----------------------------------------
|
|
; COMPARE LONG
|
|
; -----------------------------------------
|
|
; PUSHES A RESULT BYTE
|
|
; FF FOR LESS THAN
|
|
; 00 FOR EQUAL
|
|
; 01 FOR GREATER
|
|
;
|
|
IDT $_LCMP
|
|
DEF $_LCMP
|
|
$_LCMP PUSH BP
|
|
MOV BP,SP
|
|
XOR AX,AX
|
|
MOV CX,[BP][%PARM3]
|
|
MOV DX,[BP][%PARM4] ; GET L2
|
|
SUB CX,[BP][%PARM1]
|
|
SBB DX,[BP][%PARM2] ; COMPARE MSW
|
|
JG LCMP06
|
|
JL LCMP07
|
|
TEST CX,CX
|
|
JNZ LCMP06
|
|
POP BP
|
|
RETSEG
|
|
LCMP06 INC AX
|
|
POP BP
|
|
RETSEG
|
|
LCMP07 DEC AX
|
|
POP BP
|
|
RETSEG
|
|
END
|
|
;
|
|
; -----------------------------------------
|
|
; compare unsigned long
|
|
; -----------------------------------------
|
|
; PUSHES A RESULT BYTE
|
|
; FF FOR LESS THAN
|
|
; 00 FOR EQUAL
|
|
; 01 FOR GREATER
|
|
;
|
|
IDT $_LUCMP
|
|
DEF $_LUCMP
|
|
DEF $_LFIXUL
|
|
$_LFIXUL EQU $
|
|
$_LUCMP PUSH BP
|
|
MOV BP,SP
|
|
XOR AX,AX
|
|
MOV CX,[BP][%PARM3]
|
|
MOV DX,[BP][%PARM4] ; GET L2
|
|
CMP DX,[BP][%PARM2] ; COMPARE MSW
|
|
JA LCMP01
|
|
JB LCMP02
|
|
CMP CX,[BP][%PARM1] ; COMPARE LSW
|
|
JZ LCMP03 ; EQUAL
|
|
JNA LCMP02
|
|
LCMP01 MOV AL,1 ; GREATER THAN
|
|
JMPS LCMP04
|
|
LCMP02 MOV AL,>FF ; LESS THAN
|
|
JMPS LCMP04
|
|
LCMP03 XOR AX,AX ; EQUAL
|
|
LCMP04 POP BP
|
|
RETSEG
|
|
END
|
|
;
|
|
; ---------------------------------------
|
|
; LONG BITWISE AND
|
|
; ---------------------------------------
|
|
;
|
|
IDT $_LBITAN
|
|
DEF $_LBITAN
|
|
$_LBITAN MOV BX,SP
|
|
MOV AX,[BX][%PARM1-2] ; GET L1
|
|
MOV DX,[BX][%PARM2-2] ; GET H1
|
|
MOV CX,[BX][%PARM3-2] ; GET L2
|
|
AND AX,CX
|
|
MOV CX,[BX][%PARM4-2] ; GET H2
|
|
AND DX,CX
|
|
RETSEG
|
|
END
|
|
;
|
|
; ---------------------------------------
|
|
; LONG BITWISE INCLUSIVE OR
|
|
; ---------------------------------------
|
|
;
|
|
IDT $_LBITOR
|
|
DEF $_LBITOR
|
|
$_LBITOR MOV BX,SP
|
|
MOV AX,[BX][%PARM1-2] ; GET L1
|
|
MOV DX,[BX][%PARM2-2] ; GET H1
|
|
MOV CX,[BX][%PARM3-2] ; GET L2
|
|
OR AX,CX
|
|
MOV CX,[BX][%PARM4-2]
|
|
OR DX,CX
|
|
RETSEG
|
|
END
|
|
;
|
|
; ---------------------------------------
|
|
; LONG BITWISE INVERT
|
|
; ---------------------------------------
|
|
;
|
|
IDT $_LBITNO
|
|
DEF $_LBITNO
|
|
$_LBITNO MOV BX,SP
|
|
MOV AX,[BX][%PARM1-2] ; GET OPERAND
|
|
MOV DX,[BX][%PARM2-2]
|
|
NOT AX
|
|
NOT DX
|
|
RETSEG
|
|
END
|
|
;
|
|
; ---------------------------------------
|
|
; LONG BITWISE EXCLUSIVE OR
|
|
; ---------------------------------------
|
|
;
|
|
IDT $_LXOR
|
|
DEF $_LXOR
|
|
$_LXOR MOV BX,SP
|
|
MOV AX,[BX][%PARM1-2] ; GET L1
|
|
MOV DX,[BX][%PARM2-2] ; GET H1
|
|
MOV CX,[BX][%PARM3-2] ; GET L2
|
|
XOR AX,CX
|
|
MOV CX,[BX][%PARM4-2]
|
|
XOR DX,CX
|
|
RETSEG
|
|
END
|
|
;
|
|
; ---------------------------------------
|
|
; LONG BITWISE IMPLIES (NOT A) OR B
|
|
; ---------------------------------------
|
|
;
|
|
IDT $_LIMPL
|
|
DEF $_LIMPL
|
|
$_LIMPL MOV BX,SP
|
|
MOV AX,[BX][%PARM1-2] ; GET L1
|
|
MOV DX,[BX][%PARM2-2] ; GET H1
|
|
MOV CX,[BX][%PARM3-2] ; GET L2
|
|
NOT AX
|
|
OR AX,CX
|
|
MOV CX,[BX][%PARM4-2]
|
|
NOT DX
|
|
OR DX,CX
|
|
RETSEG
|
|
END
|
|
;
|
|
; ---------------------------------------
|
|
; LONG SHIFT RIGHT WITH ZERO FILL
|
|
; TOP OF STACK WORD CONTAINS THE COUNT
|
|
; TOP OF STACK-2 IS THE VALUE
|
|
; ---------------------------------------
|
|
;
|
|
IDT $_LSHIFR
|
|
DEF $_LSHIFR
|
|
$_LSHIFR MOV BX,SP
|
|
MOV CX,[BX][%PARM1-2] ; GET SHIFT COUNT
|
|
CMP CX,32
|
|
JNA LSHFR01
|
|
MOV CX,32 ; LIMIT TO 32
|
|
LSHFR01 MOV AX,[BX][%PARM2-2]
|
|
MOV DX,[BX][%PARM3-2]
|
|
JCXZ LSHFR03
|
|
LSHFR02 SHR DX ; SHIFT
|
|
RCR AX
|
|
LOOP LSHFR02
|
|
LSHFR03 RETSEG
|
|
END
|
|
;
|
|
; ---------------------------------------
|
|
; LONG SHIFT LEFT WITH ZERO FILL
|
|
; TOP OF STACK WORD CONTAINS THE COUNT
|
|
; TOP OF STACK-2 IS THE VALUE
|
|
; ---------------------------------------
|
|
;
|
|
IDT $_LSHIFL
|
|
DEF $_LSHIFL
|
|
$_LSHIFL MOV BX,SP
|
|
MOV CX,[BX][%PARM1-2] ; GET SHIFT COUNT
|
|
CMP CX,32
|
|
JNA LSHFL01
|
|
MOV CX,32 ; LIMIT TO 32
|
|
LSHFL01 MOV AX,[BX][%PARM2-2]
|
|
MOV DX,[BX][%PARM3-2]
|
|
JCXZ LSHFL03
|
|
LSHFL02 SHL AX ; SHIFT
|
|
RCL DX
|
|
LOOP LSHFL02
|
|
LSHFL03 RETSEG
|
|
END
|
|
;
|
|
; ---------------------------------------
|
|
; LONG SHIFT RIGHT WITH SIGN PROPOGATE
|
|
; TOP OF STACK WORD CONTAINS THE COUNT
|
|
; TOP OF STACK-2 IS THE VALUE
|
|
; ---------------------------------------
|
|
;
|
|
IDT $_LASHIF
|
|
DEF $_LASHIF
|
|
$_LASHIF MOV BX,SP
|
|
MOV CX,[BX][%PARM1-2] ; GET SHIFT COUNT
|
|
CMP CX,32
|
|
JNA LASHF01
|
|
MOV CX,32 ; LIMIT TO 32
|
|
LASHF01 MOV AX,[BX][%PARM2-2]
|
|
MOV DX,[BX][%PARM3-2]
|
|
JCXZ LASHF03
|
|
LASHF02 SAR DX ; SHIFT
|
|
RCR AX
|
|
LOOP LASHF02
|
|
LASHF03 RETSEG
|
|
END
|