masm v5
This commit is contained in:
parent
f06c9bf995
commit
e626a58278
BIN
Microsoft MASM v5/MASM50-POCKETREF.pdf
Normal file
BIN
Microsoft MASM v5/MASM50-POCKETREF.pdf
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/MASM50-PROGGUIDE.pdf
Normal file
BIN
Microsoft MASM v5/MASM50-PROGGUIDE.pdf
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/bin/CREF.EXE
Normal file
BIN
Microsoft MASM v5/bin/CREF.EXE
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/bin/CV.EXE
Normal file
BIN
Microsoft MASM v5/bin/CV.EXE
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/bin/CV.HLP
Normal file
BIN
Microsoft MASM v5/bin/CV.HLP
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/bin/ERROUT.EXE
Normal file
BIN
Microsoft MASM v5/bin/ERROUT.EXE
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/bin/EXEMOD.EXE
Normal file
BIN
Microsoft MASM v5/bin/EXEMOD.EXE
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/bin/EXEPACK.EXE
Normal file
BIN
Microsoft MASM v5/bin/EXEPACK.EXE
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/bin/LIB.EXE
Normal file
BIN
Microsoft MASM v5/bin/LIB.EXE
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/bin/LINK.EXE
Normal file
BIN
Microsoft MASM v5/bin/LINK.EXE
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/bin/MAKE.EXE
Normal file
BIN
Microsoft MASM v5/bin/MAKE.EXE
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/bin/MASM.EXE
Normal file
BIN
Microsoft MASM v5/bin/MASM.EXE
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/bin/SETENV.EXE
Normal file
BIN
Microsoft MASM v5/bin/SETENV.EXE
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/bin/SHOW.EXE
Normal file
BIN
Microsoft MASM v5/bin/SHOW.EXE
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/bin/WHAT.EXE
Normal file
BIN
Microsoft MASM v5/bin/WHAT.EXE
Normal file
Binary file not shown.
247
Microsoft MASM v5/e.asm
Normal file
247
Microsoft MASM v5/e.asm
Normal file
@ -0,0 +1,247 @@
|
||||
; 8086 assembly to compute e to n digits.
|
||||
; When DIGITS is 200, the first 192 digits are displayed:
|
||||
; 271828182845904523536028747135266249775724709369995957496696762772407663035354759457138217852516642742746639193200305992181741359662904357290033429526059563073813232862794349076323382988075319
|
||||
;
|
||||
; equivalent to:
|
||||
; program e;
|
||||
; const
|
||||
; DIGITS = 200;
|
||||
; type
|
||||
; arrayType = array[ 0..DIGITS ] of integer;
|
||||
; var
|
||||
; high, n, x : integer;
|
||||
; a : arrayType;
|
||||
; begin
|
||||
; high := DIGITS;
|
||||
; x := 0;
|
||||
; n := high - 1;
|
||||
; while n > 0 do begin
|
||||
; a[ n ] := 1;
|
||||
; n := n - 1;
|
||||
; end;
|
||||
;
|
||||
; a[ 1 ] := 2;
|
||||
; a[ 0 ] := 0;
|
||||
;
|
||||
; while high > 9 do begin
|
||||
; high := high - 1;
|
||||
; n := high;
|
||||
; while 0 <> n do begin
|
||||
; a[ n ] := x MOD n;
|
||||
; x := 10 * a[ n - 1 ] + x DIV n;
|
||||
; n := n - 1;
|
||||
; end;
|
||||
;
|
||||
; Write( x );
|
||||
; end;
|
||||
;
|
||||
; writeln; writeln( 'done' );
|
||||
; end.
|
||||
|
||||
; build with masm 5.0 like this:
|
||||
; ntvdm -h masm /Zi /Zd /z /l %1,,,;
|
||||
; ntvdm -h link %1,,%1,,nul.def
|
||||
;
|
||||
|
||||
dosseg
|
||||
.model small
|
||||
.stack 100h
|
||||
|
||||
; DOS constants
|
||||
|
||||
dos_write_char equ 2h
|
||||
dos_realtime_clock equ 1ah
|
||||
dos_exit equ 4ch
|
||||
|
||||
; app constants
|
||||
|
||||
true equ 1
|
||||
false equ 0
|
||||
digits equ 200
|
||||
|
||||
dataseg segment para public 'data'
|
||||
assume ds: dataseg
|
||||
|
||||
crlfmsg db 13,10,0
|
||||
donemsg db 'done',13,10,0
|
||||
|
||||
align 16
|
||||
array db digits dup( ? )
|
||||
dataseg ends
|
||||
|
||||
.code
|
||||
|
||||
start:
|
||||
mov ax, dataseg
|
||||
mov ds, ax
|
||||
|
||||
; why is the loop backwards? no idea.
|
||||
; while n > 0 do begin
|
||||
; a[ n ] := 1;
|
||||
; n := n - 1;
|
||||
; end;
|
||||
|
||||
; register bh is n. di is a[]. bl is a constant 1
|
||||
|
||||
mov bl, 1
|
||||
mov bh, digits - 1
|
||||
mov di, offset array + digits - 1
|
||||
|
||||
ainit:
|
||||
mov byte ptr [ di ], bl
|
||||
dec di
|
||||
dec bh
|
||||
jnz ainit
|
||||
|
||||
; a[ 1 ] := 2;
|
||||
; a[ 0 ] := 0;
|
||||
|
||||
mov di, offset array
|
||||
mov byte ptr[ di + 1 ], 2
|
||||
mov byte ptr[ di ], 0
|
||||
|
||||
; register bx is n. register si is high. register di is x at the start of each inner loop
|
||||
|
||||
mov si, DIGITS
|
||||
|
||||
outerloop:
|
||||
dec si ; high := high - 1;
|
||||
mov bx, si ; n := high;
|
||||
xor di, di ; x := 0;
|
||||
|
||||
innerloop:
|
||||
xor dx, dx
|
||||
mov ax, di
|
||||
div bx ; computes both x MOD n and x DIV n. dx has remainder, ax has result
|
||||
mov di, ax ; save the result of the division in di. ah is guaranteed to be 0.
|
||||
|
||||
mov byte ptr[ offset array + bx ], dl ; a[ n ] := x MOD n;
|
||||
|
||||
mov al, byte ptr [ offset array + bx - 1 ] ; load a[ n - 1 ] into al
|
||||
mov cx, 10
|
||||
mul cx
|
||||
add di, ax ; x := 10 * a[ n - 1 ] + x DIV n;
|
||||
|
||||
dec bx ; n := n - 1;
|
||||
jnz innerloop ; if n isn't 0 then loop again
|
||||
|
||||
mov ax, di
|
||||
call printint ; show the next digit(s) of e
|
||||
|
||||
cmp si, 9 ; while high > 9 do begin (re-written as a do until loop)
|
||||
jnz outerloop
|
||||
|
||||
call printcrlf
|
||||
mov dx, offset donemsg
|
||||
call printstring
|
||||
|
||||
mov al, 0
|
||||
mov ah, dos_exit
|
||||
int 21h
|
||||
;start endp
|
||||
|
||||
; print the integer in ax
|
||||
|
||||
printint proc near
|
||||
test ah, 80h
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push di
|
||||
push si
|
||||
|
||||
jz _prpositive
|
||||
neg ax ; just one instruction for complement + 1
|
||||
push ax
|
||||
mov dx, '-'
|
||||
mov ah, dos_write_char
|
||||
int 21h
|
||||
pop ax
|
||||
_prpositive:
|
||||
xor cx, cx
|
||||
xor dx, dx
|
||||
cmp ax, 0
|
||||
je _przero
|
||||
_prlabel1:
|
||||
cmp ax, 0
|
||||
je _prprint1
|
||||
mov bx, 10
|
||||
div bx
|
||||
push dx
|
||||
inc cx
|
||||
xor dx, dx
|
||||
jmp _prlabel1
|
||||
_prprint1:
|
||||
cmp cx, 0
|
||||
je _prexit
|
||||
pop dx
|
||||
add dx, 48
|
||||
mov ah, dos_write_char
|
||||
int 21h
|
||||
dec cx
|
||||
jmp _prprint1
|
||||
_przero:
|
||||
mov dx, '0'
|
||||
mov ah, dos_write_char
|
||||
int 21h
|
||||
_prexit:
|
||||
pop si
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
printint endp
|
||||
|
||||
printcrlf proc near
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push di
|
||||
push si
|
||||
mov dx, offset crlfmsg
|
||||
call printstring
|
||||
pop si
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
printcrlf endp
|
||||
|
||||
printstring proc near
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push di
|
||||
push si
|
||||
|
||||
mov di, dx
|
||||
|
||||
_psnext:
|
||||
mov al, byte ptr [ di ]
|
||||
cmp al, 0
|
||||
je _psdone
|
||||
mov dx, ax
|
||||
mov ah, dos_write_char
|
||||
int 21h
|
||||
|
||||
inc di
|
||||
jmp _psnext
|
||||
|
||||
_psdone:
|
||||
pop si
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
printstring endp
|
||||
|
||||
end
|
166
Microsoft MASM v5/inc/BIOS.INC
Normal file
166
Microsoft MASM v5/inc/BIOS.INC
Normal file
@ -0,0 +1,166 @@
|
||||
; BIOS Interface Macros - Version 1.0 - for Microsoft Macro Assembler 5.0
|
||||
; (C) Copyright Microsoft Corporation, 1987.
|
||||
|
||||
.XCREF
|
||||
.XLIST
|
||||
IF1
|
||||
; 0Fh
|
||||
@GetMode MACRO
|
||||
mov ah,0Fh
|
||||
int 10h
|
||||
ENDM
|
||||
; 00h
|
||||
@SetMode MACRO mode
|
||||
mov al,mode
|
||||
xor ah,ah
|
||||
int 10h
|
||||
ENDM
|
||||
; 0Bh
|
||||
@SetColor MACRO color
|
||||
sub bh,bh
|
||||
mov bl,color
|
||||
mov ah,0Bh
|
||||
int 10h
|
||||
ENDM
|
||||
; 0Bh
|
||||
@SetPalet MACRO color
|
||||
mov bh,1
|
||||
mov bl,color
|
||||
mov ah,0Bh
|
||||
int 10h
|
||||
ENDM
|
||||
; 05h
|
||||
@SetPage MACRO page
|
||||
mov al,page
|
||||
mov ah,05h
|
||||
int 10h
|
||||
ENDM
|
||||
; 03h
|
||||
@GetCur MACRO page
|
||||
IFNB <page>
|
||||
mov bh,page
|
||||
ELSE
|
||||
xor bh,bh
|
||||
ENDIF
|
||||
mov ah,03h
|
||||
int 10h
|
||||
ENDM
|
||||
; 02h
|
||||
@SetCurPos MACRO column,row,page
|
||||
IFNB <column>
|
||||
mov dl,column
|
||||
ENDIF
|
||||
IFNB <row>
|
||||
mov dh,row
|
||||
ENDIF
|
||||
IFNB <page>
|
||||
mov bh,page
|
||||
ELSE
|
||||
xor bh,bh
|
||||
ENDIF
|
||||
mov ah,02h
|
||||
int 10h
|
||||
ENDM
|
||||
; 01h
|
||||
@SetCurSz MACRO first,last
|
||||
mov ch,first
|
||||
mov cl,last
|
||||
mov ah,01h
|
||||
int 10h
|
||||
ENDM
|
||||
; 08h
|
||||
@GetChAtr MACRO page
|
||||
IFNB <page>
|
||||
mov bh,page
|
||||
ELSE
|
||||
sub bh,bh
|
||||
ENDIF
|
||||
mov ah,08h
|
||||
int 10h
|
||||
ENDM
|
||||
; 09h
|
||||
@PutChAtr MACRO char,atrib,page,repeat
|
||||
IFNB <char>
|
||||
mov al,char
|
||||
ENDIF
|
||||
IFNB <atrib>
|
||||
mov bl,atrib
|
||||
ENDIF
|
||||
IFNB <page>
|
||||
mov bh,page
|
||||
ELSE
|
||||
xor bh,bh
|
||||
ENDIF
|
||||
IFNB <repeat>
|
||||
mov cx,repeat
|
||||
ELSE
|
||||
mov cx,1
|
||||
ENDIF
|
||||
mov ah,09h
|
||||
int 10h
|
||||
ENDM
|
||||
; 0Ah
|
||||
@PutCh MACRO char,atrib,page,repeat
|
||||
IFNB <char>
|
||||
mov al,char
|
||||
ENDIF
|
||||
IFNB <atrib>
|
||||
mov bl,atrib
|
||||
ENDIF
|
||||
IFNB <page>
|
||||
mov bh,page
|
||||
ELSE
|
||||
xor bh,bh
|
||||
ENDIF
|
||||
IFNB <repeat>
|
||||
mov cx,repeat
|
||||
ELSE
|
||||
mov cx,1
|
||||
ENDIF
|
||||
mov ah,0Ah
|
||||
int 10h
|
||||
ENDM
|
||||
; 06h and 07h
|
||||
@Scroll MACRO distance,atrib,upcol,uprow,downcol,downrow
|
||||
IFDEF upcol
|
||||
mov cl,upcol
|
||||
ENDIF
|
||||
IFDEF uprow
|
||||
mov ch,uprow
|
||||
ENDIF
|
||||
IFDEF upcol
|
||||
mov dl,upcol
|
||||
ENDIF
|
||||
IFDEF updownrow
|
||||
mov dh,downrow
|
||||
ENDIF
|
||||
IFDEF atrib
|
||||
mov bh,atrib
|
||||
ELSE
|
||||
mov bh,07h
|
||||
ENDIF
|
||||
IF distance LE 0
|
||||
mov ax,0600h + (-(distance) AND 0FFh)
|
||||
ELSE
|
||||
mov ax,0700h + (distance AND 0FFh)
|
||||
ENDIF
|
||||
int 10h
|
||||
ENDM
|
||||
; 08h, 06h, and 02h
|
||||
@Cls MACRO
|
||||
@GetChAtr
|
||||
mov bl,bh
|
||||
mov bh,ah
|
||||
sub cx,cx
|
||||
mov dx,184Fh
|
||||
mov ax,0600h
|
||||
int 10h
|
||||
mov bh,bl
|
||||
sub dx,dx
|
||||
mov ah,02h
|
||||
int 10h
|
||||
ENDM
|
||||
ENDIF
|
||||
.CREF
|
||||
.LIST
|
||||
|
480
Microsoft MASM v5/inc/DOS.INC
Normal file
480
Microsoft MASM v5/inc/DOS.INC
Normal file
@ -0,0 +1,480 @@
|
||||
; DOS Interface Macros - Version 1.0 - for Microsoft Macro Assembler 5.0
|
||||
; (C) Copyright Microsoft Corporation, 1987.
|
||||
|
||||
.XCREF
|
||||
.XLIST
|
||||
IF1
|
||||
; Internal
|
||||
__LdAdr MACRO reg,adr
|
||||
IFE TYPE (adr)
|
||||
mov reg,adr
|
||||
ELSE
|
||||
IF TYPE (adr) EQ 1
|
||||
mov reg,OFFSET adr
|
||||
ELSE
|
||||
IF TYPE (adr) EQ 2
|
||||
mov reg,adr
|
||||
ELSE
|
||||
IF TYPE (adr) EQ 4
|
||||
lds reg,adr
|
||||
ELSE
|
||||
.ERR
|
||||
%OUT Illegal argument
|
||||
ENDIF
|
||||
ENDIF
|
||||
ENDIF
|
||||
ENDIF
|
||||
ENDM
|
||||
; Internal
|
||||
__LdSeg MACRO dest,src
|
||||
IFE TYPE (src)
|
||||
mov ax,src
|
||||
mov dest,ax
|
||||
ELSE
|
||||
mov dest,src
|
||||
ENDIF
|
||||
ENDM
|
||||
; 01h, 07h, 08h, 0Ch
|
||||
@GetKey MACRO echo,cc,clear
|
||||
LOCAL funct,disp
|
||||
IFDIF <echo>,<0>
|
||||
IFDIF <cc>,<0>
|
||||
funct = 01h
|
||||
ELSE
|
||||
funct = 07h
|
||||
disp = 02h
|
||||
ENDIF
|
||||
ELSE
|
||||
IFDIF <cc>,<0>
|
||||
funct = 08h
|
||||
ELSE
|
||||
funct = 07h
|
||||
ENDIF
|
||||
ENDIF
|
||||
IFB <clear>
|
||||
mov ah,funct
|
||||
ELSE
|
||||
IFIDN <clear>,<0>
|
||||
mov ah,funct
|
||||
ELSE
|
||||
mov ah,0Ch
|
||||
mov al,funct
|
||||
ENDIF
|
||||
ENDIF
|
||||
int 21h
|
||||
IFDEF disp
|
||||
mov dl,al
|
||||
mov ah,disp
|
||||
int 21h
|
||||
ENDIF
|
||||
ENDM
|
||||
; 0Ah
|
||||
@GetStr MACRO ofset,terminator,limit,segmnt
|
||||
__LdAdr dx,<ofset>
|
||||
IFNB <segmnt>
|
||||
__LdSeg ds,<segmnt>
|
||||
ENDIF
|
||||
mov ah,0Ah
|
||||
mov si,dx
|
||||
IFNB <limit>
|
||||
mov BYTE PTR [si],limit
|
||||
ENDIF
|
||||
int 21h
|
||||
inc si
|
||||
mov bl,[si]
|
||||
sub bh,bh
|
||||
inc si
|
||||
IFNB <terminator>
|
||||
mov BYTE PTR [bx+si],terminator
|
||||
ENDIF
|
||||
ENDM
|
||||
; 02h
|
||||
@DispCh MACRO ch1,ch2,ch3,ch4,ch5,ch6,ch7,ch8,ch9,ch10
|
||||
mov ah,02h
|
||||
IRP char,<ch1,ch2,ch3,ch4,ch5,ch6,ch7,ch8,ch9,ch10>
|
||||
IFB <char>
|
||||
EXITM
|
||||
ENDIF
|
||||
mov dl,char
|
||||
int 21h
|
||||
ENDM
|
||||
ENDM
|
||||
; 05h
|
||||
@PrtCh MACRO ch1,ch2,ch3,ch4,ch5,ch6,ch7,ch8,ch9,ch10
|
||||
mov ah,05h
|
||||
IRP char,<ch1,ch2,ch3,ch4,ch5,ch6,ch7,ch8,ch9,ch10>
|
||||
IFB <char>
|
||||
EXITM
|
||||
ENDIF
|
||||
mov dl,char
|
||||
int 21h
|
||||
ENDM
|
||||
ENDM
|
||||
; 09h
|
||||
@DispStr MACRO ofset,segmnt
|
||||
__LdAdr dx,<ofset>
|
||||
IFNB <segmnt>
|
||||
__LdSeg ds,<segmnt>
|
||||
ENDIF
|
||||
mov ah,9
|
||||
int 21h
|
||||
ENDM
|
||||
; 3Fh
|
||||
@Read MACRO ofset,bytes,handle,segmnt
|
||||
IFNB <handle>
|
||||
mov bx,handle
|
||||
ELSE
|
||||
sub bx,bx
|
||||
ENDIF
|
||||
mov cx,bytes
|
||||
__LdAdr dx,<ofset>
|
||||
IFNB <segmnt>
|
||||
__LdSeg ds,<segmnt>
|
||||
ENDIF
|
||||
mov ah,3Fh
|
||||
int 21h
|
||||
ENDM
|
||||
; 40h
|
||||
@Write MACRO ofset,bytes,handle,segmnt
|
||||
IFNB <handle>
|
||||
mov bx,handle
|
||||
ELSE
|
||||
mov bx,1
|
||||
ENDIF
|
||||
mov cx,bytes
|
||||
__LdAdr dx,<ofset>
|
||||
IFNB <segmnt>
|
||||
__LdSeg ds,<segmnt>
|
||||
ENDIF
|
||||
mov ah,40h
|
||||
int 21h
|
||||
ENDM
|
||||
; 3Ch
|
||||
@MakFil MACRO path,atrib,segmnt,kind
|
||||
IFB <atrib>
|
||||
sub cx,cx
|
||||
ELSE
|
||||
mov cx,atrib
|
||||
ENDIF
|
||||
__LdAdr dx,<path>
|
||||
IFNB <segmnt>
|
||||
__LdSeg ds,<segmnt>
|
||||
ENDIF
|
||||
IFIDNI <kind>,<tmp>
|
||||
mov ah,5Ah
|
||||
ELSE
|
||||
IFIDNI <kind>,<new>
|
||||
mov ah,5Bh
|
||||
ELSE
|
||||
mov ah,3Ch
|
||||
ENDIF
|
||||
ENDIF
|
||||
int 21h
|
||||
ENDM
|
||||
; 3Dh
|
||||
@OpenFil MACRO path,access,segmnt
|
||||
__LdAdr dx,<path>
|
||||
IFNB <segmnt>
|
||||
__LdSeg ds,<segmnt>
|
||||
ENDIF
|
||||
mov ax,3D00h + (access AND 0FFh)
|
||||
int 21h
|
||||
ENDM
|
||||
; 3Eh
|
||||
@ClosFil MACRO handle
|
||||
mov bx,handle
|
||||
mov ah,3Eh
|
||||
int 21h
|
||||
ENDM
|
||||
; 41h
|
||||
@DelFil MACRO path,segmnt
|
||||
__LdAdr dx,<path>
|
||||
IFNB <segmnt>
|
||||
__LdSeg ds,<segmnt>
|
||||
ENDIF
|
||||
mov ah,41h
|
||||
int 21h
|
||||
ENDM
|
||||
; 56h
|
||||
@MoveFil MACRO old,new,segold,segnew
|
||||
__LdAdr dx,<old>
|
||||
__LdAdr di,<new>
|
||||
IFNB <segold>
|
||||
__LdSeg ds,<segold>
|
||||
ENDIF
|
||||
IFNB <segnew>
|
||||
__LdSeg es,<segnew>
|
||||
ENDIF
|
||||
mov ah,56h
|
||||
int 21h
|
||||
ENDM
|
||||
; 4Eh
|
||||
@GetFirst MACRO path,atrib,segmnt
|
||||
IFNB <atrib>
|
||||
mov cx,atrib
|
||||
ELSE
|
||||
sub cx,cx
|
||||
ENDIF
|
||||
__LdAdr dx,<path>
|
||||
IFNB <segmnt>
|
||||
__LdSeg ds,<segmnt>
|
||||
ENDIF
|
||||
mov ah,4Eh
|
||||
int 21h
|
||||
ENDM
|
||||
; 4Fh
|
||||
@GetNext MACRO
|
||||
mov ah,4Fh
|
||||
int 21h
|
||||
ENDM
|
||||
; 2Fh
|
||||
@GetDTA MACRO
|
||||
mov ah,2Fh
|
||||
int 21h
|
||||
ENDM
|
||||
; 1Ah
|
||||
@SetDTA MACRO buffer,segmnt
|
||||
__LdAdr dx,<buffer>
|
||||
IFNB <segmnt>
|
||||
__LdSeg ds,<segmnt>
|
||||
ENDIF
|
||||
mov ah,1Ah
|
||||
int 21h
|
||||
ENDM
|
||||
; Internal
|
||||
__LdDub MACRO dub
|
||||
IF TYPE (dub) EQ 2
|
||||
sub cx,cx
|
||||
mov dx,dub
|
||||
ELSE
|
||||
IF TYPE (dub) EQ 4
|
||||
mov cx,dub[2]
|
||||
mov dx,dub[0]
|
||||
ELSE
|
||||
IF TYPE (dub) EQ 0
|
||||
sub cx,cx
|
||||
mov dx,dub
|
||||
ELSE
|
||||
.ERR
|
||||
%OUT Illegal argument
|
||||
ENDIF
|
||||
ENDIF
|
||||
ENDIF
|
||||
ENDM
|
||||
; 42h
|
||||
@GetFilSz MACRO handle
|
||||
mov bx,handle
|
||||
sub cx,cx
|
||||
sub dx,dx
|
||||
mov ax,4202h
|
||||
int 21h
|
||||
push dx
|
||||
push ax
|
||||
sub dx,dx
|
||||
mov ax,4200h
|
||||
int 21h
|
||||
pop ax
|
||||
pop dx
|
||||
ENDM
|
||||
; 42h
|
||||
@MovePtrAbs MACRO handle,distance
|
||||
IFNB <distance>
|
||||
__LdDub <distance>
|
||||
ENDIF
|
||||
mov bx,handle
|
||||
mov ax,4200h
|
||||
int 21h
|
||||
ENDM
|
||||
; 42h
|
||||
@MovePtrRel MACRO handle,distance
|
||||
IFNB <distance>
|
||||
__LdDub <distance>
|
||||
ENDIF
|
||||
mov bx,handle
|
||||
mov ax,4201h
|
||||
int 21h
|
||||
ENDM
|
||||
; 39h
|
||||
@MkDir MACRO path,segmnt
|
||||
__LdAdr dx,<path>
|
||||
IFNB <segmnt>
|
||||
__LdSeg ds,<segmnt>
|
||||
ENDIF
|
||||
mov ah,39h
|
||||
int 21h
|
||||
ENDM
|
||||
; 3Ah
|
||||
@RmDir MACRO path,segmnt
|
||||
__LdAdr dx,<path>
|
||||
IFNB <segmnt>
|
||||
__LdSeg ds,<segmnt>
|
||||
ENDIF
|
||||
mov ah,3Ah
|
||||
int 21h
|
||||
ENDM
|
||||
; 3Bh
|
||||
@ChDir MACRO path,segmnt
|
||||
__LdAdr dx,<path>
|
||||
IFNB <segmnt>
|
||||
__LdSeg ds,<segmnt>
|
||||
ENDIF
|
||||
mov ah,3Bh
|
||||
int 21h
|
||||
ENDM
|
||||
; 47h
|
||||
@GetDir MACRO buffer,drive,segmnt
|
||||
IFNB <drive>
|
||||
mov dl,drive
|
||||
ELSE
|
||||
sub dl,dl
|
||||
ENDIF
|
||||
__LdAdr si,<buffer>
|
||||
IFNB <segmnt>
|
||||
__LdSeg ds,<segmnt>
|
||||
ENDIF
|
||||
mov ah,47h
|
||||
int 21h
|
||||
ENDM
|
||||
; 19h
|
||||
@GetDrv MACRO
|
||||
mov ah,19h
|
||||
int 21h
|
||||
ENDM
|
||||
; 0Eh
|
||||
@SetDrv MACRO drive
|
||||
mov dl,drive
|
||||
mov ah,0Eh
|
||||
int 21h
|
||||
ENDM
|
||||
; 36h
|
||||
@ChkDrv MACRO drive
|
||||
IFNB <drive>
|
||||
mov dl,drive
|
||||
ELSE
|
||||
sub dl,dl
|
||||
ENDIF
|
||||
mov ah,36h
|
||||
int 21h
|
||||
ENDM
|
||||
; 4Ch
|
||||
@Exit MACRO return
|
||||
IFB <return>
|
||||
mov ah,4Ch
|
||||
ELSE
|
||||
mov ax,4C00h + (return AND 0FFh)
|
||||
ENDIF
|
||||
int 21h
|
||||
ENDM
|
||||
; 4Bh
|
||||
@Exec MACRO path,parms,segpath,segparms,overlay
|
||||
__LdAdr dx,<path>
|
||||
__LdAdr bx,<parms>
|
||||
IFNB <segpath>
|
||||
__LdSeg ds,<segpath>
|
||||
ENDIF
|
||||
IFNB <segparms>
|
||||
__LdSeg es,<segparms>
|
||||
ENDIF
|
||||
IFB <overlay>
|
||||
mov ax,4B00h
|
||||
ELSE
|
||||
mov ax,4B03h
|
||||
ENDIF
|
||||
int 21h
|
||||
ENDM
|
||||
; 4Dh
|
||||
@GetRet MACRO
|
||||
mov ah,4Dh
|
||||
int 21h
|
||||
ENDM
|
||||
; 31h
|
||||
@TSR MACRO paragraphs,return
|
||||
mov dx,paragraphs
|
||||
IFB <return>
|
||||
mov ah,31h
|
||||
ELSE
|
||||
mov ax,3100h + (return AND 0FFh)
|
||||
ENDIF
|
||||
int 21h
|
||||
ENDM
|
||||
; 49h
|
||||
@FreeBlok MACRO segmnt
|
||||
IFNB <segmnt>
|
||||
__LdSeg es,<segmnt>
|
||||
ENDIF
|
||||
mov ah,49h
|
||||
int 21h
|
||||
ENDM
|
||||
; 48h
|
||||
@GetBlok MACRO graphs
|
||||
LOCAL tryit
|
||||
mov bx,graphs
|
||||
tryit: mov ah,48h
|
||||
int 21h
|
||||
jc tryit
|
||||
ENDM
|
||||
; 4Ah
|
||||
@ModBlok MACRO graphs,segmnt
|
||||
IFNB <segmnt>
|
||||
__LdSeg es,<segmnt>
|
||||
ENDIF
|
||||
mov bx,graphs
|
||||
mov ah,4Ah
|
||||
int 21h
|
||||
ENDM
|
||||
; 2Ah
|
||||
@GetDate MACRO
|
||||
mov ah,2Ah
|
||||
int 21h
|
||||
ENDM
|
||||
; 2Bh
|
||||
@SetDate MACRO month,day,year
|
||||
mov cx,year
|
||||
mov dh,month
|
||||
mov dl,day
|
||||
mov ah,2Bh
|
||||
int 21h
|
||||
ENDM
|
||||
; 2Ch
|
||||
@GetTime MACRO
|
||||
mov ah,2Ch
|
||||
int 21h
|
||||
ENDM
|
||||
; 2Dh
|
||||
@SetTime MACRO hour,minutes,seconds,hundredths
|
||||
mov ch,hour
|
||||
mov cl,minutes
|
||||
mov dh,seconds
|
||||
mov dl,hundredths
|
||||
mov ah,2Dh
|
||||
int 21h
|
||||
ENDM
|
||||
; 30h
|
||||
@GetVer MACRO
|
||||
mov ah,30h
|
||||
int 21h
|
||||
ENDM
|
||||
; 35h
|
||||
@GetInt MACRO interrupt
|
||||
mov ax,3500h + (interrupt AND 0FFh)
|
||||
int 21h
|
||||
ENDM
|
||||
; 25h
|
||||
@SetInt MACRO interrupt,vector,segmnt
|
||||
IF TYPE (vector) GE 0FFFEh
|
||||
mov dx,OFFSET vector
|
||||
mov ax,SEG vector
|
||||
mov ds,ax
|
||||
ELSE
|
||||
__LdAdr dx,<vector>
|
||||
IFNB <segmnt>
|
||||
__LdSeg ds,<segmnt>
|
||||
ENDIF
|
||||
ENDIF
|
||||
mov ax,2500h + (interrupt AND 0FFh)
|
||||
int 21h
|
||||
ENDM
|
||||
ENDIF
|
||||
.CREF
|
||||
.LIST
|
||||
|
361
Microsoft MASM v5/inc/MIXED.INC
Normal file
361
Microsoft MASM v5/inc/MIXED.INC
Normal file
@ -0,0 +1,361 @@
|
||||
; High-Level-Language Interface Macros - Version 1.0
|
||||
; for Microsoft Macro Assembler 5.0
|
||||
; (C) Copyright Microsoft Corporation, 1987.
|
||||
|
||||
; Syntax Purpose
|
||||
; ------ -------
|
||||
;
|
||||
; setModel Sets model from text equate
|
||||
;
|
||||
; hProc <name [NEAR|FAR]> [,<USES reglist>] [,arg[:type] [,arg[:type]]]...
|
||||
; Starts a procedure with optional stack arguments
|
||||
;
|
||||
; hLocal var[:type] [,var[:type]]...
|
||||
; Defines local stack variables
|
||||
;
|
||||
; hRet Returns from the current procedure
|
||||
;
|
||||
; hEndp Ends the current procedure
|
||||
;
|
||||
; ifFP statement Assembles statement if far data
|
||||
;
|
||||
; FPoperand Conditionally provides ES override for data
|
||||
;
|
||||
; pLes register,address Conditionally loads data through ES
|
||||
;
|
||||
; pLds register,address Conditionally loads data through DS
|
||||
|
||||
if1
|
||||
|
||||
; Set model passed from command line
|
||||
|
||||
setModel macro
|
||||
setModelDoit %model
|
||||
endm
|
||||
|
||||
setModelDoit macro option
|
||||
|
||||
.model option
|
||||
endm
|
||||
|
||||
; Declare high level routine and parameters
|
||||
|
||||
hProc macro funName, a,b,c,d,e,f,g,h,i,j
|
||||
|
||||
; FP - supply far pointer ES overide as needed
|
||||
|
||||
if @Datasize
|
||||
FP equ <es:>
|
||||
else
|
||||
FP equ < >
|
||||
endif
|
||||
|
||||
cParm=0
|
||||
cbLocals=0
|
||||
argBase = 2 + @CodeSize*2
|
||||
cbReturn = 0
|
||||
localBase = 2
|
||||
|
||||
tokenize funName
|
||||
adjustType %token1
|
||||
conCat procName, %token0
|
||||
conCat nearFar, %token1
|
||||
|
||||
tokenize a
|
||||
hScanParms %token0, <a>, b,c,d,e,f,g,h,i,j
|
||||
|
||||
hProcFinish %procName, %nearFar, %regPushed
|
||||
endm
|
||||
|
||||
; Preprocess arg list to save registers
|
||||
|
||||
hScanParms macro use, regList, b,c,d,e,f,g,h,i,j
|
||||
|
||||
ifidni <use>,<uses>
|
||||
regPushed equ <regList>
|
||||
hScanArgs b,c,d,e,f,g,h,i,j
|
||||
else
|
||||
regPushed equ <>
|
||||
hScanArgs regList,b,c,d,e,f,g,h,i,j
|
||||
endif
|
||||
endm
|
||||
|
||||
; Scan parameter list to process args
|
||||
|
||||
hScanArgs macro a,b,c,d,e,f,g,h,i,j
|
||||
|
||||
irp arg,<a,b,c,d,e,f,g,h,i,j>
|
||||
|
||||
ifb <arg>
|
||||
exitm
|
||||
endif
|
||||
|
||||
fetType arg
|
||||
|
||||
ifdef cLang
|
||||
createArg %argNameCur, %typeNameCur, %argBase+cParm+2
|
||||
else
|
||||
createArg %argNameCur, %typeNameCur, %argBase-cbType-cParm,+cParm
|
||||
endif
|
||||
|
||||
cParm = cParm + cbType + 2
|
||||
endm
|
||||
endm
|
||||
|
||||
; Generate procedure and stack frame
|
||||
|
||||
hProcFinish macro funName, nearFar, regList
|
||||
|
||||
ifdef cLang
|
||||
funNameCur equ <_&funName>
|
||||
else
|
||||
funNameCur equ <funName>
|
||||
cbReturn = cParm
|
||||
|
||||
endif
|
||||
|
||||
funNameCur proc nearFar
|
||||
public funNameCur
|
||||
if cParm
|
||||
push Bp
|
||||
mov Bp,Sp
|
||||
endif
|
||||
pushReg regList
|
||||
endm
|
||||
|
||||
; Save registers
|
||||
|
||||
pushReg macro use,b,c,d,e,f,g
|
||||
|
||||
regPushed equ <>
|
||||
irp reg, <b,c,d,e,f,g>
|
||||
|
||||
ifb <reg>
|
||||
exitm
|
||||
endif
|
||||
|
||||
conCat regPushed, <,> %regPushed
|
||||
conCat regPushed, reg, %regPushed
|
||||
push reg
|
||||
localBase = localBase + 2
|
||||
endm
|
||||
endm
|
||||
|
||||
; Declare local stack variables
|
||||
|
||||
hLocal macro a,b,c,d,e,f,g,h,i,j
|
||||
|
||||
irp arg,<a,b,c,d,e,f,g,h,i,j>
|
||||
|
||||
ifb <arg>
|
||||
exitm
|
||||
endif
|
||||
|
||||
fetType arg
|
||||
createArg %argNameCur, %typeNameCur, %-cbLocals-localBase
|
||||
|
||||
cbLocals = cbLocals + cbType + 2
|
||||
endm
|
||||
|
||||
ife cParm ; Create empty frame if no params
|
||||
push Bp
|
||||
mov Bp,Sp
|
||||
endif
|
||||
|
||||
sub Sp,cbLocals
|
||||
endm
|
||||
|
||||
; Split argment into argNameCur and typeNameCur
|
||||
|
||||
fetType macro arg
|
||||
cbType=0
|
||||
fColon=0
|
||||
argNameCur equ < >
|
||||
typeNameCur equ < >
|
||||
.xcref fColon, argNameCur
|
||||
|
||||
irpc aChar,arg
|
||||
if fColon
|
||||
conCat typeNameCur, %typeNameCur, aChar
|
||||
else
|
||||
ifidni <aChar>,<:>
|
||||
fColon=1
|
||||
else
|
||||
conCat argNameCur,%argNameCur,aChar
|
||||
endif
|
||||
endif
|
||||
endm
|
||||
adjustType %typeNameCur
|
||||
endm
|
||||
|
||||
; Tokenize arg into text macro name tokenN
|
||||
tokenize macro a,b,c,d,e,f,g,h,i,j
|
||||
|
||||
cPart = 0
|
||||
doTokenSet 1
|
||||
|
||||
irp aWord,<a,b,c,d,e,f,g,h,i,j>
|
||||
ifb <aWord>
|
||||
exitm
|
||||
endif
|
||||
|
||||
doTokenSet %cPart, aWord
|
||||
cPart = cPart+1
|
||||
endm
|
||||
endm
|
||||
|
||||
; Set tokenN to a value
|
||||
|
||||
doTokenSet macro tokenNum, aWord
|
||||
token&tokenNum equ <aWord>
|
||||
endm
|
||||
|
||||
; Map typeName to byte count and ptr size
|
||||
|
||||
adjustType macro typeName
|
||||
|
||||
ifb <typeName>
|
||||
cbType = 0
|
||||
typeNameCur equ <word>
|
||||
exitm
|
||||
endif
|
||||
|
||||
ifidni <typeName>,<byte>
|
||||
cbType = 0
|
||||
exitm
|
||||
endif
|
||||
|
||||
ifidni <typeName>,<word>
|
||||
cbType = 0
|
||||
exitm
|
||||
endif
|
||||
|
||||
ifidni <typeName>,<dword>
|
||||
cbType = 2
|
||||
exitm
|
||||
endif
|
||||
|
||||
ifidni <typeName>,<ptr>
|
||||
cbType = (1 + @DataSize) AND 2
|
||||
if (cbType EQ 2)
|
||||
typeNameCur equ <dword>
|
||||
else
|
||||
typeNameCur equ <word>
|
||||
endif
|
||||
exitm
|
||||
endif
|
||||
|
||||
ifidni <typeName>,<fword>
|
||||
cbType = 4
|
||||
exitm
|
||||
endif
|
||||
|
||||
ifidni <typeName>,<qword>
|
||||
cbType = 6
|
||||
exitm
|
||||
endif
|
||||
|
||||
ifidni <typeName>,<tword>
|
||||
cbType = 8
|
||||
exitm
|
||||
endif
|
||||
|
||||
ifidni <typeName>,<near>
|
||||
argBase = 2
|
||||
exitm
|
||||
endif
|
||||
|
||||
ifidni <typeName>,<far>
|
||||
argBase = 4
|
||||
endif
|
||||
endm
|
||||
|
||||
; Concatenate a character to a text macro
|
||||
|
||||
conCat macro symbol,text,char
|
||||
symbol equ <text&char>
|
||||
endm
|
||||
|
||||
; Create text macro for an arg
|
||||
|
||||
createArg macro argName, typeName, offsetParm, argFactor
|
||||
argName equ <typeName ptr [Bp]+offsetParm&argFactor>
|
||||
endm
|
||||
|
||||
; Generate high level return
|
||||
|
||||
hRet macro
|
||||
|
||||
popRegs %regPushed
|
||||
|
||||
if cParm or cbLocals
|
||||
pop Bp
|
||||
endif
|
||||
ret cbReturn
|
||||
endm
|
||||
|
||||
; Restore saved registers
|
||||
|
||||
popRegs macro regList
|
||||
|
||||
if cbLocals
|
||||
ifnb <regList>
|
||||
add Sp,cbLocals
|
||||
else
|
||||
mov Sp,Bp
|
||||
endif
|
||||
endif
|
||||
|
||||
irp reg, <regList>
|
||||
ifnb <reg>
|
||||
pop reg
|
||||
endif
|
||||
endm
|
||||
endm
|
||||
|
||||
; End a high level procedure
|
||||
|
||||
hEndp macro
|
||||
funNameCur endp
|
||||
endm
|
||||
|
||||
; Execute instruction if far data
|
||||
|
||||
ifFP macro a,b,c,d,e,f,g,h,i,j
|
||||
|
||||
if @datasize
|
||||
a b c d e f g h i j
|
||||
endif
|
||||
endm
|
||||
|
||||
; Load 16/32 bit pointers into [ES:] reg
|
||||
|
||||
pLes macro reg, address
|
||||
|
||||
if @datasize
|
||||
|
||||
les reg,address
|
||||
else
|
||||
mov reg,address
|
||||
|
||||
endif
|
||||
endm
|
||||
|
||||
;Load 16/32 bit pointers into [DS:] reg
|
||||
|
||||
pLds macro reg, address
|
||||
|
||||
if @datasize
|
||||
|
||||
lds reg,address
|
||||
else
|
||||
mov reg,address
|
||||
|
||||
endif
|
||||
endm
|
||||
|
||||
.xcref createArg, conCat, fetType, cbType, argBase, pushReg, hScanArgs, hScanParms
|
||||
.xcref adjustType, typeNameCur, setModelDoit, tokenize, dotokenSet
|
||||
.xcref token0, token1, regPushed, hProcFinish, procName, localBase, popRegs
|
||||
|
||||
endif ; Define on pass1 only
|
8
Microsoft MASM v5/m.bat
Normal file
8
Microsoft MASM v5/m.bat
Normal file
@ -0,0 +1,8 @@
|
||||
del %1.map
|
||||
del %1.exe
|
||||
del %1.lst
|
||||
del %1.obj
|
||||
|
||||
ntvdm -h bin\masm /Zi /Zd /z /l %1,,,;
|
||||
ntvdm -h bin\link /CP:1 %1,,%1,,nul.def
|
||||
|
45
Microsoft MASM v5/samples/BA.ASM
Normal file
45
Microsoft MASM v5/samples/BA.ASM
Normal file
@ -0,0 +1,45 @@
|
||||
|
||||
.MODEL medium
|
||||
.CODE
|
||||
|
||||
; BASIC function for QuickBASIC, Version 4 and future versions
|
||||
; of Microsoft and IBM BASIC Compilers
|
||||
|
||||
PUBLIC Power2
|
||||
Power2 PROC
|
||||
push bp ; Entry sequence - save old BP
|
||||
mov bp,sp ; Set stack framepointer
|
||||
|
||||
mov bx,[bp+8] ; Load Arg1 into
|
||||
mov ax,[bx] ; AX
|
||||
mov bx,[bp+6] ; Load Arg2 into
|
||||
mov cx,[bx] ; CX
|
||||
shl ax,cl ; AX = AX * (2 to power of CX)
|
||||
; Leave return value in AX
|
||||
|
||||
pop bp ; Restore old framepointer
|
||||
ret 4 ; Exit, and restore 4 bytes of args
|
||||
Power2 ENDP
|
||||
|
||||
; BASIC subprogram for QuickBASIC, Versions 1, 2, and 3;
|
||||
; for the Microsoft BASIC Compiler through Version 5.36
|
||||
; for the IBM BASIC Compiler through Version 2.02
|
||||
|
||||
PUBLIC Power2S
|
||||
Power2S PROC
|
||||
push bp ; Entry sequence - save old BP
|
||||
mov bp,sp ; Set stack framepointer
|
||||
|
||||
mov bx,[bp+10] ; Load Arg1 into
|
||||
mov ax,[bx] ; AX
|
||||
mov bx,[bp+8] ; Load Arg2 into
|
||||
mov cx,[bx] ; CX
|
||||
shl ax,cl ; AX = AX * (2 to power of CX)
|
||||
mov bx,[bp+6] ; Store result in
|
||||
mov [bx],ax ; Arg3
|
||||
|
||||
pop bp ; Restore old framepointer
|
||||
ret 4 ; Exit, and restore 4 bytes of args
|
||||
Power2S ENDP
|
||||
END
|
||||
|
18
Microsoft MASM v5/samples/CA.ASM
Normal file
18
Microsoft MASM v5/samples/CA.ASM
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
.MODEL SMALL
|
||||
.CODE
|
||||
PUBLIC _Power2
|
||||
_Power2 PROC
|
||||
push bp ;Entry sequence
|
||||
mov bp,sp
|
||||
|
||||
mov ax,[bp+4] ; Load Arg1 into AX
|
||||
mov cx,[bp+6] ; Load Arg2 into CX
|
||||
shl ax,cl ; AX = AX * (2 to power of CX)
|
||||
; Leave return value in AX
|
||||
|
||||
pop bp ; Exit sequence
|
||||
ret
|
||||
_Power2 ENDP
|
||||
END
|
||||
|
BIN
Microsoft MASM v5/samples/DEMO.BAT
Normal file
BIN
Microsoft MASM v5/samples/DEMO.BAT
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/samples/E_AUTO.CV
Normal file
BIN
Microsoft MASM v5/samples/E_AUTO.CV
Normal file
Binary file not shown.
19
Microsoft MASM v5/samples/FA.ASM
Normal file
19
Microsoft MASM v5/samples/FA.ASM
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
.MODEL large
|
||||
.CODE
|
||||
PUBLIC Power2
|
||||
Power2 PROC
|
||||
push bp ; Entry sequence - save old BP
|
||||
mov bp,sp ; Set stack framepointer
|
||||
|
||||
les bx,[bp+10] ; Load Arg1 into
|
||||
mov ax,[bx] ; AX
|
||||
les bx,[bp+6] ; Load Arg2 into
|
||||
mov cx,[bx] ; CX
|
||||
shl ax,cl ; AX = AX * (2 to power of CX)
|
||||
; Leave return value in AX
|
||||
|
||||
pop bp ; Restore old framepointer
|
||||
ret 4 ; Exit, and restore 4 bytes of args
|
||||
Power2 ENDP
|
||||
END
|
660
Microsoft MASM v5/samples/MACRO.DOC
Normal file
660
Microsoft MASM v5/samples/MACRO.DOC
Normal file
@ -0,0 +1,660 @@
|
||||
Calling Macros in DOS.INC and BIOS.INC
|
||||
|
||||
You are responsible for saving and restoring registers used in
|
||||
macros. The "Registers used" field identifies registers to save.
|
||||
|
||||
Macros that accept address parameters use internal macros that
|
||||
allow you to specify addresses in several ways. The macro
|
||||
automatically identifies the type of the argument and handles it
|
||||
appropriately. For example, assume the following declarations:
|
||||
|
||||
String DB "test$"
|
||||
pString DW Str
|
||||
fpString DD Str
|
||||
|
||||
Given these values, the macro @DispStr (which displays the string
|
||||
at DS:DX) has the following effects:
|
||||
|
||||
Kind of argument Example Value loaded
|
||||
|
||||
Label of byte variable @DispStr String DS:OFFSET String
|
||||
Near pointer variable @DispStr pString DS:pString
|
||||
Far pointer variable @DispStr fpString fpString[2]:fpString[0]
|
||||
Constant @DispStr 0 DS:0
|
||||
Pointer in register @DispStr si DS:SI
|
||||
Near Pointer with segment @DispStr pString,es ES:pString
|
||||
Constant with segment @DispStr 0,es ES:0
|
||||
Register with segment @DispStr di,es ES:DI
|
||||
|
||||
Note that if a far pointer or a segment is given, DS must be
|
||||
saved before the macro call and restored afterward. Segments may
|
||||
be given as registers, constants, or word variables.
|
||||
|
||||
In syntax, parameters enclosed in brackets are optional.
|
||||
Paramaters sometimes have a leading symbol to indicate that the
|
||||
argument must have a certain type, as shown below:
|
||||
|
||||
Leading Symbol Example Limitation
|
||||
|
||||
# #return Must be constant
|
||||
& &vector Must be offset address as described above
|
||||
$ $terminator May be constant or register, but not memory
|
||||
|
||||
Parameters with no leading symbol may be constants, registers, or
|
||||
variables. Parameters are 16-bit except where noted in the description.
|
||||
|
||||
Symbols must be previously defined before they can be passed as
|
||||
arguments to most of the DOS macros. Generally this means that
|
||||
data must be declared before code in the source file.
|
||||
|
||||
DOS Macro Syntax and Description
|
||||
|
||||
KEYBOARD INPUT
|
||||
|
||||
@GetKey (01h, 07h, 08h, 0Ch)
|
||||
|
||||
Gets a keystroke from the keyboard
|
||||
|
||||
Syntax: @GetKey [#echo] [,[#break] [,#clearbuf]]
|
||||
|
||||
Arguments: echo = nonzero to echo keystroke - default yes
|
||||
break = nonzero to accept Control-C - default yes
|
||||
clearbuf = nonzero to clear keyboard buffer - default no
|
||||
(Arguments may be omitted to get defaults)
|
||||
Return: ASCII code of key in AL
|
||||
Registers used: AX used for all, DL used if echo on and ctrl-c off
|
||||
|
||||
|
||||
@GetStr (0Ah)
|
||||
|
||||
Gets a string from the keyboard
|
||||
|
||||
Syntax: @GetStr &buffer [,[$terminator] [,[#limit] [,segment]]]
|
||||
|
||||
Arguments: buffer = Offset of buffer where string will be stored
|
||||
Byte 1 = Maximum length of string (before call)
|
||||
Byte 2 = Actual length of string (after call)
|
||||
Byte 3+ = Bytes of string
|
||||
terminator = Terminating byte - usually null (0) or $ (24h)
|
||||
limit = Maximum length of string (if not given as
|
||||
argument, must be in buffer before macro call)
|
||||
segment = Segment of buffer (DS if not given)
|
||||
Return: Pointer to string in SI, length of string in BX
|
||||
Registers used: AX, DX, BX, SI
|
||||
|
||||
OUTPUT
|
||||
|
||||
@DispCh (02h)
|
||||
|
||||
Displays one or more characters to screen
|
||||
|
||||
Syntax: @DispCh char [,char]...
|
||||
|
||||
Arguments: char = 8-bit ASCII code
|
||||
Return: Code in AL
|
||||
Registers used: AX and DL
|
||||
|
||||
|
||||
@PrtCh (05h)
|
||||
|
||||
Prints one or more characters to LPT1
|
||||
|
||||
Syntax: @PrtCh char [,char]...
|
||||
|
||||
Arguments: char = 8-bit ASCII code
|
||||
Return: Code in AL
|
||||
Registers used: AX and DL
|
||||
|
||||
|
||||
@DispStr (09h)
|
||||
|
||||
Displays a $-terminated string
|
||||
|
||||
Syntax: @DispStr &address [,segment]
|
||||
|
||||
Arguments: address = Address of string terminated by "$" (24h)
|
||||
segment = Segment of address string (DS if not given)
|
||||
Return: None
|
||||
Registers used: AX and DS
|
||||
|
||||
DEVICE I/O
|
||||
|
||||
@Read (3Fh)
|
||||
|
||||
Reads data from a file or device
|
||||
|
||||
Syntax: @Read &buffer, length [,[handle] [,segment]]
|
||||
|
||||
Arguments: buffer = Offset of buffer where data will be stored
|
||||
length = Length of data in bytes
|
||||
handle = File or device handle; if none given,
|
||||
keyboard (handle 0) is assumed
|
||||
segment = Segment of address string (DS if not given)
|
||||
Return: If carry clear, bytes read in AX
|
||||
Registers used: Always AX, DX, BX, and CX; DS if segment changed
|
||||
|
||||
|
||||
@Write (40h)
|
||||
|
||||
Writes data to a file or device
|
||||
|
||||
Syntax: @Write &buffer, length, [,[handle] [,segment]]
|
||||
|
||||
Arguments: buffer = Offset of buffer where data is stored
|
||||
length = Length of data in bytes
|
||||
handle = File or device handle; if none given, screen
|
||||
(handle 1) is assumed
|
||||
segment = Segment of address string (DS if not given)
|
||||
Return: If carry clear, bytes written in AX
|
||||
Registers used: Always AX, DX, BX, and CX; DS if segment changed
|
||||
|
||||
FILE CONTROL
|
||||
|
||||
@MakeFil (3Ch, 5Ah, 5Bh)
|
||||
|
||||
Creates a file
|
||||
|
||||
Syntax: @MakeFil &path [,[attrib] [,[segment] [,#kind]]]
|
||||
|
||||
Arguments: path = ASCIIZ string of file
|
||||
attrib = File atrribute (0 is default if none given)
|
||||
segment = Segment of address string (DS if not given)
|
||||
kind = If none given, a file is always created even if
|
||||
one already exists. Under DOS 3+ "tmp" can be
|
||||
given to create a unique file or "new" to create
|
||||
file only if one doesn't already exist.
|
||||
Return: If carrry clear, file handle in AX
|
||||
Registers used: Always AX, DX, and CX; DS if segment changed
|
||||
|
||||
|
||||
@OpenFil (3Dh)
|
||||
|
||||
Opens a file for input or output
|
||||
|
||||
Syntax: @OpenFil &path, #access [,segment]
|
||||
|
||||
Arguments: path = ASCIIZ string of file
|
||||
access = File access code
|
||||
segment = Segment of address string (DS if not given)
|
||||
Return: If carrry set, error code in AX
|
||||
Registers used: Always AX and DX; DS if segment changed
|
||||
|
||||
|
||||
@ClosFil (3Eh)
|
||||
|
||||
Closes an open file handle
|
||||
|
||||
Syntax: @ClosFil handle
|
||||
|
||||
Arguments: handle = Previously opened file handle
|
||||
Return: If carrry set, error code in AX
|
||||
Registers used: AX and BX
|
||||
|
||||
|
||||
@DelFil (41h)
|
||||
|
||||
Deletes a specified file
|
||||
|
||||
Syntax: @DelFil &path [,segment]
|
||||
|
||||
Arguments: path = Offset of ASCIIZ filespec
|
||||
segment = Segment of path (DS if none given)
|
||||
Return: If carrry set, error code in AX
|
||||
Registers used: AX and DX; DS if segment changed
|
||||
|
||||
@MoveFil (56h)
|
||||
|
||||
Moves or renames a file by changing its path specification.
|
||||
|
||||
Syntax: @MoveFil &old, &new [,[segold] [,segnew]]
|
||||
|
||||
Arguments: old = Offset of file spec to be renamed
|
||||
new = Offset of new file spec
|
||||
segold = Segment of old name (DS if none given)
|
||||
segnew = Segment of new name (ES if none given)
|
||||
Return: If carry set, error code in AX
|
||||
Registers used: AX, DX, and DI; DS and ES if corresponding segments changed
|
||||
|
||||
|
||||
@GetFirst (4Eh) and @GetNext (4Fh)
|
||||
|
||||
Parses file specifications (optionally including wild cards) into
|
||||
file names
|
||||
|
||||
Syntax: @GetFirst &path [,[attribute] [,segment]]
|
||||
@GetNext
|
||||
|
||||
Arguments: path = Offset of ASCIIZ filespec (can have wild cards)
|
||||
attribute = File attribute to search for (0 for normal if
|
||||
none given)
|
||||
segment = Segment of path (DS if none given)
|
||||
Return: If carrry set, error code in AX
|
||||
Registers used: @GetFirst = AX, CX, and DX; DS if segment changed
|
||||
@GetNext = AX only
|
||||
|
||||
|
||||
@GetDTA (1Ah) and @SetDTA (2Fh)
|
||||
|
||||
Gets or sets the Disk Transfer Address (DTA)
|
||||
|
||||
Syntax: @GetDTA
|
||||
@SetDTA &buffer [,segment]
|
||||
|
||||
Arguments: buffer = Offset of new DTA buffer
|
||||
segment = Segment of new DTA buffer (DS if none given)
|
||||
Return: @GetDTA = ES:BX points to DTA
|
||||
@SetDTA = None
|
||||
Registers used: AX for both; DS and DX for @SetDTA; ES and BX for @GetDTA
|
||||
|
||||
@GetFilSz (42h)
|
||||
|
||||
Gets the file size by moving the file pointer to end of the file.
|
||||
Note that the file pointer is reset to zero. Thus this macro should
|
||||
not be called during operations that move the pointer.
|
||||
|
||||
Syntax: @GetFilSz handle
|
||||
|
||||
Arguments: handle = Previously opened file handle
|
||||
Return: If carrry clear, file length in DX:AX
|
||||
Registers used: AX, BX, CX, and DX
|
||||
|
||||
|
||||
@MovePrtAbs and @MovePtrRel (42h)
|
||||
|
||||
Moves the file pointer in an open file. The pointer can be moved to
|
||||
an absolute position, or relative to its current position.
|
||||
|
||||
Syntax: @MovePrtAbs handle [,distance]
|
||||
@MovePrtRel handle [,distance]
|
||||
|
||||
Arguments: handle = Previously opened file handle
|
||||
distance = Distance to move pointer - must be a 16-bit
|
||||
constant or a 16- or 32-bit variable; or
|
||||
leave blank and set distance in CX:DX before
|
||||
macro call
|
||||
Return: If carrry clear, file pointer position in DX:AX
|
||||
Registers used: AX, BX, CX, and DX
|
||||
|
||||
DIRECTORY CONTROL
|
||||
|
||||
@MkDir, (39h), @RmDir (3Ah), and @ChDir (3Bh)
|
||||
|
||||
Creates, deletes, or changes to the specified directory
|
||||
|
||||
Syntax: @MkDir &path [,segment]
|
||||
@RmDir &path [,segment]
|
||||
@ChDir &path [,segment]
|
||||
|
||||
Arguments: path = Offset of ASCIIZ string to
|
||||
segment = Segment of path (DS if none given)
|
||||
Return: If carrry set, error code in AX
|
||||
Registers used: AX and DX; DS if segment changed
|
||||
|
||||
|
||||
@GetDir (47h)
|
||||
|
||||
Returns the current directory of the specified drive
|
||||
|
||||
Syntax: @GetDir &path [,[drive] [,segment]]
|
||||
|
||||
Arguments: buffer = Offset of buffer to receive ASCIIZ directory
|
||||
drive = 8-bit drive number - 0=current, 1=A, 2=B, etc.
|
||||
(0 if none given)
|
||||
segment = Segment of path (DS if none given)
|
||||
Return: If carrry set, error code in AX
|
||||
Registers used: AX, SI, and DL; DS if segment changes
|
||||
|
||||
|
||||
DRIVE CONTROL
|
||||
|
||||
@GetDrv (0Eh) and @SetDrv (19h)
|
||||
|
||||
Gets or sets the current drive
|
||||
|
||||
Syntax: @GetDrv
|
||||
@SetDrv drive
|
||||
|
||||
Argument: drive = 8-bit drive number (0=A, 1=B, etc.)
|
||||
Return: @GetDrv = Drive number in AL (0=A, 1=B, etc.)
|
||||
@SetDrv = Number of drives in AL
|
||||
Registers used: AX for both; DL for @SetDrv
|
||||
|
||||
|
||||
@ChkDrv (36h)
|
||||
|
||||
Gets various data about a disk
|
||||
|
||||
Syntax: @ChkDrv [drive]
|
||||
|
||||
Argument: drive = 8-bit drive number (0=current,A=1, B=2, etc.);
|
||||
if none given, current assumed
|
||||
Return: AX = Sectors per cluster (-1 if drive invalid)
|
||||
BX = Available clusters
|
||||
CX = Bytes per sector
|
||||
DX = Clusters per drive
|
||||
Registers used: AX, BX, CX, and DX
|
||||
|
||||
PROCESS CONTROL
|
||||
|
||||
@Exit (4Ch)
|
||||
|
||||
Exits to DOS with return code
|
||||
|
||||
Syntax: @Exit [#return]
|
||||
|
||||
Argument: return = 8-bit code to return to DOS; if none given,
|
||||
AL is used
|
||||
Return: None
|
||||
Registers used: AX
|
||||
|
||||
|
||||
@Exec (4Bh)
|
||||
|
||||
Executes a child process or an overlay
|
||||
|
||||
Syntax: @Exec path, params [,[segpath] [,[segparams] [,overlay]]]
|
||||
|
||||
Arguments: path = Offset of ASCIIZ filespec to be executed
|
||||
params = Offset of process parameter block
|
||||
segpath = Segment of filespec (DS if none given)
|
||||
segparams = Segment of parameter block (ES if none given)
|
||||
overlay = If not defined, normal process executed;
|
||||
if defined, overlay executed
|
||||
Return: If carry set, error code
|
||||
Registers used: AX, SI, and DI; DS and ES if corresponding segments given
|
||||
|
||||
|
||||
@GetRet (4Dh)
|
||||
|
||||
Gets the return code of a child process
|
||||
|
||||
Syntax: @GetRet
|
||||
|
||||
Argument: None
|
||||
Return: Return code in AX
|
||||
Register used: AX
|
||||
|
||||
|
||||
@TSR (31h)
|
||||
|
||||
Terminates a program, but leaves it resident in memory
|
||||
|
||||
Syntax: @TSR paragraphs [,#return]
|
||||
|
||||
Arguments: return = Code to return to DOS; if none, AL used
|
||||
paragraphs = Memory in paragraphs (16 bytes) to
|
||||
allocate for resident program
|
||||
Return: None
|
||||
Registers used: AX and DX
|
||||
|
||||
MEMORY CONTROL
|
||||
|
||||
@FreeBlok (49h)
|
||||
|
||||
Frees a block of memory
|
||||
|
||||
Syntax: @FreeBlok [segment]
|
||||
|
||||
Argument: segment = Starting address of memory to be freed;
|
||||
if none, ES address assumed
|
||||
Return: If carry set, error code in AX
|
||||
Register used: AX; ES if segment given
|
||||
|
||||
|
||||
@GetBlok (48h)
|
||||
|
||||
Allocates a block of memory
|
||||
|
||||
Syntax: @GetBlok paragraphs
|
||||
|
||||
Argument: paragraphs = Paragraphs (16 bytes) of memory wanted
|
||||
Return: AX and ES = Segment address of allocated memory
|
||||
BX = Paragraphs actually allocated (may be
|
||||
less than requested if memory is short)
|
||||
Register used: AX and BX
|
||||
|
||||
|
||||
@ModBlok (48h)
|
||||
|
||||
Modifies an allocated block of memory
|
||||
|
||||
Syntax: @ModBlok paragraphs [,segment]
|
||||
|
||||
Argument: paragraphs = Paragraphs (16 bytes) of memory wanted
|
||||
segment = Starting address of memory to be freed;
|
||||
if none, ES address assumed
|
||||
Return: If carry set, error code in AX, else:
|
||||
ES = Segment address of allocated memory
|
||||
BX = If carry is clear, paragraphs allocated
|
||||
Register used: AX and BX; ES if segment given
|
||||
|
||||
MISCELLANEOUS
|
||||
|
||||
@GetDate (2Ah) and @SetDate (2Bh)
|
||||
|
||||
Gets or sets the system date
|
||||
|
||||
Syntax: @GetDate
|
||||
@SetDate month, day, year
|
||||
|
||||
Arguments: year = 16-bit year (1980-2099)
|
||||
month = 8-bit month (1-12)
|
||||
day = 8-bit day (1-31)
|
||||
Return: For @GetDate:
|
||||
AL = Day of week (0 = Sunday, 1 = Monday, etc.)
|
||||
CX = Year (1980-2099)
|
||||
DL = Month (1-12)
|
||||
DH = Day (1-31)
|
||||
For @SetDate:
|
||||
AL = If date was valid 0, else -1
|
||||
Registers used: AX, CX, and DX
|
||||
|
||||
|
||||
@GetTime (2Ch) and @SetTime (2Dh)
|
||||
|
||||
Gets or sets the system time
|
||||
|
||||
Syntax: @GetTime
|
||||
@SetTime hour,minute,second,hundredth
|
||||
|
||||
Arguments: hour = 8-bit hour (0-23)
|
||||
minute = 8-bit hour (0-59)
|
||||
second = 8-bit hour (0-59)
|
||||
hundredth = 8-bit hour (0-99)
|
||||
Return: For @GetTime:
|
||||
CL = Hour (0-23)
|
||||
CH = Minute (0-59)
|
||||
DL = Second (0-59)
|
||||
DH = Hundredth (0-99)
|
||||
For @SetTime:
|
||||
AL = If time was valid 0, else -1
|
||||
Registers used: AX, CX, and DX
|
||||
|
||||
|
||||
@GetVer (30h)
|
||||
|
||||
Gets the DOS version
|
||||
|
||||
Syntax: @GetVer
|
||||
|
||||
Argument: None
|
||||
Return: AL = Major version (0 for versions prior to 2.0)
|
||||
AH = Minor version
|
||||
BH = OEM serial number
|
||||
BL:CX = 24-bit user number
|
||||
Register used: AX, BX, and CX
|
||||
|
||||
@GetInt (35h) and @SetInt (25h)
|
||||
|
||||
Gets or sets the vector for a specified interrupt routine
|
||||
|
||||
Syntax: @GetInt #interrupt
|
||||
@SetInt #interrupt, &vector [,segment]
|
||||
|
||||
Arguments: interrupt = 8-bit interrupt number
|
||||
vector = Offset of interrupt routine
|
||||
segment = Segment of routine - if none given, DS assumed
|
||||
for data; segment ignored for code labels
|
||||
Return: @GetInt = None
|
||||
@SetInt = ES:BX points to interrupt routine
|
||||
Registers used: AX for both; ES and BX for @GetInt; DS and DS for @SetInt
|
||||
|
||||
BIOS Macro Syntax and Description
|
||||
|
||||
|
||||
MODE, PAGE, AND COLOR CONTROL
|
||||
|
||||
@GetMode (I 10h F 0Fh)
|
||||
|
||||
Gets the current video mode and page
|
||||
|
||||
Syntax: @GetMode
|
||||
|
||||
Arguments: None
|
||||
Return: AL = Mode
|
||||
AH = Width in characters
|
||||
BH = Page
|
||||
Registers used: AX and BH
|
||||
|
||||
|
||||
@SetMode (I 10h F 00h)
|
||||
|
||||
Gets the current video mode and page
|
||||
|
||||
Syntax: @SetMode mode
|
||||
|
||||
Arguments: mode = 8-bit video mode
|
||||
Return: none
|
||||
Registers used: AX
|
||||
|
||||
|
||||
@SetColor (I 10h F 0Bh)
|
||||
|
||||
Sets the background color
|
||||
|
||||
Syntax: @SetColor color
|
||||
|
||||
Arguments: color = 8-bit background color (0-15);
|
||||
border color in text modes
|
||||
Return: none
|
||||
Registers used: AX and BX
|
||||
|
||||
|
||||
@SetPalet (I 10h F 0Bh)
|
||||
|
||||
Sets the color palette
|
||||
|
||||
Syntax: @SetPalet color
|
||||
|
||||
Arguments: color = 8-bit color palette (0-1 for modes 5 and 6)
|
||||
Return: none
|
||||
Registers used: AX and BX
|
||||
|
||||
@SetPage (I 10h F 05h)
|
||||
|
||||
Sets the video page
|
||||
|
||||
Syntax: @SetPage page
|
||||
|
||||
Arguments: page = 8-bit page number; 0-3 for modes 2 and 3
|
||||
Return: none
|
||||
Registers used: AX
|
||||
|
||||
|
||||
CHARACTER AND CURSOR CONTROL
|
||||
|
||||
@GetCur (I 10h F 04h)
|
||||
|
||||
Gets the cursor position and size
|
||||
|
||||
Syntax: @GetCur [page]
|
||||
|
||||
Arguments: page = 8-bit page with cursor (if none, 0 assumed)
|
||||
Return: DL = Column
|
||||
DH = Row
|
||||
CL = Starting scan line
|
||||
CH = Ending scan line
|
||||
Registers used: AX, DX, CX, and BH
|
||||
|
||||
|
||||
@SetCurPos (I 10h F 02h)
|
||||
|
||||
Sets the cursor position
|
||||
|
||||
Syntax: @SetCurSz [column] [,[row] [,page]]
|
||||
|
||||
Arguments: column = 8-bit column; if none, DL used
|
||||
row = 8-bit row; if none, DH used
|
||||
page = 8-bit page with cursor (if none, 0 assumed)
|
||||
Return: none
|
||||
Registers used: AX, DX, and BH
|
||||
|
||||
|
||||
@SetCurSz (I 10h F 01h)
|
||||
|
||||
Sets the cursor size and shape by specifying active scan lines. The
|
||||
CGA adapter the lines are 0-7. The monochrome adapter has lines 0-13.
|
||||
|
||||
Syntax: @SetCurSz startline, endline
|
||||
|
||||
Arguments: startline = 8-bit starting scan line (default CGA=6; MA=12)
|
||||
endline = 8-bit ending scan line (default CGA=7; MA=13)
|
||||
Return: none
|
||||
Registers used: AX and CX
|
||||
|
||||
@GetChAtr (I 10h F 08h)
|
||||
|
||||
Gets the character and attribute at the cursor location
|
||||
|
||||
Syntax: @GetChAtr [page]
|
||||
|
||||
Arguments: page = 8-bit page to check (if none, 0 assumed)
|
||||
Return: AH = Attribute
|
||||
AL = ASCII character
|
||||
Registers used: AX and BH
|
||||
|
||||
|
||||
@PutChAtr (I 10h F 09h) and @PutCh (I 10h F 0Ah)
|
||||
|
||||
Puts one or more characters and attributes at the current cursor
|
||||
position. For @PutCh, the current attribute is used in text modes
|
||||
and any specified attribute is ignored.
|
||||
|
||||
Syntax: @PutChAtr [character] [,[attrib] [,[page] [,count]]]
|
||||
|
||||
Arguments: character = 8-bit ASCII character to put; if none, AL used
|
||||
attrib = 8-bit attribute to put; if none, BL used
|
||||
page = 8-bit page to put on (if none, 0 assumed)
|
||||
count = Number to put (if none, 1 assumed)
|
||||
Return: AH = Attribute
|
||||
AL = ASCII character
|
||||
Registers used: AX, BX, CX
|
||||
|
||||
|
||||
@Scroll (I 10h F 06h and 07h)
|
||||
|
||||
Scrolls a specified window up or down
|
||||
|
||||
Syntax: @Scroll dist [,[attr] [,[uprow [,[upcol [,[dnrow] [,dncol]]]]]
|
||||
|
||||
Arguments: dist = 8-bit number of lines to scroll; positive
|
||||
scrolls down; negative scrolls up; 0 clears
|
||||
attr = 8-bit attribute for blank lines (if none, 07h)
|
||||
uprow = Upper left row (if none, CH used)
|
||||
upcol = Upper left column (if none, CL used)
|
||||
dnrow = Lower right row (if none, DH used)
|
||||
dncol = Lower right column (if none, DL used)
|
||||
Return: none
|
||||
Registers used: AX, CX, DX, and BH
|
||||
|
||||
|
||||
@Cls (I 10h F 06, 08h, and 02h)
|
||||
|
||||
Clears the screen of the current page
|
||||
|
||||
Syntax: @Cls
|
||||
|
||||
Arguments: None
|
||||
Return: None
|
||||
Registers used: AX, BX, CX, and DX
|
||||
|
272
Microsoft MASM v5/samples/MIXED.DOC
Normal file
272
Microsoft MASM v5/samples/MIXED.DOC
Normal file
@ -0,0 +1,272 @@
|
||||
Mixed-Language Source Files
|
||||
|
||||
This directory contains mixed-language example programs and macros.
|
||||
|
||||
The following source files are the sample programs from Chapter 6,
|
||||
"Assembly-to-High-Level Interface," of the Mixed-Language Programming
|
||||
Guide:
|
||||
|
||||
BA.ASM Assembly module to be called from BASIC
|
||||
CA.ASM Assembly module to be called from C
|
||||
FA.ASM Assembly module to be called from FORTRAN
|
||||
PA.ASM Assembly module to be called from Pascal
|
||||
|
||||
BAMAIN.BAS BASIC main program that calls assembly module
|
||||
CAMAIN.C C main program that calls assembly module
|
||||
FAMAIN.FOR FORTRAN main program that calls assembly module
|
||||
PAMAIN.PAS Pascal main program that calls assembly module
|
||||
|
||||
In addition, the directory contains the following files:
|
||||
|
||||
MIXED.INC Macros for simplifying assembly routines intended
|
||||
to be called from high-level languages.
|
||||
POWER2.ASM Macro version of assembly module that can be called
|
||||
from BASIC, C, FORTRAN, or Pascal.
|
||||
|
||||
Mixed-Language Macros
|
||||
|
||||
MIXED.INC contains macros for defining high-level-language routines.
|
||||
It can create functions for Microsoft C, FORTRAN, or Pascal, and for
|
||||
future versions of Microsoft BASIC. It can also create subprograms
|
||||
for BASIC, subroutines for FORTRAN, or procedures for Pascal.
|
||||
|
||||
Note: Some BASIC examples use functions and the DECLARE
|
||||
statement. These features are not available in versions of
|
||||
Microsoft BASIC available at release time. They will work
|
||||
if you rewrite functions as subprograms. Functions and
|
||||
DECLARE statements will be supported in future versions of
|
||||
Microsoft BASIC compilers.
|
||||
|
||||
The following macros are provided:
|
||||
|
||||
Macro Purpose
|
||||
|
||||
setModel Sets memory model passed from a DOS command line
|
||||
hProc Initializes a procedure
|
||||
hLocal Initializes local variables
|
||||
hRet Returns from a procedure
|
||||
hEndp Terminates a procedure
|
||||
|
||||
ifFP Assembles statement if the memory model uses far data
|
||||
FP Provides ES override if the memory model uses far data
|
||||
pLes Loads data (through ES for far data)
|
||||
pLds Loads data (through DS for far data)
|
||||
|
||||
Other internal macros in MIXED.INC are used by these macros, but can
|
||||
be ignored by the user.
|
||||
Macro Syntax
|
||||
|
||||
The calling convention used in the macros depends on whether the
|
||||
symbol "cLang" is defined. If "cLang" is defined, the C calling
|
||||
convention is used. Otherwise, the calling convention used by
|
||||
BASIC, FORTRAN, and Pascal is used.
|
||||
|
||||
Macro names and arguments are case insensitive. The macros and
|
||||
their syntax are described below:
|
||||
|
||||
setModel
|
||||
|
||||
Sets the memory model to small, medium, compact, large, or huge.
|
||||
This macro is an alternative to the .MODEL directive. It enables
|
||||
you to pass a memory model from the MASM command line. For
|
||||
example, you can use
|
||||
|
||||
setModel
|
||||
|
||||
as the first code in your source file and supply the memory model
|
||||
with the /D option as shown below:
|
||||
|
||||
MASM /Dmodel=medium source;
|
||||
|
||||
|
||||
hProc <name [NEAR|FAR]> [,<USES reglist>] [,arg[:type] [,arg[:type]]]...
|
||||
|
||||
Initializes a procedure by pushing BP and saving SP in BP. The
|
||||
macro also handles the following tasks:
|
||||
|
||||
1. Declares the procedure name public in the format of the language
|
||||
("doTask" is declared as "_doTask" for the C compiler).
|
||||
|
||||
2. Gives the procedure the type NEAR or FAR if specified, or the
|
||||
default type for the memory model (NEAR for small and compact
|
||||
models or FAR for medium, large, and huge models). If type is
|
||||
specified, the name and type must be enclosed in angle brackets.
|
||||
|
||||
3. Saves and restores specified registers. The keyword USES must
|
||||
be given as a parameter followed by the registers. USES and
|
||||
the registers must be enclosed in angle brackets.
|
||||
|
||||
4. Assigns names and types to stack parameters. The type for
|
||||
parameters can be BYTE, WORD, DWORD, FWORD, QWORD, TWORD, or
|
||||
PTR. If no type is given, WORD is assumed. PTR type means
|
||||
that the parameter is a pointer. It's size is variable
|
||||
depending on the size of the memory model. Pointers are
|
||||
assumed to point to data, so the size is NEAR for small and
|
||||
medium models or FAR for compact, large, and huge models.
|
||||
|
||||
For example,
|
||||
|
||||
hProc <doTask FAR>, <USES si di>, count:BYTE, array:PTR, number
|
||||
|
||||
defines the FAR procedure "doTask" with byte parameter "count",
|
||||
pointer paramter "array", and word parameter "number". The SI and
|
||||
DI registers are saved.
|
||||
|
||||
hLocal var[:type] [,var[:type]]...
|
||||
|
||||
Saves space on the stack for local variables and assign them
|
||||
variables names. For example,
|
||||
|
||||
hLocal work,temp:DWORD
|
||||
|
||||
allocates "work" as a temporary word variable and "temp" as a
|
||||
temporary doubleword variable.
|
||||
|
||||
|
||||
hRet
|
||||
|
||||
Returns from a procedure. SP is restored from BP if local variables
|
||||
have been used. BP is popped. A RET instruction is given in
|
||||
the format appropriate for the memory model and calling
|
||||
convention.
|
||||
|
||||
|
||||
hEndp
|
||||
|
||||
Ends a procedure. Note that a procedure may have several return
|
||||
points, but only one end point.
|
||||
|
||||
|
||||
ifFP statement
|
||||
|
||||
Assembles the statement if the memory model uses far data. This
|
||||
macro can be used to push segment registers or take other
|
||||
action that is only required for far data. For example,
|
||||
|
||||
ifFP push ds
|
||||
|
||||
pushes the DS register in compact, large, and huge memory
|
||||
models, but has no effect in small and medium models.
|
||||
|
||||
|
||||
FPoperand
|
||||
|
||||
Gives an ES override if the memory model uses far data. In
|
||||
models that use near data, FP is null. For example,
|
||||
|
||||
mov ax,FP[bx]
|
||||
|
||||
assembles as
|
||||
|
||||
mov ax,es:[bx]
|
||||
|
||||
in compact, large, and huge memory models, but as
|
||||
|
||||
mov ax,[bx]
|
||||
|
||||
in small and medium models.
|
||||
|
||||
pLes register,address
|
||||
pLds register,address
|
||||
|
||||
Loads a pointer from the specified address to the specified
|
||||
register. If the memory model uses far data, the segment
|
||||
portion of the address will be moved into ES or DS, depending
|
||||
on the macro used. For example,
|
||||
|
||||
pLes bx,arg1
|
||||
|
||||
is assembled as
|
||||
|
||||
les bx,arg1
|
||||
|
||||
in compact, large, and huge memory models, but as
|
||||
|
||||
mov bx,arg1
|
||||
|
||||
in small and medium models.
|
||||
|
||||
Notes
|
||||
|
||||
The macros in MIXED.INC have several limitations:
|
||||
|
||||
1. The memory model must be set at the start of the source
|
||||
file before any mixed-language macros are used. The model
|
||||
can be set with the .MODEL directive or with the "setModel"
|
||||
macro. For example, start with
|
||||
|
||||
INCLUDE mix.inc
|
||||
.MODEL small
|
||||
|
||||
or with
|
||||
|
||||
model EQU <small> ; Or pass small from command line
|
||||
INCLUDE mix.inc
|
||||
setModel
|
||||
|
||||
The mixed-language macros only work with simplified segment
|
||||
directives. You cannot use them with full segment definitions.
|
||||
|
||||
2. If the C calling convention is used, the symbol "cLang"
|
||||
must be defined before the start of a procedure. For
|
||||
example, define the symbol in the source file with the line
|
||||
|
||||
cLang = 1
|
||||
|
||||
or from the command line with the option
|
||||
|
||||
/DcLang
|
||||
|
||||
3. The macros do not automatically handle 80386 features such
|
||||
as 32-bit pointers.
|
||||
|
||||
4. All limitations and techniques described the Mixed-Language
|
||||
Programming Guide apply. For instance, you must save and
|
||||
restore the DS, SS, DI, and SI registers if your module
|
||||
modifies them. Return values should be passed back by
|
||||
placing them in AL, AX, or DX:AX before returning.
|
||||
|
||||
5. FORTRAN and Pascal require that the address for certain
|
||||
return values (such as real numbers or arrays) be passed as
|
||||
the last argument. The macros do not handle this situation,
|
||||
so the programmer must handle it specifically. An example
|
||||
is shown below:
|
||||
|
||||
hProc FuncFORTRAN,Arg1,Arg2,RetPoint
|
||||
.
|
||||
.
|
||||
.
|
||||
mov RetPoint,bx ; Assume BX contains a pointer
|
||||
; to return value
|
||||
Return
|
||||
|
||||
6. The convenience of using the macros in MIXED.INC has a cost
|
||||
in slower assembly time.
|
||||
|
||||
Examples
|
||||
|
||||
The file POWER2.ASM contains a sample assembly module that is
|
||||
equivalent to the sample modules in BA.ASM, CA.ASM, FA.ASM, and
|
||||
PA.ASM. POWER2.ASM uses the macros in MIXED.INC and can be
|
||||
assembled from the command-line for any language or memory
|
||||
model. The module can be linked with the high-level-language
|
||||
modules created from BAMAIN.BAS, CAMAIN.C, FAMAIN.FOR, or
|
||||
PAMAIN.PAS. The command lines for default memory models are
|
||||
shown below for each language:
|
||||
|
||||
BASIC - CodeView symbolic data and medium model
|
||||
|
||||
MASM /ZI /Dmodel=medium power2;
|
||||
|
||||
C - Case sensitive, CodeView symbolic data, small model, and "cLang" defined
|
||||
|
||||
MASM /Mx /Zi /Dmodel=small /DcLang power2;
|
||||
|
||||
FORTRAN - CodeView symbolic data and large model
|
||||
|
||||
MASM /ZI /Dmodel=large power2;
|
||||
|
||||
Pascal - CodeView symbolic data and large model
|
||||
|
||||
MASM /ZI /Dmodel=large power2;
|
||||
|
BIN
Microsoft MASM v5/samples/M_AUTO.CV
Normal file
BIN
Microsoft MASM v5/samples/M_AUTO.CV
Normal file
Binary file not shown.
17
Microsoft MASM v5/samples/PA.ASM
Normal file
17
Microsoft MASM v5/samples/PA.ASM
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
.MODEL medium
|
||||
.CODE
|
||||
PUBLIC Power2
|
||||
Power2 PROC
|
||||
push bp ; Entry sequence - save old BP
|
||||
mov bp,sp ; Set stack framepointer
|
||||
|
||||
mov ax,[bp+8] ; Load Arg1 into AX
|
||||
mov cx,[bp+6] ; Load Arg2 into CX
|
||||
shl ax,cl ; AX = AX * (2 to power of CX)
|
||||
; Leave return value in AX
|
||||
|
||||
pop bp ; Restore old framepointer
|
||||
ret 4 ; Exit, and restore 4 bytes of args
|
||||
Power2 ENDP
|
||||
END
|
34
Microsoft MASM v5/samples/PACKING.LST
Normal file
34
Microsoft MASM v5/samples/PACKING.LST
Normal file
@ -0,0 +1,34 @@
|
||||
The following documentation pieces are provided with the Macro
|
||||
Assembler:
|
||||
|
||||
Macro Assembler Programmer's Guide
|
||||
Macro Assembler Reference
|
||||
CodeView and Utilities Guide
|
||||
Mixed-Language Programming Guide
|
||||
CodeView Keyboard Templates
|
||||
Old-style keyboard
|
||||
New-style keyboard
|
||||
|
||||
The following files are provided with the Macro Assembler:
|
||||
|
||||
Disk 1 Root Disk 1 \MIXED Disk 2 Root
|
||||
|
||||
WHAT.ASM BA.ASM PAGER.ASM
|
||||
RUNME.BAT CA.ASM SHOW.ASM
|
||||
SETUP.BAT FA.ASM DEMO.BAT
|
||||
SETUP2.BAT PA.ASM RUNME.BAT
|
||||
README.DOC POWER2.ASM E_AUTO.CV
|
||||
CREF.EXE BAMAIN.BAS M_AUTO.CV
|
||||
ERROUT.EXE CAMAIN.C Q_AUTO.CV
|
||||
EXEMOD.EXE FAMAIN.FOR U_AUTO.CV
|
||||
LIB.EXE PAMAIN.PAS W_AUTO.CV
|
||||
LINK.EXE MIXED.DOC CV.HLP
|
||||
MAKE.EXE MIXED.INC CV.EXE
|
||||
MASM.EXE EXEPACK.EXE
|
||||
SETENV.EXE SHOW.EXE
|
||||
SHOW.EXE WHAT.EXE
|
||||
WHAT.EXE MACRO.DOC
|
||||
PACKING.LST BIOS.INC
|
||||
\MIXED DOS.INC
|
||||
MOUSE.SYS
|
||||
|
433
Microsoft MASM v5/samples/PAGER.ASM
Normal file
433
Microsoft MASM v5/samples/PAGER.ASM
Normal file
@ -0,0 +1,433 @@
|
||||
PAGE 60,132
|
||||
.MODEL small
|
||||
.DATA
|
||||
EXTRN statatr:BYTE,scrnatr:BYTE,sbuffer:WORD,pbuffer:WORD
|
||||
EXTRN fsize:WORD,cell:WORD,statline:BYTE,linenum:WORD
|
||||
EXTRN rows:WORD,vidadr:WORD,cga:BYTE
|
||||
|
||||
.CODE
|
||||
PUBLIC Pager,isEGA
|
||||
|
||||
; Procedure Pager
|
||||
; Purpose Displays status and text lines
|
||||
; Input Stack variable: lines to scroll (negative up, positive down)
|
||||
; Global variables: "sbuffer", "pbuffer", "linenum"
|
||||
; Output To screen
|
||||
|
||||
Pager PROC
|
||||
push bp
|
||||
mov bp,sp
|
||||
|
||||
mov es,sbuffer ; Initialize buffer position
|
||||
mov di,pbuffer
|
||||
|
||||
mov cx,[bp+4] ; Get count argument
|
||||
mov ax,10 ; Search for linefeed
|
||||
|
||||
or cx,cx ; Argument 0?
|
||||
jg forward ; If above, forward
|
||||
jl backward ; If below, backward
|
||||
jmp SHORT show ; If equal, done
|
||||
|
||||
backward: call GoBack ; Adjust backward
|
||||
jmp SHORT show ; Show screen
|
||||
forward: call GoForwd ; Adjust forward
|
||||
|
||||
; Write line number to status line
|
||||
|
||||
show: cld ; Go forward
|
||||
push di
|
||||
push es
|
||||
push ds ; Load DS to ES
|
||||
pop es
|
||||
|
||||
; BinToStr (linenum,OFFSET statline[7])
|
||||
|
||||
push linenum ; Arg 1
|
||||
mov ax,OFFSET statline[7]
|
||||
push ax ; Arg 2
|
||||
call BinToStr ; Convert to string
|
||||
|
||||
; Fill in status line
|
||||
|
||||
mov cx,7 ; Seven spaces to fill
|
||||
sub cx,ax ; Subtract those already done
|
||||
mov al," " ; Fill with space
|
||||
rep stosb
|
||||
pop es
|
||||
|
||||
mov bl,statatr ; Load status attribute
|
||||
mov BYTE PTR cell[1],bl
|
||||
|
||||
; CellWrt (DS,OFFSET statline,0,cell)
|
||||
|
||||
push ds ; Arg 1
|
||||
mov ax,OFFSET statline ; Arg 2
|
||||
push ax
|
||||
sub ax,ax ; Arg 3
|
||||
push ax
|
||||
push cell ; Arg 4
|
||||
call CellWrt ; Write status line
|
||||
|
||||
pop di
|
||||
mov bl,scrnatr ; Load screen attribute
|
||||
mov BYTE PTR cell[1],bl
|
||||
mov si,di ; Update position
|
||||
mov cx,rows ; Lines per screen
|
||||
|
||||
show1: mov bx,rows ; Lines of text
|
||||
inc bx ; Adjust for 0
|
||||
sub bx,cx ; Calculate current row
|
||||
push cx ; Save line number
|
||||
|
||||
; CellWrt (sbuffer,position,line,cell)
|
||||
|
||||
push sbuffer ; Arg 1
|
||||
push si ; Arg 2
|
||||
push bx ; Arg 3
|
||||
push cell ; Arg 4
|
||||
call cellwrt ; Write line
|
||||
|
||||
push ss ; Restore DS from SS
|
||||
pop ds
|
||||
|
||||
pop cx ; Restore line number
|
||||
mov si,ax ; Get returned position
|
||||
|
||||
cmp ax,fsize ; Beyond end of file?
|
||||
jae fillout ; Yes? Fill screen with spaces
|
||||
loop show1 ; else next line
|
||||
jmp SHORT pagedone ; Get out if done
|
||||
|
||||
; Fill the rest with spaces
|
||||
|
||||
fillout: dec cx ; Adjust
|
||||
jcxz pagedone
|
||||
mov al,80 ; Columns times remaining lines
|
||||
mul cl
|
||||
|
||||
; CellFil (sbuffer,count,cell)
|
||||
|
||||
push sbuffer ; Arg 1
|
||||
push ax ; Arg 2
|
||||
push cell ; Arg 3
|
||||
call CellFil ; Fill screen with spaces
|
||||
|
||||
push ss ; Restore DS from SS
|
||||
pop ds
|
||||
|
||||
pagedone: pop bp
|
||||
ret 2
|
||||
Pager ENDP
|
||||
|
||||
; Procedure CellWrt (segment,offset,line,cell)
|
||||
; Purpose Writes a line to screen buffer
|
||||
; Input Stack variables: 1 - segment of line
|
||||
; 2 - offset
|
||||
; 3 - line number
|
||||
; 4 - attribute
|
||||
; Output Line to screen buffer
|
||||
|
||||
CellWrt PROC
|
||||
push bp
|
||||
mov bp,sp
|
||||
sub dx,dx ; Clear as flag for scan
|
||||
cmp cga,1 ; CGA?
|
||||
jne noscan
|
||||
mov dx,03DAh ; Load port #
|
||||
|
||||
noscan: mov es,vidadr ; Load screen buffer segment
|
||||
mov ds,[bp+10] ; Buffer segment
|
||||
mov si,[bp+8] ; Buffer position
|
||||
mov cx,80 ; Cells per row
|
||||
mov ax,[bp+6] ; Starting row
|
||||
mov bx,80*2 ; Bytes per row
|
||||
mul bl ; Figure columns per row
|
||||
mov di,ax ; Load as destination
|
||||
mov bx,di ; Save start for tab calculation
|
||||
mov ax,[bp+4] ; Attribute
|
||||
movechar: lodsb ; Get character
|
||||
cmp al,13 ; CR?
|
||||
je fillspc
|
||||
cmp al,9 ; Tab?
|
||||
jne notab
|
||||
call filltab ; Yes? fill with spaces
|
||||
jcxz nextline ; If beyond limit done
|
||||
jmp SHORT movechar
|
||||
|
||||
notab: or dx,dx ; CGA?
|
||||
je notab2
|
||||
call Retrace ; Yes? Write during retrace
|
||||
loop movechar
|
||||
jmp SHORT nextline
|
||||
|
||||
notab2: stosw ; Write
|
||||
loop movechar
|
||||
jmp SHORT nextline ; Done
|
||||
|
||||
fillspc: mov al," " ; Fill with space
|
||||
|
||||
or dx,dx ; CGA?
|
||||
je space2
|
||||
space1: call Retrace ; Yes? Write during retrace
|
||||
loop space1
|
||||
inc si ; Adjust
|
||||
jmp SHORT exit ; Done
|
||||
|
||||
space2: rep stosw ; Write
|
||||
inc si ; Adjust for LF
|
||||
jmp SHORT exit ; Done
|
||||
|
||||
nextline: mov ah,10 ; Search for next line feed
|
||||
chklf: lodsb ; Load and compare
|
||||
cmp al,ah
|
||||
loopne chklf
|
||||
|
||||
exit: mov ax,si ; Return position
|
||||
pop bp
|
||||
ret 8
|
||||
CellWrt ENDP
|
||||
|
||||
; Procedure CellFil (segment,count,cell)
|
||||
; Purpose Fills screen with character
|
||||
; Input Stack variables: 1 - segment of text (offset 0)
|
||||
; 2 - number of characters
|
||||
; 3 - attribute and character
|
||||
; Output Characters to screen buffer
|
||||
|
||||
CellFil PROC
|
||||
push bp
|
||||
mov bp,sp
|
||||
sub dx,dx ; Clear as flag for scan
|
||||
cmp cga,1 ; CGA?
|
||||
jne noscan2
|
||||
mov dx,03DAh ; Load port #
|
||||
|
||||
noscan2: mov es,vidadr ; Load screen buffer segment
|
||||
mov ds,[bp+8] ; Buffer segment (position 0)
|
||||
mov cx,[bp+6] ; Characters to fill
|
||||
mov ax,[bp+4] ; Attribute
|
||||
or dx,dx ; CGA?
|
||||
je fillem2
|
||||
fillem1: call Retrace ; Yes? Write during retrace
|
||||
loop fillem1
|
||||
jmp SHORT filled ; Done
|
||||
fillem2: rep stosw ; Write
|
||||
|
||||
filled: pop bp
|
||||
ret 6
|
||||
CellFil ENDP
|
||||
|
||||
; Procedure FillTab
|
||||
; Purpose Writes spaces for tab to screen
|
||||
; Input BX points to start of line, DI points to current position
|
||||
; Output Spaces to screen buffer
|
||||
|
||||
FillTab PROC
|
||||
push bx
|
||||
push cx
|
||||
|
||||
sub bx,di ; Get current position in line
|
||||
neg bx
|
||||
shr bx,1 ; Divide by 2 bytes per character
|
||||
|
||||
mov cx,8 ; Default count 8
|
||||
and bx,7 ; Get modulus
|
||||
sub cx,bx ; Subtract
|
||||
mov bx,cx ; Save modulus
|
||||
|
||||
mov al," " ; Spaces
|
||||
or dx,dx ; CGA?
|
||||
je tabem2
|
||||
|
||||
tabem1: call Retrace ; Yes? Write during retrace
|
||||
loop tabem1
|
||||
jmp SHORT tabbed
|
||||
tabem2: rep stosw ; Write
|
||||
|
||||
tabbed: pop cx
|
||||
sub cx,bx ; Adjust count
|
||||
jns nomore ; Make negative count 0
|
||||
sub cx,cx
|
||||
nomore: pop bx
|
||||
ret
|
||||
FillTab ENDP
|
||||
|
||||
; Procedure GoBack
|
||||
; Purpose Searches backward through buffer
|
||||
; Input CX has number of lines; ES:DI has buffer position
|
||||
; Output Updates "linenum" and "pbuffer"
|
||||
|
||||
GoBack PROC
|
||||
std ; Go backward
|
||||
neg cx ; Make count positive
|
||||
mov dx,cx ; Save a copy
|
||||
inc cx ; One extra to go up one
|
||||
or di,di ; Start of file?
|
||||
je exback ; If so, ignore
|
||||
findb: push cx ; else save count
|
||||
mov cx,0FFh ; Load maximum character count
|
||||
cmp cx,di ; Near start of buffer?
|
||||
jl notnear ; No? Continue
|
||||
mov cx,di ; else search only to start
|
||||
notnear: repne scasb ; Find last previous LF
|
||||
jcxz atstart ; If not found, must be at start
|
||||
pop cx
|
||||
loop findb
|
||||
cmp linenum,0FFFFh ; End of file flag?
|
||||
jne notend ; No? Continue
|
||||
add di,2 ; Adjust for cr/lf
|
||||
mov pbuffer,di ; Save position
|
||||
call EndCount ; Count back to get line number
|
||||
ret
|
||||
|
||||
notend: sub linenum,dx ; Calculate line number
|
||||
jg positive
|
||||
mov linenum,1 ; Set to 1 if negative
|
||||
positive: add di,2 ; Adjust for cr/lf
|
||||
mov pbuffer,di ; Save position
|
||||
ret
|
||||
|
||||
atstart: pop cx
|
||||
sub di,di ; Load start of file
|
||||
mov linenum,1 ; Line 1
|
||||
mov pbuffer,di ; Save position
|
||||
exback: ret
|
||||
GoBack ENDP
|
||||
|
||||
; Procedure GoForwd
|
||||
; Purpose Searches forward through a buffer
|
||||
; Input CX has number of lines; ES:DI has buffer position
|
||||
; Output Updates "linenum" and "pbuffer"
|
||||
|
||||
GoForwd PROC
|
||||
cld ; Go forward
|
||||
mov dx,cx ; Copy count
|
||||
findf: push cx ; Save count
|
||||
mov cx,0FFh ; Load maximum character count
|
||||
repne scasb ; Find next LF
|
||||
jcxz atend ; If not found, must be at end
|
||||
cmp di,fsize ; Beyond end?
|
||||
jae atend
|
||||
pop cx
|
||||
loop findf
|
||||
add linenum,dx ; Calulate line number
|
||||
mov pbuffer,di ; Save position
|
||||
ret
|
||||
|
||||
atend: pop cx
|
||||
mov di,pbuffer ; Restore position
|
||||
ret
|
||||
GoForwd ENDP
|
||||
|
||||
; Procedure EndCount
|
||||
; Purpose Counts backward to count lines in file
|
||||
; Input ES:DI has buffer position
|
||||
; Output Modifies "linenum"
|
||||
|
||||
EndCount PROC
|
||||
push di
|
||||
|
||||
mov al,13 ; Search for CR
|
||||
mov linenum,0 ; Initialize
|
||||
|
||||
findstrt: inc linenum ; Adjust count
|
||||
mov cx,0FFh ; Load maximum character count
|
||||
cmp cx,di ; Near start of buffer?
|
||||
jl notnear2 ; No? Continue
|
||||
mov cx,di ; else search only to start
|
||||
notnear2: repne scasb ; Find last previous cr
|
||||
jcxz found ; If not found, must be at start
|
||||
jmp SHORT findstrt
|
||||
|
||||
found: pop di
|
||||
ret
|
||||
EndCount ENDP
|
||||
|
||||
; Procedure isEGA
|
||||
; Purpose Determines if an EGA is active
|
||||
; Input None
|
||||
; Output 0 if no; lines per screen if yes
|
||||
|
||||
isEGA PROC
|
||||
push bp
|
||||
push es
|
||||
mov ah,12h ; Call EGA status function
|
||||
mov bl,10h
|
||||
sub cx,cx ; Clear status bits
|
||||
int 10h
|
||||
sub ax,ax ; Segment 0 and assume no EGA
|
||||
jcxz noega ; If status still clear, no EGA
|
||||
|
||||
mov es,ax ; ES=0
|
||||
test BYTE PTR es:[487h],1000b ; Test active bit
|
||||
jnz noega ; If set, not active
|
||||
mov ax,1130h ; Get EGA information
|
||||
int 10h
|
||||
mov al,dl ; Return lines per screen
|
||||
cbw
|
||||
|
||||
noega: pop es
|
||||
pop bp
|
||||
ret
|
||||
isEGA ENDP
|
||||
|
||||
; Procedure BinToStr (number,address)
|
||||
; Purpose Converts integer to string
|
||||
; Input Stack arguments: 1 - Number to convert; 2 - Near address for write
|
||||
; Output AX has characters written
|
||||
|
||||
BinToStr PROC
|
||||
push bp
|
||||
mov bp,sp
|
||||
mov ax,[bp+6] ; Arg 1
|
||||
mov di,[bp+4] ; Arg 2
|
||||
|
||||
sub cx,cx ; Clear counter
|
||||
mov bx,10 ; Divide by 10
|
||||
|
||||
; Convert and save on stack backwards
|
||||
|
||||
getdigit: sub dx,dx ; Clear top
|
||||
div bx ; Divide to get last digit as remainder
|
||||
add dl,"0" ; Convert to ASCII
|
||||
push dx ; Save on stack
|
||||
or ax,ax ; Quotient 0?
|
||||
loopnz getdigit ; No? Get another
|
||||
|
||||
; Take off the stack and store forward
|
||||
|
||||
neg cx ; Negate and save count
|
||||
mov dx,cx
|
||||
putdigit: pop ax ; Get character
|
||||
stosb ; Store it
|
||||
loop putdigit
|
||||
mov ax,dx ; Return digit count
|
||||
|
||||
pop bp
|
||||
ret 4
|
||||
BinToStr ENDP
|
||||
|
||||
; Procedure Retrace
|
||||
; Purpose Writes cell during horizontal retrace (CGA)
|
||||
; Input ES:DI has screen buffer position, AX has cell
|
||||
; Output Character to screen buffer
|
||||
|
||||
Retrace PROC
|
||||
push bx
|
||||
mov bx,ax ; Save character
|
||||
lscan2: in al,dx ; Look in the port
|
||||
shr al,1 ; until it goes low
|
||||
jc lscan2
|
||||
cli
|
||||
hscan2: in al,dx ; Look in the port
|
||||
shr al,1 ; until it goes high
|
||||
jnc hscan2
|
||||
mov ax,bx ; Restore and write it
|
||||
stosw
|
||||
sti
|
||||
pop bx
|
||||
ret
|
||||
Retrace ENDP
|
||||
|
||||
END
|
63
Microsoft MASM v5/samples/POWER2.ASM
Normal file
63
Microsoft MASM v5/samples/POWER2.ASM
Normal file
@ -0,0 +1,63 @@
|
||||
; Default command line for BASIC: MASM /Dmodel=medium /DBASIC power2;
|
||||
; Default command line for C: MASM /MX /Dmodel=small /DcLang power2;
|
||||
; Default command line for FORTRAN: MASM /Dmodel=large /DFORTRAN power2;
|
||||
; Default command line for Pascal: MASM /Dmodel=large /DPascal power2;
|
||||
|
||||
INCLUDE mixed.inc
|
||||
setModel %model
|
||||
|
||||
IFDEF BASIC
|
||||
reference EQU 1
|
||||
ENDIF
|
||||
IFDEF FORTRAN
|
||||
reference EQU 1
|
||||
ENDIF
|
||||
|
||||
.CODE
|
||||
|
||||
; Function for C, FORTRAN, Pascal, Version 4 of QuickBASIC, and
|
||||
; future versions of Microsoft and IBM BASIC Compilers
|
||||
|
||||
IFDEF reference ; Pass by reference for BASIC or FORTRAN
|
||||
hProc Power2, Value:PTR, Count:PTR
|
||||
|
||||
pLes bx,Value ; Load arguments passed by reference
|
||||
mov ax,FP[bx]
|
||||
pLes bx,Count
|
||||
mov cx,FP[bx]
|
||||
|
||||
ELSE ; Pass by value for C or Pascal
|
||||
hProc Power2, Value, Count
|
||||
|
||||
mov ax,Value ; Load arguments passed by value
|
||||
mov cx,Count
|
||||
ENDIF
|
||||
|
||||
shl ax,cl ; AX = AX * (2 to power of CL)
|
||||
; Return result in AX
|
||||
hRet
|
||||
hEndp
|
||||
|
||||
IFDEF BASIC
|
||||
|
||||
; Subprogram for QuickBASIC, Versions 1, 2, and 3;
|
||||
; for the Microsoft BASIC Compiler through Version 5.36
|
||||
; for the IBM BASIC Compiler through Version 2.02
|
||||
|
||||
hProc Power2S, Value, Count, RetVal
|
||||
|
||||
pLes bx,Value ; Load BASIC arguments
|
||||
mov ax,FP[bx] ; passed by reference
|
||||
pLes bx,Count
|
||||
mov cx,FP[bx]
|
||||
|
||||
shl ax,cl ; AX = AX * (2 to power of CL)
|
||||
|
||||
pLes bx,RetVal ; Load return address
|
||||
mov FP[bx],ax ; and store result in it
|
||||
|
||||
hRet
|
||||
hEndp
|
||||
ENDIF ; BASIC
|
||||
END
|
||||
|
BIN
Microsoft MASM v5/samples/Q_AUTO.CV
Normal file
BIN
Microsoft MASM v5/samples/Q_AUTO.CV
Normal file
Binary file not shown.
270
Microsoft MASM v5/samples/README.DOC
Normal file
270
Microsoft MASM v5/samples/README.DOC
Normal file
@ -0,0 +1,270 @@
|
||||
Microsoft Macro Assembler Package
|
||||
Version 5.00
|
||||
|
||||
Text files on the Macro Assembler disks are tabbed to save
|
||||
disk space. If your printer does not automatically handle
|
||||
tabs during printing, you must use a print program that
|
||||
expands tabs. For example, use the DOS PRINT program to print
|
||||
this and other document or source files on the disk.
|
||||
|
||||
Note to DOS 3.0 Users
|
||||
|
||||
Because of an incompatibility between DOS 3.0 and the batch
|
||||
file enhancer on this disk, you cannot run the setup batch
|
||||
files under DOS 3.0. Instead, follow the setup instructions in
|
||||
Chapter 1 of the Programmer's Guide. You can run the CodeView
|
||||
demo on Disk 2. Type DEMO to run DEMO.BAT.
|
||||
|
||||
==( MASM.EXE )==
|
||||
|
||||
New Feature
|
||||
|
||||
The /LA option has been added to specify a complete listing
|
||||
of all symbols, macros, and false conditionals. It is
|
||||
equivalent to using the .LIST, .LFCOND, .LALL, and .CREF
|
||||
directives throughout the source file. The option overrides
|
||||
any conflicting directives in the source file.
|
||||
|
||||
Clarification
|
||||
|
||||
The PTR operator can be used to specify the size of a
|
||||
register indirect operand for a CALL or JMP instruction.
|
||||
However, the size cannot be specified with NEAR or FAR. Use
|
||||
WORD or DWORD instead. (In 80386 32-bit segments, use DWORD
|
||||
or FWORD.) Examples are shown below:
|
||||
|
||||
; 8086, 80826, or 80386 16-bit mode
|
||||
|
||||
jmp WORD PTR [bx] ; Legal near jump
|
||||
call NEAR PTR [bx] ; Illegal near call
|
||||
call DWORD PTR [bx] ; Legal far call
|
||||
jmp FAR PTR [bx] ; Illegal far jump
|
||||
|
||||
; 80386 32-bit mode only
|
||||
|
||||
jmp DWORD PTR [bx] ; Legal near jump
|
||||
call NEAR PTR [bx] ; Illegal near call
|
||||
call FWORD PTR [bx] ; Legal far call
|
||||
jmp FAR PTR [bx] ; Illegal far jump
|
||||
|
||||
This limitation only applies to register indirect operands.
|
||||
NEAR or FAR can be applied to operands associated with
|
||||
labels. Examples are shown below:
|
||||
|
||||
jmp NEAR PTR pointer[bx] ; Legal
|
||||
call FAR PTR location ; Legal
|
||||
|
||||
Correction
|
||||
|
||||
When evaluating expressions, MASM does 16-bit arithmetic except
|
||||
when the 80386 processor is enabled. If the .386 or .386P
|
||||
directive has been given, MASM does 32-bit arithmetic. This
|
||||
behavior is consistent with earlier versions of MASM, which
|
||||
always did 16-bit arithmetic. The notes in Sections 9.2.1 and
|
||||
9.2.1.5 of the Programmer's Guide are incorrect. They should say
|
||||
that MASM always does 16-bit arithmetic.
|
||||
|
||||
Clarification
|
||||
|
||||
The description of declaring external symbols in Section 8.2
|
||||
is incomplete and the example is incorrect. You cannot
|
||||
access the segment of an external far data variable with the
|
||||
@FARDATA equate. Instead you must use the SEG operator as
|
||||
shown below:
|
||||
|
||||
.FARDATA
|
||||
EXTRN fvar:WORD ; FAR variable in far data
|
||||
.CODE
|
||||
start: ASSUME es:SEG fvar ; Tell the assembler
|
||||
mov ax,SEG fvar ; Tell the processor
|
||||
mov es,ax
|
||||
|
||||
This is the same limitation described for communal variables
|
||||
in Section 8.4. The reason is that under the DOS segment
|
||||
conventions, multiple far data segments share the same name
|
||||
(FAR_DATA) and have private combine type. Segments with the
|
||||
same name can only be distinguished indirectly using the SEG
|
||||
operator.
|
||||
|
||||
Clarification
|
||||
|
||||
The .286P and .386P processor directives enable instructions
|
||||
that are normally used in systems programming. However,
|
||||
some of these instructions do not necessarily require that
|
||||
the processor be in privileged or protected mode.
|
||||
|
||||
Correction
|
||||
|
||||
Public absolute symbols must be declared during pass 1. This
|
||||
means that aliases for absolute symbols or other forward
|
||||
references to them will cause errors. For example, the
|
||||
following code generates an error:
|
||||
|
||||
PUBLIC lines
|
||||
lines EQU rows
|
||||
rows EQU 25
|
||||
|
||||
This behavior is different than in previous versions of MASM
|
||||
and contrary to the note in Section 8.1.
|
||||
|
||||
Behavior Change
|
||||
|
||||
Some errors and questionable practices that were ignored by
|
||||
earlier versions are now flagged as errors. As a result,
|
||||
existing source code may produce errors or warnings.
|
||||
The following are examples:
|
||||
|
||||
- Labels defined only during pass 1 will cause errors if
|
||||
used in expressions.
|
||||
- A CS assume that changes from pass 1 to pass 2 causes
|
||||
an error.
|
||||
- Constants are now checked for type overflow.
|
||||
- Reserved words used as labels produce warnings.
|
||||
- The OFFSET operator used with a constant causes an error.
|
||||
|
||||
==( CREF.EXE )==
|
||||
|
||||
New Feature
|
||||
|
||||
Cross-reference listing files created with CREF now have an
|
||||
additional symbol. A line number followed by + indicates
|
||||
that a symbol is modified at the given line. For example:
|
||||
|
||||
TST . . . . . . . . . . . . . . 134# 237 544+
|
||||
|
||||
The symbol TST is defined at line 134, used at line 237, and
|
||||
modified at line 544.
|
||||
|
||||
==( MASM.EXE and LINK.EXE )==
|
||||
|
||||
Clarification
|
||||
|
||||
The description of STACK combine type in Section 5.2.2.3
|
||||
does not explain how multiple initialized stack segments are
|
||||
combined. The total size of the stack is the total size of
|
||||
all stack definitions. LINK puts initialized data for each
|
||||
defined stack segment at the end of the stack. Data initialized
|
||||
in the last segment linked overrides data initialized in
|
||||
previoussegments. This behavior is usually not relevant, since
|
||||
most programs only define one stack of uninitialized data.
|
||||
Stack data cannot be initialized with simplified segment
|
||||
directives.
|
||||
|
||||
==( CodeView Debugger )==
|
||||
|
||||
New Feature
|
||||
|
||||
The /R option has been added to enable the CodeView debugger
|
||||
to use the debug registers (DR0, DR1, DR2, and DR3) of the
|
||||
80386 processor. The option is ignored if you do not have an
|
||||
80386 processor.
|
||||
|
||||
The display does not change to indicate that the debug
|
||||
registers are in use, but debugger operations with
|
||||
tracepoint or trace memory statements (but not with
|
||||
watchpoint statements) will be much faster. Any of the
|
||||
following conditions will prevent the debugger from using
|
||||
debug registers:
|
||||
|
||||
1) /E is used.
|
||||
2) More than four tracepoints are set.
|
||||
3) A tracepoint watches more than four bytes of memory.
|
||||
4) A watchpoint is set.
|
||||
|
||||
Clarification
|
||||
|
||||
The Pascal expression evaluator described in the CodeView
|
||||
and Utilities manual is not implemented in this version of
|
||||
the CodeView debugger. It will be implemented in the
|
||||
debugger supplied with the next version of Pascal, which
|
||||
will also produce executable files with CodeView symbolic
|
||||
information. Current versions of Pascal do not work with the
|
||||
CodeView debugger.
|
||||
|
||||
Clarification
|
||||
|
||||
Section 4.2, "FORTRAN Expressions," of the CodeView and
|
||||
Utilities manual should mention that FORTRAN relational
|
||||
operators do not work with string variables or constants.
|
||||
|
||||
Warning
|
||||
|
||||
Some versions of the GENOA EGA short card are incompatible
|
||||
with CodeView when used with a mouse. You can work around this
|
||||
problem by turning off the mouse with /M.
|
||||
|
||||
==( LINK.EXE )==
|
||||
|
||||
New Feature
|
||||
|
||||
The following new LINK message warns about a practice that is
|
||||
legal in real mode, but illegal in protected mode:
|
||||
|
||||
warning L4003: intersegment self-relative fixup at <position>
|
||||
|
||||
In assembly-language, the warning only occurs if the DOSSEG
|
||||
directive or /DOSSEG linker option is used. It indicates a
|
||||
16-bit jump to an address in another segment. For example,
|
||||
the following code produces the error:
|
||||
|
||||
_TEXT SEGMENT
|
||||
EXTRN doit:NEAR
|
||||
jmp _TEXT2:doit
|
||||
.
|
||||
.
|
||||
.
|
||||
_TEXT ENDS
|
||||
|
||||
_TEXT2 SEGMENT
|
||||
PUBLIC doit
|
||||
doit PROC NEAR
|
||||
.
|
||||
.
|
||||
.
|
||||
doit ENDP
|
||||
_TEXT2 ENDS
|
||||
|
||||
The warning usually indicates a fatal error in high-level-
|
||||
language programs. It can occur when the /NT option is used
|
||||
to compile a small-model C program.
|
||||
|
||||
==( Mixed-Languages Programming Guide )==
|
||||
|
||||
Clarification
|
||||
|
||||
Naming convention rules on page 10 are incomplete. If you
|
||||
combine BASIC with other high-level languages, avoid using
|
||||
symbolic names longer than eight characters. Pascal and C
|
||||
will recognize only the first eight characters, whereas
|
||||
BASIC will recognize more than eight characters.
|
||||
|
||||
Clarification
|
||||
|
||||
The example programs for BASIC in Chapter 6 will not work
|
||||
with QuickBASIC Versions 2.0 or 3.0. They will work if you
|
||||
rewrite the function as a subprogram, and omit the DECLARE
|
||||
statement. Functions and DECLARE statements will be supported
|
||||
in future versions of Microsoft BASIC compilers.
|
||||
|
||||
==( Macro Files )==
|
||||
|
||||
New Feature
|
||||
|
||||
Macro files have been added to the Macro Assembler package.
|
||||
The following files are provided:
|
||||
|
||||
MIXED.INC For defining assembler procedures
|
||||
that can be called from high-level
|
||||
languages
|
||||
|
||||
MIXED.DOC Documentation for the macros in
|
||||
MIXED.INC.
|
||||
|
||||
DOS.INC For calling common DOS interrupts
|
||||
|
||||
BIOS.INC For calling common BIOS interrupts
|
||||
used on IBM and IBM-compatible computers
|
||||
|
||||
MACRO.DOC Description, syntax, and reference
|
||||
for using the macros in DOS.INC and
|
||||
BIOS.INC.
|
BIN
Microsoft MASM v5/samples/RUNME.BAT
Normal file
BIN
Microsoft MASM v5/samples/RUNME.BAT
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/samples/SETUP.BAT
Normal file
BIN
Microsoft MASM v5/samples/SETUP.BAT
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/samples/SETUP2.BAT
Normal file
BIN
Microsoft MASM v5/samples/SETUP2.BAT
Normal file
Binary file not shown.
325
Microsoft MASM v5/samples/SHOW.ASM
Normal file
325
Microsoft MASM v5/samples/SHOW.ASM
Normal file
@ -0,0 +1,325 @@
|
||||
PAGE 60,132
|
||||
TITLE SHOW
|
||||
|
||||
; Program SHOW.ASM
|
||||
; Purpose Text file displayer
|
||||
; Input File name from command line or prompt
|
||||
; Output Display file to screen
|
||||
|
||||
DOSSEG
|
||||
.MODEL small
|
||||
|
||||
INCLUDE dos.inc
|
||||
INCLUDE bios.inc
|
||||
|
||||
.STACK 100h
|
||||
|
||||
.DATA
|
||||
|
||||
; Status line
|
||||
|
||||
PUBLIC statline,linenum
|
||||
statline DB " Line: "
|
||||
statfile DB " File: "
|
||||
stathelp DB " Quit: ESC Move: PGUP PGDN HOME END "
|
||||
linenum DW 1
|
||||
|
||||
; Variables for screen handling
|
||||
|
||||
PUBLIC cell,rows,columns,vidadr,statatr,scrnatr,cga
|
||||
cell LABEL WORD ; Cell (character and attribute)
|
||||
char DB " " ; Initialize to space
|
||||
attr DB ? ; Attribute
|
||||
|
||||
columns EQU 80 ; Number of columns
|
||||
rows DW 24 ; Number of rows - status line takes one more
|
||||
mode DB ? ; Initial mode
|
||||
pag DB ? ; Initial display page
|
||||
newvid DB 0 ; Video change flag
|
||||
cga DB 1 ; CGA flag - default yes
|
||||
|
||||
vidadr DW 0B800h ; Video buffer address - default CGA
|
||||
mono EQU 0B000h ; Monochrome address
|
||||
statatr DB 030h ; Color default - black on cyan
|
||||
bwstat EQU 070h ; B&W default - black on white
|
||||
scrnatr DB 017h ; Color default - white on blue
|
||||
bwscrn EQU 007h ; B&W default - white on black
|
||||
|
||||
; Variables for buffer and file handling
|
||||
|
||||
PUBLIC buffer,pbuffer,sbuffer,fsize,namebuf
|
||||
buffer LABEL DWORD
|
||||
pbuffer DW 0 ; Position in buffer (offset)
|
||||
sbuffer DW ? ; Base of buffer (segment)
|
||||
lbuffer DW ? ; Length of buffer
|
||||
fhandle DW ? ; Holds file handle on open
|
||||
fsize DW ? ; File size after dosopen
|
||||
|
||||
prompt DB 13,10,13,10,"Enter filename: $"
|
||||
prompt2 DB 13,10,"File problem. Try again? $"
|
||||
namebuf DB 66,?
|
||||
filename DB 66 DUP (0) ; Buffer for file name
|
||||
|
||||
err1 DB 13,10,"Must have DOS 2.0 or higher",13,10,"$"
|
||||
err2 DB 13,10,"File too big",13,10,"$"
|
||||
|
||||
; Call table
|
||||
|
||||
exkeys DB 71,72,73,79,80,81 ; Extended key codes
|
||||
lexkeys EQU $-exkeys ; Table of keys
|
||||
extable DW homek
|
||||
DW upk
|
||||
DW pgupk
|
||||
DW endk
|
||||
DW downk
|
||||
DW pgdnk
|
||||
DW nonek
|
||||
|
||||
.CODE
|
||||
EXTRN pager:PROC,isEGA:PROC ; Routines in other module
|
||||
start: mov ax,@DATA ; Initialize data segment
|
||||
mov ds,ax
|
||||
|
||||
cli ; Turn off interrupts
|
||||
mov ss,ax ; Make SS and
|
||||
mov sp,OFFSET STACK ; SP relative to DGROUP
|
||||
sti
|
||||
|
||||
; Adjust memory allocation
|
||||
|
||||
mov bx,sp ; Convert stack pointer to paragraphs
|
||||
mov cl,4 ; to get stack size
|
||||
shr bx,cl
|
||||
add ax,bx ; Add SS to get end of program
|
||||
mov bx,es ; Get start of program
|
||||
sub ax,bx ; Subtract start from end
|
||||
@ModBlok ax ; Release memory after program
|
||||
|
||||
; Allocate dynamic memory for file buffer
|
||||
|
||||
@GetBlok 0FFFh ; Try to allocate 64K
|
||||
mov sbuffer,ax ; Save buffer segment
|
||||
mov lbuffer,bx ; Save actual length allocated
|
||||
|
||||
; Check DOS
|
||||
|
||||
@GetVer ; Get DOS version
|
||||
cmp al,2 ; Requires DOS 2.0
|
||||
jge video
|
||||
@DispStr err1 ; else error and quit
|
||||
int 20h
|
||||
|
||||
; Adjust for current mode and and video adapter
|
||||
|
||||
video: call isEGA ; EGA (or VGA)?
|
||||
or ax,ax ; If 0 must be CGA or MA
|
||||
je modechk ; Leave default
|
||||
mov rows,ax ; Load rows
|
||||
dec cga ; Not CGA
|
||||
|
||||
modechk: @GetMode ; Get video mode
|
||||
mov mode,al ; Save initial mode and page
|
||||
mov pag,bh
|
||||
mov dl,al ; Work on copy
|
||||
cmp dl,7 ; Is it mono 7?
|
||||
je loadmono ; Yes? Set mono
|
||||
cmp dl,15 ; Is it mono 15?
|
||||
jne graphchk ; No? Check graphics
|
||||
loadmono: mov vidadr,mono ; Load mono address
|
||||
mov statatr,bwstat ; Set B&W defaults for status line
|
||||
mov scrnatr,bwscrn ; and screen background
|
||||
dec cga ; Not CGA
|
||||
cmp al,15 ; Is it mono 15?
|
||||
jne cmdchk ; No? Done
|
||||
mov dl,7 ; Yes? Set standard mono
|
||||
jmp SHORT chmode
|
||||
|
||||
graphchk: cmp dl,7 ; 7 or higher?
|
||||
jg color ; 8 to 14 are color (7 and 15 done)
|
||||
cmp dl,4 ; 4 or higher?
|
||||
jg bnw ; 5 and 6 are probably black and white
|
||||
je color ; 4 is color
|
||||
test dl,1 ; Even?
|
||||
jz bnw ; 0 and 2 are black and white
|
||||
color: ; 1 and 3 are color
|
||||
cmp dl,3 ; 3?
|
||||
je cmdchk ; Yes? Done
|
||||
mov dl,3 ; Change mode to 3
|
||||
jmp SHORT chmode
|
||||
|
||||
bnw: mov statatr,bwstat ; Set B&W defaults for status line
|
||||
mov scrnatr,bwscrn ; and screen background
|
||||
cmp dl,2 ; 2?
|
||||
je cmdchk ; Yes? Done
|
||||
mov dl,2 ; Make it 2
|
||||
|
||||
chmode: @SetMode dl ; Set video mode
|
||||
@SetPage 0 ; Set video page
|
||||
mov newvid,1 ; Set flag
|
||||
|
||||
; Try to open command line file
|
||||
|
||||
cmdchk: mov bl,es:[80h] ; Get length
|
||||
sub bh,bh
|
||||
mov WORD PTR es:[bx+81h],0; Convert to ASCIIZ
|
||||
push ds
|
||||
@OpenFil 82h,0,es ; Open argument
|
||||
pop ds
|
||||
jc getname ; If error, get from prompt
|
||||
mov fhandle,ax ; else save handle
|
||||
push ds
|
||||
@GetFirst 82h,,es ; Let DOS convert to file name
|
||||
pop ds
|
||||
jnc opened ; If OK file is open
|
||||
|
||||
; Prompt for file
|
||||
|
||||
getname: @DispStr prompt ; Prompt for file
|
||||
@GetStr namebuf,0 ; Get response as ASCIIZ
|
||||
@OpenFil filename,0 ; Try to open response
|
||||
jc badfile ; If successful, continue
|
||||
mov fhandle,ax ; Save handle
|
||||
@GetFirst filename ; Let DOS convert to file name
|
||||
jnc opened ; If OK, file is opened
|
||||
|
||||
badfile: @DispStr prompt2 ; else prompt to try again
|
||||
@GetKey 0,1,0
|
||||
and al,11011111b ; Convert key to uppercase
|
||||
cmp al,"Y" ; If yes,
|
||||
je getname ; try again
|
||||
jmp quit ; else quit
|
||||
|
||||
; Copy file name to status line
|
||||
|
||||
opened: mov si,9Eh ; Load FCB as as source
|
||||
mov di,OFFSET statfile[7] ; Load status line as destination
|
||||
mov al,es:[si] ; Load first byte
|
||||
inc si
|
||||
copy: mov [di],al ; Save and load bytes until 0
|
||||
inc di
|
||||
mov al,es:[si]
|
||||
inc si
|
||||
or al,al ; Check for 0
|
||||
loopne copy
|
||||
|
||||
; Check file size
|
||||
|
||||
@GetFilSz fhandle ; Get file size
|
||||
|
||||
or dx,dx ; Larger than 64K?
|
||||
jne big ; Yes? Too big
|
||||
mov fsize,ax ; Save file size
|
||||
mov cx,4 ; Convert to paragraphs
|
||||
shr ax,cl
|
||||
cmp ax,lbuffer ; Is it larger than buffer
|
||||
jle fileread ; No? Continue
|
||||
|
||||
big: @DispStr err2 ; else error
|
||||
@Exit 2
|
||||
|
||||
fileread: push ds
|
||||
@Read buffer,fsize,fhandle ; Read file
|
||||
pop ds
|
||||
jnc readok ; If no read error continue
|
||||
jmp getname ; else try again
|
||||
|
||||
; Search back for EOF marker and adjust if necessary
|
||||
|
||||
readok: mov di,ax ; Load file length
|
||||
push es ; Save ES and load buffer segment
|
||||
mov es,sbuffer
|
||||
std ; Look backward for 255 characters
|
||||
mov cx,0FFh
|
||||
mov al,1Ah ; Search for EOF marker
|
||||
repne scasb
|
||||
cld
|
||||
jcxz noeof ; If none, we're OK
|
||||
inc di ; else adjust and save file size
|
||||
mov fsize,di
|
||||
|
||||
noeof: pop es
|
||||
@SetCurPos 0,43 ; Turn off cursor by moving off screen
|
||||
|
||||
; Display first page
|
||||
|
||||
xor ax,ax ; Start at 0
|
||||
push ax
|
||||
firstpg: call pager
|
||||
|
||||
; Handle keys
|
||||
|
||||
nextkey: @GetKey 0,0,0 ; Get a key
|
||||
nextkey2: cmp al,0 ; Is it a null?
|
||||
je extended ; Yes? Must be extended code
|
||||
|
||||
cmp al,27 ; Is it ESCAPE?
|
||||
jne nextkey ; No? Ignore unknown command
|
||||
|
||||
quit: @ClosFil fhandle ; Yes? Close file
|
||||
@FreeBlok sbuffer ; Release buffer
|
||||
cmp newvid,1 ; Restore video?
|
||||
jne thatsall ; No?
|
||||
@SetMode mode ; Restore video mode, page, and cursor
|
||||
@SetPage pag
|
||||
thatsall: mov dx,rows ; Load last row and first column
|
||||
xchg dl,dh
|
||||
mov cx,dx ; Make row the same
|
||||
mov dl,79
|
||||
@Scroll 0 ; Clear last line
|
||||
sub dl,dl
|
||||
@SetCurPos ; Set cursor
|
||||
|
||||
@Exit 0 ; Quit
|
||||
|
||||
extended: @GetKey 0,0,0 ; Get extended code
|
||||
push es
|
||||
push ds ; Load DS into ES
|
||||
pop es
|
||||
mov di,OFFSET exkeys ; Load address and length of key list
|
||||
mov cx,lexkeys+1
|
||||
repne scasb ; Find position
|
||||
pop es
|
||||
sub di,(OFFSET exkeys)+1 ; Point to key
|
||||
shl di,1 ; Adjust pointer for word addresses
|
||||
call extable[di] ; Call procedure
|
||||
jmp nextkey
|
||||
|
||||
homek: mov pbuffer,0 ; HOME - set position to 0
|
||||
push pbuffer
|
||||
mov linenum,1
|
||||
call pager
|
||||
retn
|
||||
|
||||
upk: mov ax,-1 ; UP - scroll back 1 line
|
||||
push ax
|
||||
call pager
|
||||
retn
|
||||
|
||||
pgupk: mov ax,rows ; PGUP - Page back
|
||||
neg ax
|
||||
push ax
|
||||
call pager
|
||||
retn
|
||||
|
||||
endk: mov ax,fsize ; END - Get last byte of file
|
||||
mov pbuffer,ax ; Make it the file position
|
||||
mov linenum,-1 ; Set illegal line number as flag
|
||||
mov ax,rows ; Page back
|
||||
neg ax
|
||||
push ax
|
||||
call pager
|
||||
retn
|
||||
|
||||
downk: mov ax,1 ; DOWN - scroll forward 1 line
|
||||
push ax
|
||||
call pager
|
||||
retn
|
||||
|
||||
pgdnk: push rows ; PGDN - page forward
|
||||
call pager
|
||||
retn
|
||||
|
||||
nonek: retn ; Ignore unknown key
|
||||
|
||||
END start
|
||||
|
BIN
Microsoft MASM v5/samples/SHOW.EXE
Normal file
BIN
Microsoft MASM v5/samples/SHOW.EXE
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/samples/U_AUTO.CV
Normal file
BIN
Microsoft MASM v5/samples/U_AUTO.CV
Normal file
Binary file not shown.
793
Microsoft MASM v5/samples/WHAT.ASM
Normal file
793
Microsoft MASM v5/samples/WHAT.ASM
Normal file
@ -0,0 +1,793 @@
|
||||
TITLE WHAT
|
||||
|
||||
; Program WHAT.ASM
|
||||
; Purpose Batch file enhancer
|
||||
; Input Command line consisting of:
|
||||
; Command letter (with optional E for extended)
|
||||
; Optional prompt enclosed in double quotes
|
||||
; Optional argument
|
||||
; Output Number in DOS ERRORLEVEL and string in WHAT environment variable
|
||||
|
||||
DOSSEG
|
||||
.MODEL small
|
||||
PAGE 60,120
|
||||
INCLUDE DOS.INC
|
||||
|
||||
.STACK 100h
|
||||
|
||||
.DATA
|
||||
help1 LABEL BYTE
|
||||
DB 13,10," WHAT - Batch file enhancer",13,10,13,10
|
||||
DB "Command Purpose Argument Environ Exit Extended",13,10
|
||||
DB "--------- ------- -------- ------- ---- ------",13,10
|
||||
DB "C[E] [""prompt""] [chars] Get Allowable Character Character Echo",13,10
|
||||
DB " character characters",13,10,13,10
|
||||
DB "S[E] [""prompt""] Get string None String Length Echo",13,10,13,10
|
||||
DB "D[E] Check DOS None Major (Major*10) Minor",13,10
|
||||
DB " version +Minor version",13,10,13,10
|
||||
DB "E[E] Get environ None Bytes Bytes/10 10 bytes",13,10
|
||||
DB " bytes left bytes in exit",13,10,13,10
|
||||
DB "F[E] filespec Get file Filespec Kilobytes Ks/10Ks 10Ks in",13,10
|
||||
DB " size (255=directory) exit",13,10,13,10
|
||||
DB "K[E] [driveletter] Get disk Drive Kilobytes Ks/10Ks 10Ks in",13,10
|
||||
DB " space exit",13,10,13,10
|
||||
DB "Press a key to continue . . .$"
|
||||
help2 LABEL BYTE
|
||||
DB 13,"M[E] Check None Kilobytes Ks/10Ks 10Ks in",13,10
|
||||
DB " memory exit",13,10,13,10
|
||||
DB "P Check for None 1=yes,0=no 1=yes,0=no None",13,10
|
||||
DB " printer",13,10,13,10
|
||||
DB "V [number] Get/Set New mode Current or Current or None",13,10
|
||||
DB " video mode last mode last mode",13,10,13,10
|
||||
DB "7 Check for None 1=yes,0=no 1=yes,0=no None",13,10
|
||||
DB " coprocessor",13,10,13,10
|
||||
DB "A Check for None 1=yes,0=no 1=yes,0=no None",13,10
|
||||
DB " ANSI driver",13,10,13,10
|
||||
DB "Y[E] Get current None Directory Level/Drive Drive",13,10
|
||||
DB " directory",13,10,"$"
|
||||
|
||||
guess DB 80 ; Prompt for string
|
||||
actual DB ?
|
||||
string DB 80 DUP (0)
|
||||
|
||||
extend DB 0 ; Flag for extended command
|
||||
vid DB 3 ; Video mode
|
||||
ans DB 27,"[6n$" ; ANSI string to get current position
|
||||
overwrt DB 8,8,8,8," $"; Overwrite ANSI characters
|
||||
delete DB 8,8,8,"$" ; Delete ANSI characters
|
||||
|
||||
what DB "WHAT=" ; Variable name
|
||||
lwhat EQU $-what
|
||||
|
||||
prompt DW 0 ; Pointer to prompt
|
||||
lprompt DW 0 ; Length of prompt
|
||||
arg DW 0 ; Pointer to argument
|
||||
larg DW 0 ; Length of argument
|
||||
|
||||
; Command table
|
||||
|
||||
cmds DB "CSVDMEKFP7AY" ; Command character list
|
||||
lcmds EQU $-cmds ; and length of list
|
||||
EVEN
|
||||
table DW GetChar ; Command procedure table
|
||||
DW GetStr
|
||||
DW DoVid
|
||||
DW GetDOS
|
||||
DW GetMem
|
||||
DW GetEnvSz
|
||||
DW GetDskSz
|
||||
DW GetFilSz
|
||||
DW VeriPrint
|
||||
DW VeriCop
|
||||
DW VerAnsi
|
||||
DW GetDir
|
||||
DW NoCmd
|
||||
|
||||
err1 DB "Invalid command",7,13,10,"$"
|
||||
err2 DB "Out of environment space",7,13,10,"$"
|
||||
err3 DB "Must have DOS Version 2.0 or higher",7,13,10,"$"
|
||||
|
||||
.CODE
|
||||
start: mov ax,@DATA ; Starting execution address
|
||||
mov ds,ax ; Initialize data segment
|
||||
|
||||
@GetVer ; Get DOS version
|
||||
or al,al ; Is it 0?
|
||||
jne DOSOK ; No? Continue
|
||||
@DispStr err3 ; Yes? Quit for 1.x
|
||||
int 20h
|
||||
|
||||
DOSOK: mov si,83h ; Starting point in PSP
|
||||
mov ax,WORD PTR es:[5Dh] ; Load command characters
|
||||
cmp al,' ' ; Is it space?
|
||||
jne isarg ; If no argument, show help
|
||||
call Help
|
||||
|
||||
isarg: cmp ah,'E' ; Extend flag?
|
||||
jne noextend ; No? Continue
|
||||
inc extend ; Yes? Turn on flag and adjust pointer
|
||||
inc si
|
||||
|
||||
noextend: call GetArg ; Get argument from command line
|
||||
|
||||
push es ; Save and load DS into ES
|
||||
mov bx,ds
|
||||
mov es,bx
|
||||
mov di,OFFSET cmds ; Load pointer to command table
|
||||
mov cx,lcmds+1 ; Load length
|
||||
repne scasb ; Find position of command character
|
||||
pop es
|
||||
sub di,(OFFSET cmds)+1 ; Point to procedure
|
||||
shl di,1 ; Adjust for word addresses
|
||||
call table[di] ; Call the selected procedure
|
||||
|
||||
push ax ; Save
|
||||
push es
|
||||
call DoEnviron ; Put result in environment string
|
||||
or ax,ax ; Test for 0 before
|
||||
pop es ; restore
|
||||
pop ax
|
||||
jz done
|
||||
|
||||
cmp BYTE PTR es:[5Dh],'E' ; Is it Environment command
|
||||
je done ; Yes? Skip message
|
||||
|
||||
error2: @DispStr err2 ; Error message
|
||||
|
||||
done: @Exit ; Quit with AL as return code
|
||||
|
||||
; End of program - Start of procedures
|
||||
|
||||
; Procedure GetChar
|
||||
; Purpose Get a character from user
|
||||
; Input Allowable characters pointed to by "arg" (optional)
|
||||
; Prompt pointed to by "prompt" (optional)
|
||||
; Output Character in AX and in "string"
|
||||
|
||||
GetChar PROC
|
||||
|
||||
call ShowPrmpt ; Display prompt if there is one
|
||||
|
||||
readkey: @GetKey 0,1 ; Get a key
|
||||
cmp al,13 ; Is it carriage return?
|
||||
jne notcr ; Yes? Continue
|
||||
mov al,"~" ; Call it tilde
|
||||
; (use tilde in character list
|
||||
; if you want to accept CR)
|
||||
notcr: or al,al ; Is it 0 for extended key?
|
||||
je exkey ; Special case
|
||||
|
||||
mov bl,al ; Save a copy and swap
|
||||
xchg ah,al
|
||||
|
||||
call UpCase ; Uppercase it
|
||||
|
||||
xchg ah,al ; Swap back
|
||||
mov si,arg ; Load pointer and length of argument
|
||||
mov cx,larg
|
||||
jcxz gotchar ; If no argument, quit early
|
||||
|
||||
; Compare character to argument to see if it's valid
|
||||
|
||||
argcheck: mov ah,BYTE PTR es:[si] ; Get character
|
||||
inc si ; Increment index
|
||||
|
||||
call UpCase ; Convert to uppercase
|
||||
|
||||
cmp ah,al ; Is it in argument?
|
||||
je gotchar ; Yes? We're done
|
||||
loop argcheck ; else check another
|
||||
@DispCh 7 ; Checked all, so ring bell
|
||||
jmp SHORT readkey ; and get another character
|
||||
|
||||
gotchar: push ax
|
||||
cmp extend,0 ; Is extend flag set?
|
||||
jne noecho ; Yes? Don't echo
|
||||
cmp bl,"~" ; Don't echo ~ (alias for CR)
|
||||
je noecho
|
||||
@DispCh bl ; Display valid character
|
||||
noecho: pop ax
|
||||
mov string,al ; Put the character in string
|
||||
inc actual ; Length is one
|
||||
ret
|
||||
|
||||
exkey: @GetKey 0,1 ; Get second key in AL
|
||||
mov si,arg ; Load pointer to argument
|
||||
cmp BYTE PTR es:[si],"`" ; Is argument grave accent?
|
||||
; (use grave in character list if
|
||||
; you want to accept extended keys)
|
||||
je gotext ; Yes? Extended character
|
||||
@DispCh 7 ; No? Illegal, so ring bell
|
||||
jmp SHORT readkey ; and get another
|
||||
gotext: mov string[0],'0' ; Extended flag value is "0<char>"
|
||||
mov string[1],al
|
||||
mov actual,2 ; Length is 2
|
||||
|
||||
ret
|
||||
GetChar ENDP
|
||||
|
||||
; Procedure GetStr
|
||||
; Purpose Get a string
|
||||
; Input Prompt pointed to by prompt (optional)
|
||||
; Output String in "string"; length to AX
|
||||
|
||||
GetStr PROC
|
||||
|
||||
call ShowPrmpt ; Display prompt if there is one
|
||||
|
||||
cmp extend,1 ; Extend flag true?
|
||||
je password ; Yes? Then don't echo
|
||||
|
||||
@GetStr guess,0 ; Get string (null-terminated)
|
||||
jmp SHORT gotstr ; Done
|
||||
|
||||
password: mov bx,OFFSET string ; Load offset of string buffer
|
||||
mov cx,80 ; Maximum count
|
||||
nextkey: @GetKey 0,1 ; Get key, no echo
|
||||
cmp al,13 ; Is it carriage return
|
||||
je gotpass ; Yes? Done
|
||||
mov [bx],al ; No? Put key in buffer
|
||||
inc bx ; Point to next
|
||||
loop nextkey
|
||||
|
||||
gotpass: sub bx,OFFSET string ; Adjust pointer to get count
|
||||
mov actual,bl ; Save count
|
||||
|
||||
gotstr: @DispCh 13,10
|
||||
mov ax,bx ; Save string length
|
||||
ret
|
||||
GetStr ENDP
|
||||
|
||||
; Procedure GetDOS
|
||||
; Purpose Get DOS version
|
||||
; Input None
|
||||
; Output Major or minor version in "string"; (major *10)+minor in AX
|
||||
|
||||
GetDOS PROC
|
||||
@GetVer ; Get DOS version
|
||||
mov string,al ; Put major in string
|
||||
mov bh,al ; Save copy
|
||||
mov al,ah ; Divide minor to get one digit
|
||||
sub ah,ah ; Clear top
|
||||
mov cl,10 ; Divide by 10
|
||||
div cl
|
||||
xchg al,bh ; Exchange major and minor
|
||||
mul cl ; Multiply major by 10
|
||||
add al,bh ; (Major*10)+Minor - 3.2 is now 32
|
||||
cmp extend,1 ; Extend?
|
||||
jne gotver ; No? Already got it
|
||||
mov string,bh ; Save number
|
||||
gotver: mov actual,1 ; Save length 1
|
||||
add string,30h ; Convert to ASCII
|
||||
ret
|
||||
GetDOS ENDP
|
||||
|
||||
; Procedure GetEnvSz
|
||||
; Purpose Get environment bytes available
|
||||
; Input None
|
||||
; Output Environment bytes available
|
||||
|
||||
GetEnvSz PROC
|
||||
push es ; Save ES
|
||||
call GetEnv ; Get the environment size
|
||||
pop es ; Restore
|
||||
sub ax,cx ; Subtract length used from total
|
||||
; length to get length remaining
|
||||
call BinToDec ; Convert to string
|
||||
call Byticize ; Handle values too large for byte
|
||||
ret
|
||||
GetEnvSz ENDP
|
||||
|
||||
; Procedure GetFilSz
|
||||
; Purpose Get the size of a specified file
|
||||
; Input Filespec pointed to by "arg"
|
||||
; Output File size
|
||||
|
||||
GetFilSz PROC
|
||||
cmp arg,0 ; File name argument?
|
||||
jne isfile
|
||||
call NoCmd
|
||||
isfile: mov di,arg ; Point to start and end of arg
|
||||
mov bx,larg
|
||||
mov BYTE PTR es:[bx+di],0 ; Make null-terminated
|
||||
|
||||
push ds
|
||||
@OpenFil arg,0,es ; Open file for reading
|
||||
pop ds
|
||||
jc ferror ; Error if carry
|
||||
|
||||
notdir: @GetFilSz ax
|
||||
jc ferror ; Error if carry
|
||||
mov cx,1000 ; Convert to thousands
|
||||
div cx
|
||||
inc ax ; Round up
|
||||
jmp SHORT gotsize
|
||||
|
||||
ferror: cmp ax,5 ; Access denied? Probably a directory
|
||||
jne nofile ; No file or some other error
|
||||
mov ax,0FFh ; Call directory size 255
|
||||
jmp SHORT gotsize
|
||||
nofile: sub ax,ax ; Size of nothing is 0
|
||||
|
||||
gotsize: call BinToDec ; Convert to string
|
||||
call Byticize ; Handle large values
|
||||
ret
|
||||
GetFilSz ENDP
|
||||
|
||||
; Procedure GetDskSz
|
||||
; Purpose Get K remaining on specified disk
|
||||
; Input Drive letter pointed to by "arg"
|
||||
; Output Disk space remaining
|
||||
|
||||
GetDskSz PROC
|
||||
sub ax,ax ; Assume default drive
|
||||
cmp arg,0 ; Was there an argument?
|
||||
je defdrive ; No? Got drive
|
||||
mov al,BYTE PTR es:6Dh ; Yes? Get drive letter
|
||||
sub al,'A'-1 ; Convert to binary
|
||||
defdrive: @ChkDrv al ; Get disk space
|
||||
cmp ax,0FFFFh ; Is drive valid?
|
||||
jne valid
|
||||
call NoCmd
|
||||
valid: mul bx ; Sectors = sectors/cluster * clusters
|
||||
mul cx ; Bytes = bytes/sector * sectors
|
||||
mov cx,1000 ; Convert to thousand
|
||||
div cx
|
||||
inc ax ; Round up
|
||||
call BinToDec ; Convert to string
|
||||
call Byticize ; Handle large values
|
||||
|
||||
ret
|
||||
GetDskSz ENDP
|
||||
|
||||
; Procedure GetMem
|
||||
; Purpose Get memory available
|
||||
; Input None
|
||||
; Output Available memory
|
||||
|
||||
GetMem PROC
|
||||
int 12h ; Get memory available in K
|
||||
mov bx,es ; Get memory used
|
||||
mov cx,6 ; Convert to K
|
||||
shr bx,cl
|
||||
sub ax,bx ; Calculate how much is left
|
||||
sub dx,dx ; Clear DX
|
||||
mov cx,1024 ; Multiply to get bytes
|
||||
mul cx
|
||||
mov cx,1000 ; Divide to get thousands (not K)
|
||||
div cx
|
||||
call BinToDec ; Convert to string
|
||||
call Byticize ; Handle large values
|
||||
ret
|
||||
GetMem ENDP
|
||||
|
||||
; Procedure VeriPrint
|
||||
; Purpose See if LPT1 (PRN) is available
|
||||
; Input None
|
||||
; Output 1 for yes or 0 for no
|
||||
|
||||
VeriPrint PROC
|
||||
mov ax,200h ; Check printer status
|
||||
sub dx,dx ; for main parallel printer (port 0)
|
||||
int 17h
|
||||
xchg dx,ax ; Put 0 (for error) in AX
|
||||
test dh,00101001b ; Are any error bits on?
|
||||
jne printerr ; Yes? Leave 0
|
||||
test dh,10010000b ; Are both operation bits on?
|
||||
jz printerr ; No? Leave 0
|
||||
inc ax ; Yes? Return 1
|
||||
printerr: call BinToDec ; Convert to string
|
||||
ret
|
||||
VeriPrint ENDP
|
||||
|
||||
; Procedure DoVid
|
||||
; Purpose Get current video mode and optionally set a new mode
|
||||
; Input New video mode pointed to by "arg" (optional)
|
||||
; Output Current video mode (before change)
|
||||
|
||||
DoVid PROC
|
||||
mov ah,0Fh ; Get video mode
|
||||
int 10h
|
||||
|
||||
cmp larg,1 ; How many digits in mode?
|
||||
jl gotmode ; None? Get out
|
||||
push ax ; Some? Save mode
|
||||
mov bx,arg ; Load address of argument string
|
||||
mov ax,es:WORD PTR [bx] ; Get address of mode string
|
||||
je one ; One digit - skip the reverse
|
||||
xchg ah,al ; Reverse for two digits
|
||||
sub ax,'00' ; Adjust from ASCII to numeric
|
||||
aad ; Convert to binary
|
||||
jmp SHORT setmode
|
||||
one: sub al,'0' ; Convert to numeric
|
||||
setmode: sub ah,ah ; Set mode
|
||||
int 10h
|
||||
pop ax ; Restore
|
||||
gotmode: cbw ; Extend to AX
|
||||
call BinToDec ; Convert to string
|
||||
ret
|
||||
DoVid ENDP
|
||||
|
||||
; Procedure VeriCop
|
||||
; Purpose Check for coprocessor
|
||||
; Input None
|
||||
; Output 1 for yes or 0 for no
|
||||
|
||||
VeriCop PROC
|
||||
int 11h ; Check peripherals
|
||||
test al,10b ; Coprocessor
|
||||
mov ax,0 ; Assume no (don't change flags)
|
||||
jz no87 ; No? Done
|
||||
inc ax ; Yes? Set to 1
|
||||
no87: call BinToDec ; Convert to string
|
||||
ret
|
||||
VeriCop ENDP
|
||||
|
||||
; Procedure VerAnsi
|
||||
; Purpose Check for ANSI driver
|
||||
; Input None
|
||||
; Output 1 for yes or 0 for no
|
||||
|
||||
VerAnsi PROC
|
||||
|
||||
@DispStr ans ; Print ANSI string to get
|
||||
; cursor position
|
||||
mov ah,6 ; Check for key
|
||||
mov dl,0FFh ; in buffer
|
||||
int 21h
|
||||
jnz ansi ; Done if ANSI
|
||||
@DispStr overwrt ; Overwrite ANSI string
|
||||
sub ax,ax ; 0 if not ANSI
|
||||
jmp SHORT gotansi
|
||||
ansi: mov ax,0C06h ; Clear returned ANSI keys
|
||||
mov dl,0FFh ; out of buffer
|
||||
int 21h
|
||||
@DispStr delete ; Delete ANSI string
|
||||
mov ax,1 ; Set 1 for true
|
||||
gotansi: call BinToDec ; Convert to string
|
||||
ret
|
||||
VerAnsi ENDP
|
||||
|
||||
; Procedure GetDir
|
||||
; Purpose Get the current directory or drive
|
||||
; Input None
|
||||
; Output Current directory or drive in "string"; level or drive number in AX
|
||||
|
||||
GetDir PROC NEAR
|
||||
cmp extend,1 ; Extend flag true?
|
||||
jne directry ; No? Get directory
|
||||
|
||||
@GetDrv ; Yes? Get drive
|
||||
mov ah,al ; Copy
|
||||
add ah,'A' ; Convert to drive letter
|
||||
mov string,ah ; Put character in string
|
||||
inc actual ; Length 1
|
||||
cbw
|
||||
ret
|
||||
|
||||
directry: mov si,OFFSET string ; Load address for string
|
||||
mov BYTE PTR [si],"\" ; Insert backslash (DOS doesn't)
|
||||
inc si ; Point to next
|
||||
@GetDir si
|
||||
sub cx,cx ; Count is zero
|
||||
dec si ; Move pointer back to start
|
||||
findback: lodsb ; Load
|
||||
cmp al,"\" ; Is it backslash?
|
||||
jne notslash ; No? Continue
|
||||
inc dx ; Yes? Increment level counter
|
||||
notslash: or al,al ; Is it 0?
|
||||
loopne findback ; No? Repeat
|
||||
|
||||
neg cx ; Negate to get positive count
|
||||
mov actual,cl ; Put level in variable
|
||||
xchg ax,dx
|
||||
ret
|
||||
GetDir ENDP
|
||||
|
||||
; Procedure NoCmd
|
||||
; Purpose Return error for invalid command
|
||||
; Input None
|
||||
; Output None
|
||||
|
||||
NoCmd PROC
|
||||
@DispStr err1 ; Display error and quit
|
||||
@Exit 0
|
||||
NoCmd ENDP
|
||||
|
||||
; Procedure Byticize
|
||||
; Purpose Adjust word values to fit in a byte
|
||||
; Input Value in AX
|
||||
; Output 255 for word values, else value (no extend) or value*10 (extend)
|
||||
|
||||
Byticize PROC
|
||||
cmp extend,0 ; Is extend flag set?
|
||||
je sizechk ; No? Check size
|
||||
sub dx,dx ; Yes? Clear DX
|
||||
mov bx,10 ; Divide by 10 to get 10-unit chunks
|
||||
div bx
|
||||
|
||||
sizechk: or ah,ah ; Is it 255 or less?
|
||||
je byteOK
|
||||
mov al,0FFh ; No? Call it 255
|
||||
byteok: ret
|
||||
Byticize ENDP
|
||||
|
||||
; Procedure GetArg
|
||||
; Purpose Parse command line for argument and prompt strings
|
||||
; Input Command line
|
||||
; Output Pointer to argument in "arg"; length (or 0 if none) in "larg"
|
||||
; Pointer to prompt in "prompt"; length (or 0 if none) in "lprompt"
|
||||
|
||||
GetArg PROC
|
||||
push ax
|
||||
push es ; Swap ES and DS
|
||||
push ds
|
||||
pop es
|
||||
pop ds
|
||||
|
||||
white: lodsb ; Load while white space
|
||||
cmp al,' ' ; Is it space?
|
||||
je white ; Throw away
|
||||
cmp al,9 ; Is it tab?
|
||||
je white ; Throw away
|
||||
cmp al,'"' ; Is it quote?
|
||||
je promptit ; Process
|
||||
cmp al,13 ; Is it carriage return?
|
||||
je gotarg ; Done
|
||||
|
||||
sub cx,cx
|
||||
qdone: dec si ; Adjust
|
||||
mov es:arg,si ; Save pointer to argument start
|
||||
|
||||
chars: lodsb ; Load while not white
|
||||
cmp al,' ' ; Is it space?
|
||||
je nomore ; Done
|
||||
cmp al,9 ; Is it tab?
|
||||
je nomore ; Done
|
||||
cmp al,13 ; Is it carriage return?
|
||||
loopne chars ; Throw away
|
||||
nomore: not cx ; Adjust count
|
||||
mov es:larg,cx ; Save length
|
||||
jmp SHORT gotarg
|
||||
|
||||
promptit: mov di,si ; Save pointer to start
|
||||
sub cx,cx ; Clear count
|
||||
inprompt: lodsb ; Another
|
||||
cmp al,13 ; Is it carriage return?
|
||||
je oneq ; Yes? Treat one quote like character
|
||||
cmp al,'"' ; Is it quote?
|
||||
loopne inprompt ; No? Throw away
|
||||
mov es:prompt,di ; Save prompt pointer
|
||||
not cx
|
||||
mov es:lprompt,cx ; and length
|
||||
jmp SHORT white ; Get the argument
|
||||
|
||||
oneq: mov si,di ; Restore
|
||||
mov cx,-1 ; Set count to -1
|
||||
jmp SHORT qdone
|
||||
|
||||
gotarg: push es ; Swap ES and DS back
|
||||
push ds
|
||||
pop es
|
||||
pop ds
|
||||
|
||||
pop ax
|
||||
ret
|
||||
GetArg ENDP
|
||||
|
||||
; Procedure ShowPrmpt
|
||||
; Purpose If prompt, display it
|
||||
; Input Pointer to prompt
|
||||
; Output Prompt to screen
|
||||
|
||||
ShowPrmpt PROC
|
||||
cmp prompt,0 ; Is there a prompt?
|
||||
je noshow ; If not, continue
|
||||
push ds ; Save and restore DS
|
||||
@Write prompt,lprompt,,es ; DOS Write function
|
||||
pop ds
|
||||
|
||||
noshow: ret
|
||||
ShowPrmpt ENDP
|
||||
|
||||
; Procedure DoEnviron
|
||||
; Purpose Convert a string to an environment variable
|
||||
; Input String in "string"
|
||||
; Output String in "WHAT" environment variable;
|
||||
; AX has 0 for success, nonzero for failure
|
||||
|
||||
DoEnviron PROC
|
||||
call GetEnv ; Get environment size, length, address
|
||||
mov dx,ax ; Save size and length
|
||||
mov bx,cx
|
||||
|
||||
; Find "WHAT="
|
||||
|
||||
sub di,di ; Point to start
|
||||
sub al,al ; Search for zero
|
||||
mov si, OFFSET what ; Point source at "WHAT="
|
||||
findwh: repne scasb ; Search
|
||||
cmp BYTE PTR es:[di],0 ; If double null, end of environment
|
||||
je gotend
|
||||
jcxz noroom ; Error if not found
|
||||
push di ; Save
|
||||
push cx
|
||||
mov si,OFFSET what ; Load address and length of "what"
|
||||
mov cx,lwhat ; for comparison
|
||||
repe cmpsb ; Compare
|
||||
mov si,di ; Make copy
|
||||
pop cx ; Restore
|
||||
pop di
|
||||
jnz findwh
|
||||
|
||||
; Find end of "WHAT" variable
|
||||
|
||||
xchg di,si
|
||||
repne scasb ; Find end of environment variable
|
||||
xchg si,di ; Point source to next variable
|
||||
|
||||
; Calculate characters left to write
|
||||
|
||||
mov cx,bx ; Load total characters
|
||||
sub cx,si ; Subtract finished to get left
|
||||
|
||||
; Move everything back to overwrite "WHAT="
|
||||
|
||||
movenv: push ds ; Save DS
|
||||
mov ax,es ; Copy to ES
|
||||
mov ds,ax
|
||||
rep movsb ; Copy
|
||||
mov BYTE PTR es:[di],0 ; Put null at end in case of error
|
||||
pop ds ; Restore
|
||||
|
||||
; Check environment space
|
||||
|
||||
gotend: mov al,actual ; Load length of string
|
||||
sub ah,ah ; Clear top
|
||||
add ax,lwhat ; Add length of name
|
||||
add ax,di ; Add position to get final length
|
||||
cmp ax,dx ; Is it longer than environment?
|
||||
jge noroom ; Yes? Quit
|
||||
|
||||
; Put WHAT= at end
|
||||
|
||||
mov si,OFFSET what ; Load address and length of what
|
||||
mov cx,lwhat
|
||||
rep movsb
|
||||
|
||||
; Put new string at end
|
||||
|
||||
mov si,OFFSET string ; Load address and length of string
|
||||
mov cl,actual
|
||||
rep movsb
|
||||
mov WORD PTR es:[di],0 ; Put double null at end
|
||||
sub ax,ax ; Return 0 for success
|
||||
ret
|
||||
|
||||
noroom: inc ax ; Return nonzero for fail
|
||||
ret
|
||||
DoEnviron ENDP
|
||||
|
||||
; Procedure GetEnv
|
||||
; Purpose Find and measure the environment
|
||||
; Input None
|
||||
; Output Segment of environment in ES, size in AX, length in CX
|
||||
|
||||
GetEnv PROC
|
||||
mov dx,es:10h ; Load segment of COMMAND.COM
|
||||
mov es,dx ; into ES
|
||||
mov ax,es:2Ch ; Load COMMAND.COM's environment
|
||||
or ax,ax ; Is it 0?
|
||||
jnz secondry ; No? This is a secondary command
|
||||
; and we have its environment in AX
|
||||
dec dx ; Yes? This is original COMMAND.COM
|
||||
mov es,dx ; so point ES to paragraph before PSP
|
||||
add dx,es:03 ; Offset of environment is 3 bytes in
|
||||
add dx,2 ; Adjust it back to PSP
|
||||
mov ax,dx ; Put it in AX
|
||||
secondry:
|
||||
|
||||
; Note:
|
||||
; CodeView cannot debug the previous section of code, because the PSP
|
||||
; addresses checked by the code are those passed from DOS to CodeView,
|
||||
; not addresses passed from DOS to the program. To debug with CodeView,
|
||||
; find the actual address of the environment:
|
||||
|
||||
; S 500:0 L FFFF "COMSPEC="
|
||||
|
||||
; When you find the actual address, hard code it into your program:
|
||||
|
||||
; mov ax,110Ch ; Debug line
|
||||
|
||||
; Comment the line out for final assembly after debugging.
|
||||
|
||||
mov si,ax ; Save a copy
|
||||
sub dx,dx ; Clear DX for multiply
|
||||
dec ax ; Get paragaraph before environment
|
||||
mov es,ax ; Load into DS
|
||||
mov ax,es:03 ; Size in paragraphs is at byte 4
|
||||
mov cx,16 ; Multiply by 16
|
||||
mul cx
|
||||
mov es,si ; Restore environment address
|
||||
sub di,di ; Point to start
|
||||
mov cx,ax ; Load maximum count (size of
|
||||
mov bx,ax ; environment) and save a copy
|
||||
sub ax,ax ; Search for double null
|
||||
null2: repne scasb ; Look for null
|
||||
jz noerr ; If not out of space, continue
|
||||
sub ax,ax ; else error (return 0)
|
||||
jmp error2
|
||||
noerr: cmp BYTE PTR es:[di],0 ; Is it double null?
|
||||
jne null2 ; No? Look again
|
||||
mov cx,di ; Yes? Save length in CX
|
||||
mov ax,bx ; Reload size to AX
|
||||
|
||||
ret
|
||||
GetEnv ENDP
|
||||
|
||||
; Procedure BinToDec
|
||||
; Purpose Convert binary number in AX to string
|
||||
; Input Value in AX
|
||||
; Output Value string in "string"; length of string in "actual"
|
||||
|
||||
; AL contains number to be converted
|
||||
|
||||
BinToDec PROC
|
||||
push ax
|
||||
push es
|
||||
sub cx,cx ; Clear counter
|
||||
mov bx,10 ; Get ready to divide by 10
|
||||
|
||||
getdigit: sub dx,dx ; Clear top
|
||||
div bx ; Remainder is last digit
|
||||
add dl,'0' ; Convert to ASCII
|
||||
push dx ; Put on stack
|
||||
inc cx ; Count character
|
||||
or ax,ax ; Is quotient 0?
|
||||
jnz getdigit ; No? Get another
|
||||
|
||||
mov actual,cl ; Save number of digits
|
||||
mov ax,ds ; Load DS to ES
|
||||
mov es,ax
|
||||
mov di,OFFSET string ; Load source
|
||||
|
||||
putdigit: pop ax ; Get a digit off stack
|
||||
stosb ; Store it to string
|
||||
loop putdigit
|
||||
|
||||
pop es
|
||||
pop ax
|
||||
ret
|
||||
BinToDec ENDP
|
||||
|
||||
; Procedure UpCase
|
||||
; Purpose Convert a character to uppercase
|
||||
; Input Character in AH
|
||||
; Output Converted character in AH
|
||||
|
||||
UpCase PROC
|
||||
|
||||
cmp ah,"a" ; Is character below lowercase?
|
||||
jl ok ; If so, continue
|
||||
; else
|
||||
cmp ah,"z" ; Is character above lowercase?
|
||||
jg ok ; If so, continue
|
||||
; else
|
||||
sub ah,20h ; Make it lowercase
|
||||
ok: ret
|
||||
UpCase ENDP
|
||||
|
||||
; Procedure Help
|
||||
; Purpose Display syntax screens
|
||||
; Input None
|
||||
; Output Help to screen
|
||||
|
||||
Help PROC
|
||||
@DispStr help1 ; First screen
|
||||
@GetKey ; Pause
|
||||
@DispStr help2 ; Second screen
|
||||
@Exit 0
|
||||
Help ENDP
|
||||
|
||||
END start ; End assembly
|
||||
|
BIN
Microsoft MASM v5/samples/WHAT.EXE
Normal file
BIN
Microsoft MASM v5/samples/WHAT.EXE
Normal file
Binary file not shown.
BIN
Microsoft MASM v5/samples/W_AUTO.CV
Normal file
BIN
Microsoft MASM v5/samples/W_AUTO.CV
Normal file
Binary file not shown.
237
Microsoft MASM v5/sieve.asm
Normal file
237
Microsoft MASM v5/sieve.asm
Normal file
@ -0,0 +1,237 @@
|
||||
; 8086 assembly to compute e to n digits.
|
||||
; build with masm 5.0 like this:
|
||||
; ntvdm -h masm /Zi /Zd /z /l %1,,,;
|
||||
; ntvdm -h link %1,,%1,,nul.def
|
||||
; replicate this:
|
||||
; #define TRUE 1
|
||||
; #define FALSE 0
|
||||
; #define SIZE 8190
|
||||
;
|
||||
; char flags[SIZE+1];
|
||||
;
|
||||
; int main()
|
||||
; {
|
||||
; int i,k;
|
||||
; int prime,count,iter;
|
||||
;
|
||||
; for (iter = 1; iter <= 10; iter++) { /* do program 10 times */
|
||||
; count = 0; /* initialize prime counter */
|
||||
; for (i = 0; i <= SIZE; i++) /* set all flags true */
|
||||
; flags[i] = TRUE;
|
||||
; for (i = 0; i <= SIZE; i++) {
|
||||
; if (flags[i]) { /* found a prime */
|
||||
; prime = i + i + 3; /* twice index + 3 */
|
||||
; for (k = i + prime; k <= SIZE; k += prime)
|
||||
; flags[k] = FALSE; /* kill all multiples */
|
||||
; count++; /* primes found */
|
||||
; }
|
||||
; }
|
||||
; }
|
||||
; printf("%d primes.\n",count); /*primes found in 10th pass */
|
||||
; return 0;
|
||||
; }
|
||||
;
|
||||
|
||||
dosseg
|
||||
.model small
|
||||
.stack 100h
|
||||
|
||||
; DOS constants
|
||||
|
||||
dos_write_char equ 2h
|
||||
dos_realtime_clock equ 1ah
|
||||
dos_exit equ 4ch
|
||||
|
||||
; app constants
|
||||
|
||||
true equ 1
|
||||
false equ 0
|
||||
loops equ 10
|
||||
arraysize equ 8190
|
||||
|
||||
dataseg segment para public 'data'
|
||||
assume ds: dataseg
|
||||
|
||||
crlfmsg db 13,10,0
|
||||
primesmsg db ' primes.',13,10,0
|
||||
count dw 0
|
||||
ITER dw 0
|
||||
PKFLAGS dd 0
|
||||
|
||||
align 16
|
||||
flags db arraysize + 1 dup( ? )
|
||||
afterflags db 0
|
||||
dataseg ends
|
||||
|
||||
.code
|
||||
|
||||
start:
|
||||
mov ax, dataseg
|
||||
mov ds, ax
|
||||
mov cx, 0 ; handy place for 0
|
||||
mov di, offset afterFlags ; handy place for this constant
|
||||
|
||||
iteragain: ; for ( iter = 1; iter <= 10; iter++ )
|
||||
mov word ptr [ count ], 0 ; count = 0
|
||||
|
||||
; set all array entries to true: for (i = 0; i <= SIZE; i++) flags[i] = TRUE;
|
||||
xor bx, bx
|
||||
|
||||
nexttrue:
|
||||
mov byte ptr [ offset flags + bx ], true
|
||||
inc bx
|
||||
cmp bx, arraysize
|
||||
jle nexttrue
|
||||
|
||||
; iterate through array entries and count primes
|
||||
|
||||
xor bx, bx ; bx is "i" in the outer for loop
|
||||
|
||||
nextprime: ; for (i = 0; i <= SIZE; i++) {
|
||||
cmp byte ptr [ flags + bx ], 0
|
||||
jz flagisoff
|
||||
|
||||
mov ax, 3 ; ax == prime = i + i + 3
|
||||
add ax, bx
|
||||
add ax, bx
|
||||
mov si, offset flags
|
||||
add si, bx ; for (k = i + prime; k <= SIZE; k += prime)
|
||||
|
||||
kloop:
|
||||
add si, ax ; k += prime
|
||||
cmp si, di ; is si >= offset afterFlags?
|
||||
jge inccount
|
||||
|
||||
mov byte ptr [ si ], cl ; flags[ k ] = false. use cl for 0 because it's faster than an immediate
|
||||
jmp kloop
|
||||
|
||||
inccount:
|
||||
inc word ptr [ COUNT ] ; count++
|
||||
|
||||
flagisoff: ; check if outer loop is done
|
||||
inc bx
|
||||
cmp bx, arraysize + 1
|
||||
jnz nextprime
|
||||
|
||||
checknextiter: ; are we done iterating loops times?
|
||||
inc word ptr [ ITER ]
|
||||
cmp word ptr [ ITER ], loops
|
||||
jnz iteragain
|
||||
|
||||
mov ax, word ptr [COUNT]
|
||||
call printint
|
||||
|
||||
call printcrlf
|
||||
mov dx, offset primesmsg
|
||||
call printstring
|
||||
|
||||
mov al, 0
|
||||
mov ah, dos_exit
|
||||
int 21h
|
||||
;start endp
|
||||
|
||||
; print the integer in ax
|
||||
|
||||
printint proc near
|
||||
test ah, 80h
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push di
|
||||
push si
|
||||
|
||||
jz _prpositive
|
||||
neg ax ; just one instruction for complement + 1
|
||||
push ax
|
||||
mov dx, '-'
|
||||
mov ah, dos_write_char
|
||||
int 21h
|
||||
pop ax
|
||||
_prpositive:
|
||||
xor cx, cx
|
||||
xor dx, dx
|
||||
cmp ax, 0
|
||||
je _przero
|
||||
_prlabel1:
|
||||
cmp ax, 0
|
||||
je _prprint1
|
||||
mov bx, 10
|
||||
div bx
|
||||
push dx
|
||||
inc cx
|
||||
xor dx, dx
|
||||
jmp _prlabel1
|
||||
_prprint1:
|
||||
cmp cx, 0
|
||||
je _prexit
|
||||
pop dx
|
||||
add dx, 48
|
||||
mov ah, dos_write_char
|
||||
int 21h
|
||||
dec cx
|
||||
jmp _prprint1
|
||||
_przero:
|
||||
mov dx, '0'
|
||||
mov ah, dos_write_char
|
||||
int 21h
|
||||
_prexit:
|
||||
pop si
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
printint endp
|
||||
|
||||
printcrlf proc near
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push di
|
||||
push si
|
||||
mov dx, offset crlfmsg
|
||||
call printstring
|
||||
pop si
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
printcrlf endp
|
||||
|
||||
printstring proc near
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push di
|
||||
push si
|
||||
|
||||
mov di, dx
|
||||
|
||||
_psnext:
|
||||
mov al, byte ptr [ di ]
|
||||
cmp al, 0
|
||||
je _psdone
|
||||
mov dx, ax
|
||||
mov ah, dos_write_char
|
||||
int 21h
|
||||
|
||||
inc di
|
||||
jmp _psnext
|
||||
|
||||
_psdone:
|
||||
pop si
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
printstring endp
|
||||
|
||||
end
|
850
Microsoft MASM v5/ttt.asm
Normal file
850
Microsoft MASM v5/ttt.asm
Normal file
@ -0,0 +1,850 @@
|
||||
; 8086 version of app that proves you can't win at tic-tac-toe
|
||||
; build with masm 5.0 like this:
|
||||
; ntvdm -h masm /Zi /Zd /z /l %1,,,;
|
||||
; ntvdm -h link %1,,%1,,nul.def
|
||||
;
|
||||
; board position:
|
||||
; 0 1 2
|
||||
; 3 4 5
|
||||
; 6 7 8
|
||||
|
||||
dosseg
|
||||
.model small
|
||||
.stack 100h
|
||||
|
||||
; DOS constants
|
||||
|
||||
dos_write_char equ 2h
|
||||
dos_realtime_clock equ 1ah
|
||||
dos_exit equ 4ch
|
||||
|
||||
default_iterations equ 1 ; # of times to run (max 32767)
|
||||
max_score equ 9 ; maximum score
|
||||
min_score equ 2 ; minimum score
|
||||
win_score equ 6 ; winning score
|
||||
tie_score equ 5 ; tie score
|
||||
lose_score equ 4 ; losing score
|
||||
x_piece equ 1
|
||||
o_piece equ 2
|
||||
blank_piece equ 0
|
||||
|
||||
; arguments to minmax relative to bp/sp
|
||||
; space between locals and arguments:
|
||||
; 0-1 2 or 4 bytes for return pc if minmax is near or far (it's near here)
|
||||
; 2-3 2 bytes to save BP
|
||||
|
||||
alpha_offset equ 4
|
||||
beta_offset equ 6
|
||||
|
||||
dataseg segment para public 'data'
|
||||
assume ds: dataseg
|
||||
|
||||
crlfmsg db 13,10,0
|
||||
secondsmsg db ' seconds',13,10,0
|
||||
iterationsmsg db 'iterations: ',0
|
||||
zeroitersmsg db 'iterations argument must be 1..32767',13,10,0
|
||||
movesmsg db 'moves: ',0
|
||||
commaspmsg db ', ',0
|
||||
|
||||
align 16
|
||||
board db 0,0,0,0,0,0,0,0,0
|
||||
|
||||
align 2
|
||||
iters dw 0 ; iterations of running the app so far
|
||||
totaliters dw 0 ; # of iterations to run in total
|
||||
|
||||
align 4
|
||||
scratchpad dd 0
|
||||
starttime dd 0
|
||||
result dd 0
|
||||
|
||||
align 2
|
||||
winprocs dw proc0, proc1, proc2, proc3, proc4, proc5, proc6, proc7, proc8
|
||||
dataseg ends
|
||||
|
||||
.code
|
||||
|
||||
start:
|
||||
mov ax, dataseg
|
||||
mov ds, ax
|
||||
mov di, 0
|
||||
mov [ di + totaliters ], default_iterations
|
||||
xor ax, ax
|
||||
cmp al, byte ptr es: [ di + 128 ] ; command tail length is 128 bytes into the PSP
|
||||
jz done_with_arguments
|
||||
|
||||
mov cx, 129 ; string is guaranteed to be 0x0d terminated by DOS
|
||||
push ds
|
||||
mov ax, es ; temporarily make ds point to the psp
|
||||
mov ds, ax
|
||||
call atou ; pointer to string in cx, unsigned integer result in ax
|
||||
pop ds
|
||||
mov [ di + totaliters ], ax
|
||||
cmp ax, 0
|
||||
jnz done_with_arguments
|
||||
|
||||
mov dx, offset zeroitersmsg ; the argument isn't valid; show error and exit
|
||||
call printstring
|
||||
|
||||
mov al, 1
|
||||
mov ah, dos_exit
|
||||
int 21h
|
||||
|
||||
done_with_arguments:
|
||||
xor ax, ax
|
||||
int dos_realtime_clock
|
||||
mov word ptr [ starttime ], dx
|
||||
mov word ptr [ starttime + 2 ], cx
|
||||
|
||||
lea bx, [ board ] ; global board pointer
|
||||
xor ax, ax ; make sure ah is 0
|
||||
mov dx, ax ; make sure dh is 0
|
||||
|
||||
again:
|
||||
xor si, si ; zero the global move count so it doesn't overflow
|
||||
|
||||
; run for the 3 unique first moves
|
||||
|
||||
mov ax, 0
|
||||
call runmm
|
||||
mov ax, 1
|
||||
call runmm
|
||||
mov ax, 4
|
||||
call runmm
|
||||
|
||||
inc word ptr [ iters ]
|
||||
mov ax, [ totaliters ]
|
||||
cmp ax, [ iters ]
|
||||
jne again
|
||||
|
||||
push si ; save the global move count for later
|
||||
|
||||
call printelap
|
||||
mov dx, offset secondsmsg
|
||||
call printstring
|
||||
|
||||
mov dx, offset movesmsg
|
||||
call printstring
|
||||
|
||||
pop ax ; restore the global move count for printing
|
||||
call printint
|
||||
call printcrlf
|
||||
|
||||
mov dx, offset iterationsmsg
|
||||
call printstring
|
||||
|
||||
mov ax, [iters]
|
||||
call printint
|
||||
call printcrlf
|
||||
|
||||
mov al, 0
|
||||
mov ah, dos_exit
|
||||
int 21h
|
||||
;start endp
|
||||
|
||||
runmm proc near
|
||||
; make the first move
|
||||
mov di, ax
|
||||
push di
|
||||
mov byte ptr [ bx + di ], x_piece
|
||||
|
||||
; alpha and beta passed on the stack
|
||||
; current move in di
|
||||
; current value in dl
|
||||
; current depth in cx
|
||||
; global move count in si
|
||||
; global board pointer in bx
|
||||
; always 0 in ah and dh
|
||||
|
||||
xor cx, cx ; depth in cx
|
||||
mov al, max_score ; pushing constants didn't start until the 80186
|
||||
push ax ; beta
|
||||
mov al, min_score
|
||||
push ax ; alpha
|
||||
|
||||
call minmax_min
|
||||
|
||||
; restore the board at the first move position
|
||||
|
||||
pop di
|
||||
mov byte ptr [ bx + di ], blank_piece
|
||||
|
||||
ret
|
||||
runmm endp
|
||||
|
||||
minmax_max proc near
|
||||
inc si ; increment global move count
|
||||
|
||||
cmp cl, 4
|
||||
jl short _max_no_winner_check
|
||||
|
||||
shl di, 1
|
||||
mov al, o_piece
|
||||
call word ptr [ offset winprocs + di ]
|
||||
|
||||
cmp al, o_piece
|
||||
mov al, lose_score
|
||||
je short _max_just_return_al
|
||||
|
||||
_max_no_winner_check:
|
||||
push bp
|
||||
mov bp, sp ; set bp to the stack location
|
||||
|
||||
push dx ; save caller's value
|
||||
mov dl, min_score ; dx has value
|
||||
mov di, -1 ; di has the move 0..8
|
||||
inc cx ; increment global depth
|
||||
|
||||
_max_loop:
|
||||
cmp di, 8
|
||||
je short _max_load_value_return
|
||||
inc di
|
||||
|
||||
cmp byte ptr [ bx + di ], 0
|
||||
jnz short _max_loop
|
||||
|
||||
push di
|
||||
mov byte ptr [ bx + di ], x_piece
|
||||
|
||||
push [ bp + beta_offset ]
|
||||
push [ bp + alpha_offset ]
|
||||
|
||||
call minmax_min
|
||||
|
||||
pop di
|
||||
mov byte ptr [ bx + di ], 0
|
||||
|
||||
cmp al, win_score ; can't do better than winning
|
||||
je short _max_restore_value
|
||||
|
||||
cmp ax, dx ; compare score with value
|
||||
jle short _max_loop
|
||||
|
||||
cmp al, [ bp + beta_offset ] ; compare value with beta
|
||||
jge short _max_restore_value ; beta pruning
|
||||
|
||||
mov dx, ax ; update value with score
|
||||
cmp al, [ bp + alpha_offset ] ; compare value with alpha
|
||||
jle short _max_loop
|
||||
|
||||
mov [ bp + alpha_offset ], al ; update alpha with value
|
||||
jmp short _max_loop
|
||||
|
||||
_max_load_value_return:
|
||||
mov ax, dx
|
||||
|
||||
_max_restore_value:
|
||||
dec cx
|
||||
pop dx ; restore caller's value
|
||||
pop bp
|
||||
|
||||
_max_just_return_al:
|
||||
ret 4 ; cleanup stack space used for arguments
|
||||
minmax_max endp
|
||||
|
||||
minmax_min proc near
|
||||
inc si ; increment global move count
|
||||
|
||||
cmp cl, 4
|
||||
jl short _min_no_winner_check
|
||||
|
||||
shl di, 1
|
||||
mov al, x_piece
|
||||
call word ptr [ offset winprocs + di ]
|
||||
|
||||
cmp al, x_piece
|
||||
mov al, win_score
|
||||
je short _min_just_return_al
|
||||
|
||||
cmp cl, 8
|
||||
mov al, tie_score
|
||||
je short _min_just_return_al
|
||||
|
||||
_min_no_winner_check:
|
||||
push bp
|
||||
mov bp, sp ; set bp to the stack location
|
||||
|
||||
push dx ; save caller's value
|
||||
mov dl, max_score ; dx has value
|
||||
mov di, -1 ; di has the move 0..8
|
||||
inc cx ; increment global depth
|
||||
|
||||
_min_loop:
|
||||
cmp di, 8
|
||||
je short _min_load_value_return
|
||||
inc di
|
||||
|
||||
cmp byte ptr [ bx + di ], 0
|
||||
jne short _min_loop
|
||||
|
||||
push di
|
||||
mov byte ptr [ bx + di ], o_piece
|
||||
|
||||
push [ bp + beta_offset ]
|
||||
push [ bp + alpha_offset ]
|
||||
|
||||
call minmax_max
|
||||
|
||||
pop di
|
||||
mov byte ptr [ bx + di ], 0
|
||||
|
||||
cmp al, lose_score ; can't do better than losing
|
||||
je short _min_restore_value
|
||||
|
||||
cmp al, dl ; compare score with value
|
||||
jge short _min_loop
|
||||
|
||||
cmp al, [ bp + alpha_offset ] ; compare value with alpha
|
||||
jle short _min_restore_value ; alpha pruning
|
||||
|
||||
mov dx, ax ; update value with score
|
||||
cmp al, [ bp + beta_offset ] ; compare value with beta
|
||||
jge short _min_loop
|
||||
|
||||
mov [ bp + beta_offset ], al ; update beta with value
|
||||
jmp short _min_loop
|
||||
|
||||
_min_load_value_return:
|
||||
mov ax, dx
|
||||
|
||||
_min_restore_value:
|
||||
dec cx
|
||||
pop dx ; restore caller's value
|
||||
pop bp
|
||||
|
||||
_min_just_return_al:
|
||||
ret 4 ; cleanup stack space used for arguments
|
||||
minmax_min endp
|
||||
|
||||
IFDEF WinnerProc
|
||||
|
||||
; winner is no longer used since function pointers with the most recent move in ax are much faster
|
||||
|
||||
winner proc near
|
||||
xor al, al
|
||||
mov al, [ bx ]
|
||||
cmp al, 0
|
||||
je _win_check_3
|
||||
|
||||
cmp al, [ bx + 1 ]
|
||||
jne _win_check_0_b
|
||||
cmp al, [ bx + 2 ]
|
||||
jne _win_check_0_b
|
||||
ret
|
||||
|
||||
_win_check_0_b:
|
||||
cmp al, [ bx + 3 ]
|
||||
jne _win_check_3
|
||||
cmp al, [ bx + 6 ]
|
||||
jne _win_check_3
|
||||
ret
|
||||
|
||||
_win_check_3:
|
||||
mov al, [ bx + 3 ]
|
||||
cmp al, 0
|
||||
je _win_check_6
|
||||
|
||||
cmp al, [ bx + 4 ]
|
||||
jne _win_check_6
|
||||
cmp al, [ bx + 5 ]
|
||||
jne _win_check_6
|
||||
ret
|
||||
|
||||
_win_check_6:
|
||||
mov al, [ bx + 6 ]
|
||||
cmp al, 0
|
||||
je _win_check_1
|
||||
|
||||
cmp al, [ bx + 7 ]
|
||||
jne _win_check_1
|
||||
cmp al, [ bx + 8 ]
|
||||
jne _win_check_1
|
||||
ret
|
||||
|
||||
_win_check_1:
|
||||
mov al, [ bx + 1 ]
|
||||
cmp al, 0
|
||||
je _win_check_2
|
||||
|
||||
cmp al, [ bx + 4 ]
|
||||
jne _win_check_2
|
||||
cmp al, [ bx + 7 ]
|
||||
jne _win_check_2
|
||||
ret
|
||||
|
||||
_win_check_2:
|
||||
mov al, [ bx + 2 ]
|
||||
cmp al, 0
|
||||
je _win_check_4
|
||||
|
||||
cmp al, [ bx + 5 ]
|
||||
jne _win_check_4
|
||||
cmp al, [ bx + 8 ]
|
||||
jne _win_check_4
|
||||
ret
|
||||
|
||||
_win_check_4:
|
||||
mov al, [ bx + 4 ]
|
||||
cmp al, 0
|
||||
je _win_return
|
||||
|
||||
cmp al, [ bx ]
|
||||
jne _win_check_4_b
|
||||
cmp al, [ bx + 8 ]
|
||||
jne _win_check_4_b
|
||||
ret
|
||||
|
||||
_win_check_4_b:
|
||||
cmp al, [ bx + 2 ]
|
||||
jne _win_return_blank
|
||||
cmp al, [ bx + 6 ]
|
||||
je _win_return
|
||||
|
||||
_win_return_blank:
|
||||
xor al, al
|
||||
_win_return:
|
||||
ret
|
||||
winner endp
|
||||
|
||||
ENDIF ; WinnerProc
|
||||
|
||||
atou proc near ; string input in cx. unsigned 16-bit integer result in ax
|
||||
push di
|
||||
push bx
|
||||
push cx
|
||||
mov bx, 0 ; running total is in bx
|
||||
mov di, cx
|
||||
mov cx, 10
|
||||
|
||||
_skipspaces:
|
||||
cmp byte ptr [di ], ' '
|
||||
jne _atouNext
|
||||
inc di
|
||||
jmp _skipspaces
|
||||
|
||||
_atouNext:
|
||||
cmp byte ptr [ di ], '0' ; if not a digit, we're done. Works with null and 0x0d terminated strings
|
||||
jb _atouDone
|
||||
cmp byte ptr [ di ], '9' + 1
|
||||
jge _atouDone
|
||||
|
||||
mov ax, bx
|
||||
mul cx
|
||||
mov bx, ax
|
||||
|
||||
xor ah, ah
|
||||
mov al, byte ptr [ di ]
|
||||
sub ax, '0'
|
||||
add bx, ax
|
||||
inc di
|
||||
jmp _atouNext
|
||||
|
||||
_atouDone:
|
||||
mov ax, bx
|
||||
pop cx
|
||||
pop bx
|
||||
pop di
|
||||
ret
|
||||
atou endp
|
||||
|
||||
; print the integer in ax
|
||||
|
||||
printint proc near
|
||||
test ah, 80h
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push di
|
||||
push si
|
||||
|
||||
jz _prpositive
|
||||
neg ax ; just one instruction for complement + 1
|
||||
push ax
|
||||
mov dx, '-'
|
||||
mov ah, dos_write_char
|
||||
int 21h
|
||||
pop ax
|
||||
_prpositive:
|
||||
xor cx, cx
|
||||
xor dx, dx
|
||||
cmp ax, 0
|
||||
je _przero
|
||||
_prlabel1:
|
||||
cmp ax, 0
|
||||
je _prprint1
|
||||
mov bx, 10
|
||||
div bx
|
||||
push dx
|
||||
inc cx
|
||||
xor dx, dx
|
||||
jmp _prlabel1
|
||||
_prprint1:
|
||||
cmp cx, 0
|
||||
je _prexit
|
||||
pop dx
|
||||
add dx, 48
|
||||
mov ah, dos_write_char
|
||||
int 21h
|
||||
dec cx
|
||||
jmp _prprint1
|
||||
_przero:
|
||||
mov dx, '0'
|
||||
mov ah, dos_write_char
|
||||
int 21h
|
||||
_prexit:
|
||||
pop si
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
printint endp
|
||||
|
||||
printcrlf proc near
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push di
|
||||
push si
|
||||
mov dx, offset crlfmsg
|
||||
call printstring
|
||||
pop si
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
printcrlf endp
|
||||
|
||||
printcommasp proc near
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push di
|
||||
push si
|
||||
mov dx, offset commaspmsg
|
||||
call printstring
|
||||
pop si
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
printcommasp endp
|
||||
|
||||
prperiod proc near
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push di
|
||||
push si
|
||||
mov dx, '.'
|
||||
mov ah, dos_write_char
|
||||
int 21h
|
||||
pop si
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
prperiod endp
|
||||
|
||||
printelap proc near
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push di
|
||||
push si
|
||||
xor ax, ax
|
||||
int dos_realtime_clock
|
||||
mov word ptr [ scratchpad ], dx
|
||||
mov word ptr [ scratchpad + 2 ], cx
|
||||
mov dl, 0
|
||||
mov ax, word ptr [ scratchpad ]
|
||||
mov bx, word ptr [ starttime ]
|
||||
sub ax, bx
|
||||
mov word ptr [ result ], ax
|
||||
mov ax, word ptr [ scratchpad + 2 ]
|
||||
mov bx, word ptr [ starttime + 2 ]
|
||||
sbb ax, bx
|
||||
mov word ptr [ result + 2 ], ax
|
||||
mov dx, word ptr [ result + 2 ]
|
||||
mov ax, word ptr [ result ]
|
||||
mov bx, 10000
|
||||
mul bx
|
||||
mov bx, 18206
|
||||
div bx
|
||||
xor dx, dx
|
||||
mov bx, 10
|
||||
div bx
|
||||
push dx
|
||||
call printint
|
||||
call prperiod
|
||||
pop ax
|
||||
call printint
|
||||
pop si
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
printelap endp
|
||||
|
||||
printstring proc near
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push di
|
||||
push si
|
||||
|
||||
mov di, dx
|
||||
|
||||
_psnext:
|
||||
mov al, byte ptr [ di ]
|
||||
cmp al, 0
|
||||
je _psdone
|
||||
mov dx, ax
|
||||
mov ah, dos_write_char
|
||||
int 21h
|
||||
|
||||
inc di
|
||||
jmp _psnext
|
||||
|
||||
_psdone:
|
||||
pop si
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
printstring endp
|
||||
|
||||
align 2
|
||||
proc0 proc near
|
||||
cmp al, [bx + 1]
|
||||
jne short proc0_next_win
|
||||
cmp al, [bx + 2]
|
||||
je short proc0_yes
|
||||
|
||||
proc0_next_win:
|
||||
cmp al, [bx + 3]
|
||||
jne short proc0_next_win2
|
||||
cmp al, [bx + 6]
|
||||
je short proc0_yes
|
||||
|
||||
proc0_next_win2:
|
||||
cmp al, [bx + 4]
|
||||
jne short proc0_no
|
||||
cmp al, [bx + 8]
|
||||
je short proc0_yes
|
||||
|
||||
proc0_no:
|
||||
mov al, ah ; ah is always 0. mov al, ah is 2 cycles. xor ax and xor al are both 3 cycles.
|
||||
|
||||
proc0_yes:
|
||||
ret
|
||||
proc0 endp
|
||||
|
||||
align 2
|
||||
proc1 proc near
|
||||
cmp al, [bx + 0]
|
||||
jne short proc1_next_win
|
||||
cmp al, [bx + 2]
|
||||
je short proc1_yes
|
||||
|
||||
proc1_next_win:
|
||||
cmp al, [bx + 4]
|
||||
jne short proc1_no
|
||||
cmp al, [bx + 7]
|
||||
je short proc1_yes
|
||||
|
||||
proc1_no:
|
||||
mov al, ah
|
||||
|
||||
proc1_yes:
|
||||
ret
|
||||
proc1 endp
|
||||
|
||||
align 2
|
||||
proc2 proc near
|
||||
cmp al, [bx + 0]
|
||||
jne short proc2_next_win
|
||||
cmp al, [bx + 1]
|
||||
je short proc2_yes
|
||||
|
||||
proc2_next_win:
|
||||
cmp al, [bx + 5]
|
||||
jne short proc2_next_win2
|
||||
cmp al, [bx + 8]
|
||||
je short proc2_yes
|
||||
|
||||
proc2_next_win2:
|
||||
cmp al, [bx + 4]
|
||||
jne short proc2_no
|
||||
cmp al, [bx + 6]
|
||||
je short proc2_yes
|
||||
|
||||
proc2_no:
|
||||
mov al, ah
|
||||
|
||||
proc2_yes:
|
||||
ret
|
||||
proc2 endp
|
||||
|
||||
align 2
|
||||
proc3 proc near
|
||||
cmp al, [bx + 0]
|
||||
jne short proc3_next_win
|
||||
cmp al, [bx + 6]
|
||||
je short proc3_yes
|
||||
|
||||
proc3_next_win:
|
||||
cmp al, [bx + 4]
|
||||
jne short proc3_no
|
||||
cmp al, [bx + 5]
|
||||
je short proc3_yes
|
||||
|
||||
proc3_no:
|
||||
mov al, ah
|
||||
|
||||
proc3_yes:
|
||||
ret
|
||||
proc3 endp
|
||||
|
||||
align 2
|
||||
proc4 proc near
|
||||
cmp al, [bx + 0]
|
||||
jne short proc4_next_win
|
||||
cmp al, [bx + 8]
|
||||
je short proc4_yes
|
||||
|
||||
proc4_next_win:
|
||||
cmp al, [bx + 2]
|
||||
jne short proc4_next_win2
|
||||
cmp al, [bx + 6]
|
||||
je short proc4_yes
|
||||
|
||||
proc4_next_win2:
|
||||
cmp al, [bx + 1]
|
||||
jne short proc4_next_win3
|
||||
cmp al, [bx + 7]
|
||||
je short proc4_yes
|
||||
|
||||
proc4_next_win3:
|
||||
cmp al, [bx + 3]
|
||||
jne short proc4_no
|
||||
cmp al, [bx + 5]
|
||||
je short proc4_yes
|
||||
|
||||
proc4_no:
|
||||
mov al, ah
|
||||
|
||||
proc4_yes:
|
||||
ret
|
||||
proc4 endp
|
||||
|
||||
align 2
|
||||
proc5 proc near
|
||||
cmp al, [bx + 3]
|
||||
jne short proc5_next_win
|
||||
cmp al, [bx + 4]
|
||||
je short proc5_yes
|
||||
|
||||
proc5_next_win:
|
||||
cmp al, [bx + 2]
|
||||
jne short proc5_no
|
||||
cmp al, [bx + 8]
|
||||
je short proc5_yes
|
||||
|
||||
proc5_no:
|
||||
mov al, ah
|
||||
|
||||
proc5_yes:
|
||||
ret
|
||||
proc5 endp
|
||||
|
||||
align 2
|
||||
proc6 proc near
|
||||
cmp al, [bx + 2]
|
||||
jne short proc6_next_win
|
||||
cmp al, [bx + 4]
|
||||
je short proc6_yes
|
||||
|
||||
proc6_next_win:
|
||||
cmp al, [bx + 0]
|
||||
jne short proc6_next_win2
|
||||
cmp al, [bx + 3]
|
||||
je short proc6_yes
|
||||
|
||||
proc6_next_win2:
|
||||
cmp al, [bx + 7]
|
||||
jne short proc6_no
|
||||
cmp al, [bx + 8]
|
||||
je short proc6_yes
|
||||
|
||||
proc6_no:
|
||||
mov al, ah
|
||||
|
||||
proc6_yes:
|
||||
ret
|
||||
proc6 endp
|
||||
|
||||
align 2
|
||||
proc7 proc near
|
||||
cmp al, [bx + 1]
|
||||
jne short proc7_next_win
|
||||
cmp al, [bx + 4]
|
||||
je short proc7_yes
|
||||
|
||||
proc7_next_win:
|
||||
cmp al, [bx + 6]
|
||||
jne short proc7_no
|
||||
cmp al, [bx + 8]
|
||||
je short proc7_yes
|
||||
|
||||
proc7_no:
|
||||
mov al, ah
|
||||
|
||||
proc7_yes:
|
||||
ret
|
||||
proc7 endp
|
||||
|
||||
align 2
|
||||
proc8 proc near
|
||||
cmp al, [bx + 0]
|
||||
jne short proc8_next_win
|
||||
cmp al, [bx + 4]
|
||||
je short proc8_yes
|
||||
|
||||
proc8_next_win:
|
||||
cmp al, [bx + 2]
|
||||
jne short proc8_next_win2
|
||||
cmp al, [bx + 5]
|
||||
je short proc8_yes
|
||||
|
||||
proc8_next_win2:
|
||||
cmp al, [bx + 6]
|
||||
jne short proc8_no
|
||||
cmp al, [bx + 7]
|
||||
je short proc8_yes
|
||||
|
||||
proc8_no:
|
||||
mov al, ah
|
||||
|
||||
proc8_yes:
|
||||
ret
|
||||
proc8 endp
|
||||
|
||||
end
|
Loading…
Reference in New Issue
Block a user