; general Real mode macros
; By Andrew Kohlsmith 11/6/94
; Some adapted from John McCarthy's 3DVECT stuff.
;------------------------------------------------------------------------------
comment *
As you can see, both this and my MCB follower were coded a fair time ago
(The April '95 date was the last mod date, the original MCB code is over two
years old) so if the coding is attrocious, I do appologise.  :-)

Oh, just noticed that the cmul code WON'T work in real mode...  this file was
originally my protected mode macros and I ported most of 'em over, but not
cmul...  Oh well, I'm sure someone can use it.  John McCarthy spent a lot of
time on it.  :-)
*

b       equ byte ptr
w       equ word ptr
d       equ dword ptr
o       equ offset
f       equ far ptr
s       equ short
?x4     equ <?,?,?,?>
?x3     equ <?,?,?>

pushw      macro ww  ; push word, used for pushing constants
           mov ax,ww
           push ax
           endm

; macro to out a 16 bit value to an i/o port
out_16     macro register, value
           ifdifi <register>, <dx> ; if dx not setup
           mov dx, register        ; then select register
           endif
           ifdifi <value>, <ax>    ; if ax not setup
           mov ax, value           ; then get data value
           endif
           out dx, ax              ; set i/o register(s)
endm

; macro to out a 8 bit value to an i/o port
out_8      macro register, value
           ifdifi <register>, <dx> ; if dx not setup
           mov dx, register        ; then select register
           endif
           ifdifi <value>, <al>    ; if al not setup
           mov al, value           ; then get data value
           endif
           out dx, al              ; set i/o register
endm

; macros to push and pop multiple registers
pushx      macro r1, r2, r3, r4, r5, r6, r7, r8
           ifnb <r1>
           push r1                 ; save r1
           pushx r2, r3, r4, r5, r6, r7, r8
           endif
endm

popx       macro r1, r2, r3, r4, r5, r6, r7, r8
           ifnb <r1>
           pop r1                  ; restore r1
           popx r2, r3, r4, r5, r6, r7, r8
           endif
endm

; macro to clear registers to 0
clr        macro register, r2, r3, r4, r5, r6
           ifnb <register>
           xor register, register  ; set register = 0
           clr r2, r3, r4, r5, r6
           endif
endm

; macros to decrement counter & jump on condition
loopx      macro register, destination
           dec register            ; counter--
           jnz destination         ; jump if not 0
endm

loopjz     macro register, destination
           dec register            ; counter--
           jz destination          ; jump if 0
endm

Beep Macro             ; just beeps... for debugging...
        mov ah, 2
        mov dl, 7
        int 21h
endm

;Assembler display Macros
;
;        PRINTS s    Sends string s to standard output.
;        PRINT8  n, b  Prints 8-bit register 'n' in base 'b'
;        PRINT16 n, b  Prints 16-bit register 'n' in base 'b'
;        PRINT32 n, b  Prints 32-bit register 'n' in base 'b'
;
;Submacros
;        PRINTX       Prints the digit
;-------------------------------------------------------------------------

;-------------------------------------------------------------------------
puts        macro s           ; prints string 's' at current position
        local ps_1, str        ; eg. prints "Hello world!"
        jmp ps_1

str        db s             ; string is placed here...
        db '$'

ps_1:
        push ax             ; save what we alter
        push dx
        push ds

        push cs
        pop ds
        mov ah, 9
        mov dx, offset str
        int 21h

        pop ds
        pop dx
        pop ax
        endm

;-------------------------------------------------------------------------
print8 macro reg, base              ; Prints 8-bit 'reg' in base 'base'
        local print8_1, print8_2, print8_3

        push ax             ; save some important regs
        push cx
        push dx

        mov al, reg         ; value to print in AL
        xor ah, ah          ; zero out hi word of AX
        mov cx, base        ; base (divisor) in CX

        call print8_1         ; start the recursion
        jmp print8_3        ; jmp to end

print8_1:
        xor dx, dx          ; clear dividend
        div cx         ; divide out to find digit
        push dx             ; save it
        cmp ax, 0           ; are we done yet?
        je print8_2         ; jmp if so
        call print8_1         ; otherwise call ourselves again

print8_2:
        printx         ; print whatever's in DL and RETurn

print8_3:
        pop dx         ; restore what we saved
        pop cx
        pop ax
        endm

;-------------------------------------------------------------------------
print16 macro reg, base             ; Prints 16-bit 'reg' in base 'base'
        local print16_1, print16_2, print16_3

        push ax             ; save some important regs
        push cx
        push dx

        mov ax, reg         ; value to print in AX
        mov cx, base        ; base (divisor) in CX

        call print16_1        ; start the recursion
        jmp print16_3         ; jmp to end

print16_1:
        xor dx, dx          ; clear dividend
        div cx         ; divide out to find digit
        push dx             ; save it
        cmp ax, 0           ; are we done yet?
        je print16_2        ; jmp if so
        call print16_1        ; otherwise call ourselves again

print16_2:
        printx         ; print whatever's in DL and RETurn

print16_3:
        pop dx         ; restore what we saved
        pop cx
        pop ax
        endm

;-------------------------------------------------------------------------
print32 macro reg, base             ; Prints 32-bit 'reg' in base 'base'
        local print32_1, print32_2, print32_3

        push eax       ; save some important regs
        push ecx
        push edx

        mov eax, reg        ; value to print in EAX
        xor ecx, ecx        ; make sure hi word of ECX is 0
        mov ecx, base         ; base (divisor) in CX

        call print32_1        ; start the recursion
        jmp print32_3         ; jmp to end

print32_1:
        xor edx, edx        ; clear dividend
        div ecx             ; divide out to find digit
        push dx             ; save it
        cmp eax, 0          ; are we done yet?
        je print32_2        ; jmp if so
        call print32_1        ; otherwise call ourselves again

print32_2:
        printx         ; print whatever's in DL and RETurn

print32_3:
        pop edx             ; restore what we saved
        pop ecx
        pop eax
        endm

;-------------------------------------------------------------------------
printx macro
        local printx_1
        pop dx         ; get the last dividend
        add dl, 30h         ; convert to number 0-9
        cmp dl, 39h         ; is it 9?
        jle printx_1        ; jmp if greater
        add dl, 7           ; covert to character A-F

printx_1:
        mov ah, 2
        int 21h
        ret           ; undo recursion
        endm

;--- Printh8/16, printd8/16 ---------------------------------------------------
; Prints in hex/decimal 8/16 bit registers, zero-padding

printh8 macro reg
local printh8_1, printh8_2

        push ax
        push bx
        push cx

        mov bl, reg
        mov ch, 2             ; # of digits
printh8_1:
        mov cl, 4
        rol bl, cl
        mov al, bl            ; move to AL
        and al, 0fh           ; mask off left digit
        add al, 30h           ; convert to ASCII
        cmp al, 3ah           ; is it > "9"?
        jl printh8_2          ; jmp if not
        add al, 7             ; convert to a-f
printh8_2:
        mov ah, 2
        mov dl, al
        int 21h               ; DOS - print char
        dec ch              ; one less digit
        jnz printh8_1

        pop cx
        pop bx
        pop ax
endm

printh16 macro reg, colour
local printh16_1, printh16_2

        push ax
        push bx
        push cx

        mov bx, reg
        mov ch, 4             ; # of digits
printh16_1:
        mov cl, 4             ; set count to # of digits
        rol bx, cl            ; left digit to right
        mov al, bl            ; move to AL
        and al, 0fh           ; mask off left digit
        add al, 30h           ; convert to ASCII
        cmp al, 3ah           ; is it > "9"?
        jl printh16_2          ; jmp if not
        add al, 7             ; convert to a-f
printh16_2:
        mov ah, 2
        mov dl, al
        int 21h               ; DOS - print char
        dec ch              ; one less digit
        jnz printh16_1

        pop cx
        pop bx
        pop ax
endm

;============================================================================== 
; macro to multiply by a constant - this can be done because of protected
; mode's lea function.
;
; use: cmul eax,ecx,12   eax=ecx*12
; as opposed to using imul

cmul       macro result,value,constant  ; constant multiply, use fast lea

           if constant eq 7
           lea result,[value*4+value]   ; 7 = %0111
           shl value,1
           add result,value
           cdq

           elseif constant eq 8
           lea result,[value*8]         ; 8 = %1000
           cdq

           elseif constant eq 9
           lea result,[value*8+value]   ; 9 = %1001
           cdq

           elseif constant eq 10
           shl value,1
           lea result,[value*4+value]   ; 10 = %1010
           cdq

           elseif constant eq 11
           lea result,[value*2+value]   ; 11 = %1011
           shl value,3
           add result,value
           cdq

           elseif constant eq 12
           lea result,[value*2+value]   ; 12 = %1100
           shl result,2
           cdq

           elseif constant eq 13
           lea result,[value*2+value]   ; 13 = %1101
           shl result,2
           add result,value
           cdq

           elseif constant eq 14
           shl value,1
           lea result,[value*4+value]   ; 14 = %1110
           shl value,1
           add result,value
           cdq

           elseif constant eq 15
           lea result,[value*4+value]   ; 15 = %1111
           shl value,1
           lea value,[value*4+value]
           add result,value
           cdq

           elseif constant eq 240
           shl value,4
           lea result,[value*4+value]   ; 240 = %0 1111 0000
           shl value,1
           lea value,[value*4+value]
           add result,value
           cdq

           elseif constant eq 260
           lea result,[value*4]         ; 260 = %1 0000 0100
           shl value,8
           add result,value
           cdq

           elseif constant eq 280
           shl value,3
           lea result,[value*2+value]   ; 240 = %1 0001 1000
           shl value,5
           add result,value
           cdq

           elseif constant eq 300
           shl value,2
           lea result,[value*2+value]   ; 300 = %1 0010 1100
           shl value,3
           lea value,[value*8+value]
           add result,value
           cdq

           elseif constant eq 320
           lea result,[value*4+value]   ; 320 = %1 0100 0000
           shl result,6
           cdq

           elseif constant eq 360
           shl value,3
           lea result,[value*4+value]   ; 360 = %1 0110 1000
           shl value,3
           lea value,[value*4+value]
           add result,value
           cdq

           elseif constant eq 416
           shl value,5
           lea result,[value*4+value]   ; 416 = %1 1010 0000
           shl value,3
           add result,value
           cdq

           elseif constant eq 448
           lea result,[value*8]         ; 464 = %1 1100 0000
           shl value,2
           lea value,[value*4+value]
           add result,value
           shl result,4
           cdq

           elseif constant eq 464
           lea result,[value*8+value]   ; 464 = %1 1101 0000
           shl value,2
           lea value,[value*4+value]
           add result,value
           shl result,4
           cdq

           elseif constant eq 480
           shl value,5
           lea result,[value*4+value]   ; 480 = %1 1110 0000
           shl value,1
           lea value,[value*4+value]
           add result,value
           cdq

           else
           mov result,constant
           imul value
           display "Note: Slow multiplication used in constant multiply"
           display "      See cmul macro in file macros.inc"
           endif
endm

;[end]


