dos_compilers/Mix Power C v1/LONG.ASM
2024-07-01 15:26:34 -07:00

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