This commit is contained in:
davidly 2024-06-30 06:49:30 -07:00
parent f06c9bf995
commit e626a58278
45 changed files with 5298 additions and 0 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

247
Microsoft MASM v5/e.asm Normal file
View 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

View 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

View 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

View 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
View 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

View 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

View 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

Binary file not shown.

Binary file not shown.

View 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

View 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

View 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;

Binary file not shown.

View 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

View 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

View 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

View 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

Binary file not shown.

View 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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View 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

Binary file not shown.

Binary file not shown.

View 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

Binary file not shown.

Binary file not shown.

237
Microsoft MASM v5/sieve.asm Normal file
View 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
View 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