📄 misc.asm
字号:
GetKeyClock ENDP
;* GetPSP - Gets address of Program Segment Prefix. For DOS 3.0 or higher.
;*
;* Shows: DOS Function - 62h (Get PSP Address)
;* Instruction - call
;*
;* Params: None
;*
;* Return: Short integer with PSP segment address
;* or 0 if DOS version below 3.0
GetPSP PROC
INVOKE GetVer ; Get DOS version number
.IF ax >= 300 ; If DOS 3.0 or higher:
mov ah, 62h ; query DOS for PSP,
int 21h ; get PSP Address,
mov ax, bx ; return in AX
.ELSE ; Else 2.0:
sub ax, ax ; For version 2, return 0
.ENDIF
ret
GetPSP ENDP
;* GetMem - Gets total size of memory and determines the largest amount of
;* unallocated memory available. GetMem invokes DOS Function 48h (Allocate
;* Memory) to request an impossibly large memory block. DOS denies the re-
;* quest, but returns instead the size of the largest block available. This
;* is the amount that GetMem returns to the calling program. See the WinOpen
;* procedure for an example of calling Function 48h to allocate unused memory.
;*
;* Shows: BIOS Interrupt - 12h (Get Conventional Memory Size)
;* Instructions - push pop ret
;*
;* Params: None
;*
;* Return: Long integer, high word = total memory in kilobytes (KB)
;* low word = largest block of available memory (KB)
GetMem PROC
int 12h ; Get total memory in kilobytes
push ax ; Save size of memory
mov ah, 48h ; Request memory allocation
mov bx, 0FFFFh ; Ensure request is denied for
; impossibly large block
int 21h ; Get largest available block in BX
mov ax, bx ; Copy to AX
mov cl, 6 ; Convert paragraphs to kilobytes by
shr ax, cl ; dividing by 64
pop dx ; Recover total in DX
ret ; Return long integer DX:AX
GetMem ENDP
;* VeriPrint - Checks if LPT1 (PRN) is available.
;*
;* Shows: BIOS Interrupt - 17h (Parallel Port Printer Driver)
;*
;* Params: None
;*
;* Return: Short integer, 1 for yes or 0 for no
VeriPrint PROC
mov ah, 2 ; Check printer status for
sub dx, dx ; parallel printer (port 0)
int 17h
xchg dx, ax ; Put 0 (for error) in AX
; If all error bits are off and both operation bits are on, return 1
.IF !(dh & 00101001y) && (dh & 10010000y)
inc ax ; Return 1
.ENDIF
ret
VeriPrint ENDP
;* IntToAsc - Converts integer to ASCII string. This procedure is useful
;* only for assembly language and is not intended to be callable by C.
;*
;* Shows: Instructions - aam xchg
;*
;* Entry: AX = integer (9999 max)
;*
;* Return: DX:AX = 4-digit ASCII number
IntToAsc PROC
cwd ; Zero DX register
mov cx, 100 ; Divide AX by 100, yields
div cx ; AX=quotient, DX=remainder
aam ; Make digits unpacked BCD
or ax, "00" ; Convert to ASCII
xchg ax, dx ; Do same thing for DX
aam
or ax, "00"
ret ; Return DX:AX = ASCII number
IntToAsc ENDP
;* VeriAnsi - Checks for ANSI driver by writing ANSI sequence to report
;* cursor position. If report compares with position returned from
;* GetCurPos procedure, then ANSI driver is operating.
;*
;* Shows: DOS Functions - 06h (Direct Console I/O)
;* 0Ch (Flush Input Buffer and then Input)
;*
;* Params: None
;*
;* Return: Short integer, 1 for yes or 0 for no
.DATA
PUBLIC report
report DB ESCAPE, "[6n$" ; ANSI Report Cursor sequence
.CODE
VeriAnsi PROC
; Get cursor position from BIOS
INVOKE GetCurPos
mov cx, ax ; Save it in CX
mov dx, OFFSET report ; ANSI string to get position
mov ah, 9 ; Request DOS String Output
int 21h ; Write ANSI escape sequence
mov ah, 6 ; Skip Esc character in
mov dl, 0FFh ; keyboard buffer
int 21h
jz e_exit ; If no key, ANSI not loaded
mov ah, 6 ; Skip '[' character
int 21h
jz e_exit ; If no key, ANSI not loaded
mov ah, 6 ; Get 1st digit of cursor row
int 21h
jz e_exit ; If no key, ANSI not loaded
mov bh, al ; Store in BH
mov ah, 6 ; Get 2nd digit of cursor row
int 21h
jz e_exit ; If no key, ANSI not loaded
mov bl, al ; Store in BL
mov al, ch ; Get original row # in AL
cbw ; AX = row # from GetCurPos
inc ax ; Add 1 to it
call IntToAsc ; Make ASCII digits
cmp ax, bx ; ANSI and BIOS reports match?
jne e_exit ; No? Then ANSI not loaded
mov ax, 0C06h ; Flush remaining ANSI keys
mov dl, 0FFh ; from buffer
int 21h
mov ax, 1 ; Set 1 for true
jmp exit ; and exit
e_exit:
sub ax, ax ; Set 0 return code if no
exit:
ret ; ANSI driver installed
VeriAnsi ENDP
;* VeriCop - Checks for coprocessor.
;*
;* Shows: BIOS Interrupt - 11h (Get Equipment Configuration)
;*
;* Params: None
;*
;* Return: Short integer, 1 for yes or 0 for no
VeriCop PROC
int 11h ; Check peripherals
test al, 2 ; Coprocessor?
mov ax, 0 ; Assume no, don't alter flags
.IF !zero?
inc ax ; Set to 1
.ENDIF
ret
VeriCop ENDP
;* SetLineMode - Sets line mode for EGA or VGA.
;*
;* Shows: BIOS Interrupt - 10h, Function 11h (Character Generator Interface)
;* 10h, Function 12h (Video Subsystem Configuration)
;*
;* Uses: vconfig - Video configuration structure (initialized
;* by calling the GetVidConfig procedure)
;*
;* Params: Line - Requested line mode (25, 43, or 50)
;*
;* Return: Short integer with error code
;* 0 if successful
;* 1 if error
SetLineMode PROC,
Line:WORD
.IF vconfig.adapter >= EGA ; If EGA or VGA:
mov ax, Line ; Check for valid parameter
cmp al, 25
je line25
cmp al, 43
je line43
cmp al, 50
je line50
jmp e_exit ; If not 25, 43, or 50, exit w/ error
line25:
mov al, 11h ; Set for EGA 25-line mode
cmp vconfig.adapter, EGA ; EGA?
je linemode ; Yes? Continue
mov ax, 1202h ; No? Function 12h for VGA
mov bl, 30h ; AL = 2 for 400 scan lines
int 10h ; Reset to 400 scan lines
mov ax, 0003 ; Reset mode (Function 0)
int 10h ; to mode 3 (80-col text)
mov al, 14h ; Request 8x16 char matrix
jmp linemode
line43:
mov al, 12h ; Set for EGA 43-line mode
cmp vconfig.adapter, EGA ; EGA?
je linemode ; Yes? Continue
mov ax, 1201h ; No? Function 12h for VGA
mov bl, 30h ; AL = 1 for 350 scan lines
int 10h ; Reset to 350 scan lines
mov ax, 0003 ; Reset mode (Function 0)
int 10h ; to mode 3 (80-col text)
mov al, 12h ; Request 8x8 character matrix
jmp linemode
line50:
cmp vconfig.adapter, VGA ; VGA?
jne e_exit ; No? Exit with error
mov ax, 1202h ; Yes? Function 12h
mov bl, 30h ; AL = 2 for 400 scan lines
int 10h ; Reset to 400 scan lines
mov ax, 0003 ; Reset mode (Function 0)
int 10h ; to mode 3 (80-col text)
mov al, 12h ; Request 8x8 character matrix
linemode:
sub bl, bl ; Use table 0
mov ah, 11h ; Request Function 11h
int 10h ; Set new line mode
mov ah, 12h ; Select alternate print
mov bl, 20h ; screen for EGA and VGA
int 10h
cmp vconfig.adapter, VGA ; VGA?
je exit ; Yes? Then exit
cmp Line, 12h ; If EGA 43-line mode, set
je port ; cursor through port to
; avoid cursor emulation bug
; Set normal cursor size, pass top and bottom scan lines
INVOKE SetCurSize, 6, 7
jmp exit
port:
mov dx, 03D4h ; Video controller address
mov ax, 060Ah ; Set AH = 06h (cursor start)
; AL = 0Ah (register #)
out dx, ax ; Update port
mov ax, 000Bh ; Set AH = 00h (cursor end)
; AL = 0Bh (register #)
out dx, ax ; Update port
jmp exit ; Normal exit
.ENDIF ; EGA or VGA
e_exit:
mov ax, 1 ; Set error code
jmp exit2
exit:
sub ax, ax ; Clear error code
exit2:
ret
SetLineMode ENDP
;* Pause - Waits for specified number of clocks to elapse, then returns.
;*
;* Shows: BIOS Interrupt - 1Ah, Function 0 (Real-Time Clock Driver)
;* Operators - LOCAL []
;*
;* Params: Duration - Desired duration in clocks, where
;* 18 clocks = approx 1 second
;*
;* Return: None
Pause PROC,
Duration:WORD
LOCAL tick:DWORD
sub ah, ah
int 1Ah ; Get Clock Count in CX:DX
add dx, Duration ; Add pause time to it
adc cx, 0
mov WORD PTR tick[0], dx ; Result is target time;
mov WORD PTR tick[2], cx ; keep in local variable
.REPEAT
int 1Ah ; Poll clock until target time
.UNTIL (dx >= WORD PTR tick[0]) || (cx >= WORD PTR fileinfo.time[2])
ret
Pause ENDP
;* Sound - Sounds speaker with specified frequency and duration.
;*
;* Shows: Instructions - in out
;*
;* Params: Freq - Desired frequency of sound in hertz
;* Duration - Desired duration in clocks, where
;* 18 clocks = approx 1 second
;*
;* Return: None
Sound PROC,
Freq:WORD, Duration:WORD
mov al, 0B6h ; Initialize channel 2 of
out 43h, al ; timer chip
mov dx, 12h ; Divide 1,193,182 hertz
mov ax, 34DEh ; (clock frequency) by
div Freq ; desired frequency
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -