📄 emu8086.inc
字号:
; Copyright (C) 2002 emu8086, Inc.
; http://www.emu8086.com
; info@emu8086.com
; All rights reserved.
; this macro prints a
; char in AL and advances
; the current cursor
; position:
PUTC MACRO char
PUSH AX
MOV AL, char
MOV AH, 0Eh
INT 10h
POP AX
ENDM
; this macro prints a string that is
; given as a parameter, example:
; PRINT 'hello world!'
; (new line is NOT added).
PRINT MACRO sdat
LOCAL next_char, s_dcl, printed, skip_dcl
PUSH AX ; store registers...
PUSH SI ;
JMP skip_dcl ; skip declaration.
s_dcl DB sdat, 0
skip_dcl:
LEA SI, s_dcl
next_char:
MOV AL, CS:[SI]
CMP AL, 0
JZ printed
INC SI
MOV AH, 0Eh ; teletype function.
INT 10h
JMP next_char
printed:
POP SI ; re-store registers...
POP AX ;
ENDM
; this macro prints a string that is
; given as a parameter, example:
; PRINTN 'hello world!'
; (the same as PRINT, but
; new line is automatically added).
PRINTN MACRO sdat
LOCAL next_char, s_dcl, printed, skip_dcl
PUSH AX ; store registers...
PUSH SI ;
JMP skip_dcl ; skip declaration.
s_dcl DB sdat, 13, 10, 0
skip_dcl:
LEA SI, s_dcl
next_char:
MOV AL, CS:[SI]
CMP AL, 0
JZ printed
INC SI
MOV AH, 0Eh ; teletype function.
INT 10h
JMP next_char
printed:
POP SI ; re-store registers...
POP AX ;
ENDM
; turns off the cursor:
CURSOROFF MACRO
PUSH AX
PUSH CX
MOV AH, 1
MOV CH, 28h
MOV CL, 09h
INT 10h
POP CX
POP AX
ENDM
; turns on the cursor:
CURSORON MACRO
PUSH AX
PUSH CX
MOV AH, 1
MOV CH, 08h
MOV CL, 09h
INT 10h
POP CX
POP AX
ENDM
; sets current cursor
; position:
GOTOXY MACRO col, row
PUSH AX
PUSH BX
PUSH DX
MOV AH, 02h
MOV DH, row
MOV DL, col
MOV BH, 0
INT 10h
POP DX
POP BX
POP AX
ENDM
;***************************************************************
; This macro defines a procedure that
; gets the multi-digit SIGNED number from the keyboard,
; and stores the result in CX register:
DEFINE_SCAN_NUM MACRO
LOCAL make_minus, ten, next_digit, set_minus
LOCAL too_big, backspace_checked, too_big2
LOCAL stop_input, not_minus, skip_proc_scan_num
LOCAL remove_not_digit, ok_AE_0, ok_digit, not_cr
; protect from wrong definition location:
JMP skip_proc_scan_num
SCAN_NUM PROC NEAR
PUSH DX
PUSH AX
PUSH SI
MOV CX, 0
; reset flag:
MOV CS:make_minus, 0
next_digit:
; get char from keyboard
; into AL:
MOV AH, 00h
INT 16h
; and print it:
MOV AH, 0Eh
INT 10h
; check for MINUS:
CMP AL, '-'
JE set_minus
; check for ENTER key:
CMP AL, 13 ; carriage return?
JNE not_cr
JMP stop_input
not_cr:
CMP AL, 8 ; 'BACKSPACE' pressed?
JNE backspace_checked
MOV DX, 0 ; remove last digit by
MOV AX, CX ; division:
DIV CS:ten ; AX = DX:AX / 10 (DX-rem).
MOV CX, AX
PUTC ' ' ; clear position.
PUTC 8 ; backspace again.
JMP next_digit
backspace_checked:
; allow only digits:
CMP AL, '0'
JAE ok_AE_0
JMP remove_not_digit
ok_AE_0:
CMP AL, '9'
JBE ok_digit
remove_not_digit:
PUTC 8 ; backspace.
PUTC ' ' ; clear last entered not digit.
PUTC 8 ; backspace again.
JMP next_digit ; wait for next input.
ok_digit:
; multiply CX by 10 (first time the result is zero)
PUSH AX
MOV AX, CX
MUL CS:ten ; DX:AX = AX*10
MOV CX, AX
POP AX
; check if the number is too big
; (result should be 16 bits)
CMP DX, 0
JNE too_big
; convert from ASCII code:
SUB AL, 30h
; add AL to CX:
MOV AH, 0
MOV DX, CX ; backup, in case the result will be too big.
ADD CX, AX
JC too_big2 ; jump if the number is too big.
JMP next_digit
set_minus:
MOV CS:make_minus, 1
JMP next_digit
too_big2:
MOV CX, DX ; restore the backuped value before add.
MOV DX, 0 ; DX was zero before backup!
too_big:
MOV AX, CX
DIV CS:ten ; reverse last DX:AX = AX*10, make AX = DX:AX / 10
MOV CX, AX
PUTC 8 ; backspace.
PUTC ' ' ; clear last entered digit.
PUTC 8 ; backspace again.
JMP next_digit ; wait for Enter/Backspace.
stop_input:
; check flag:
CMP CS:make_minus, 0
JE not_minus
NEG CX
not_minus:
POP SI
POP AX
POP DX
RET
make_minus DB ? ; used as a flag.
ten DW 10 ; used as multiplier.
SCAN_NUM ENDP
skip_proc_scan_num:
DEFINE_SCAN_NUM ENDM
;***************************************************************
;***************************************************************
; this macro defines a procedure to print a null terminated
; string at current cursor position,
; receives address of string in DS:SI
; register:
DEFINE_PRINT_STRING MACRO
LOCAL next_char, printed, skip_proc_print_string
; protect from wrong definition location:
JMP skip_proc_print_string
PRINT_STRING PROC NEAR
PUSH AX ; store registers...
PUSH SI ;
next_char:
MOV AL, [SI]
CMP AL, 0
JZ printed
INC SI
MOV AH, 0Eh ; teletype function.
INT 10h
JMP next_char
printed:
POP SI ; re-store registers...
POP AX ;
RET
PRINT_STRING ENDP
skip_proc_print_string:
DEFINE_PRINT_STRING ENDM
;***************************************************************
;***************************************************************
; This macro defines a procedure to print a null terminated
; string at current cursor position.
; The ZERO TERMINATED string should be defined just after
; the CALL. For example:
;
; CALL PTHIS
; db 'Hello World!', 0
;
; Address of string is stored in the Stack as return address.
; Procedure updates value in the Stack to make return
; after string definition.
DEFINE_PTHIS MACRO
LOCAL next_char, printed, skip_proc_pthis, temp1
; protect from wrong definition location:
JMP skip_proc_pthis
PTHIS PROC NEAR
MOV CS:temp1, SI ; re-store SI register.
POP SI ; get return address (IP).
PUSH AX ; store AX register.
next_char:
MOV AL, CS:[SI]
INC SI ; next byte.
CMP AL, 0
JZ printed
MOV AH, 0Eh ; teletype function.
INT 10h
JMP next_char ; loop.
printed:
POP AX ; re-store AX register.
; SI should point to next command after
; the CALL instruction and string definition:
PUSH SI ; save new return address into the Stack.
MOV SI, CS:temp1 ; re-store SI register.
RET
temp1 DW ? ; variable to store original value of SI register.
PTHIS ENDP
skip_proc_pthis:
DEFINE_PTHIS ENDM
;***************************************************************
;***************************************************************
; This macro defines a procedure to get a null terminated
; string from user, the received string is written to buffer
; at DS:DI, buffer size should be in DX.
; Procedure stops the input when 'Enter' is pressed.
DEFINE_GET_STRING MACRO
LOCAL empty_buffer, wait_for_key, skip_proc_get_string
LOCAL exit, add_to_buffer
; protect from wrong definition location:
JMP skip_proc_get_string
GET_STRING PROC NEAR
PUSH AX
PUSH CX
PUSH DI
PUSH DX
MOV CX, 0 ; char counter.
CMP DX, 1 ; buffer too small?
JBE empty_buffer ;
DEC DX ; reserve space for last zero.
;============================
; Eternal loop to get
; and processes key presses:
wait_for_key:
MOV AH, 0 ; get pressed key.
INT 16h
CMP AL, 13 ; 'RETURN' pressed?
JZ exit
CMP AL, 8 ; 'BACKSPACE' pressed?
JNE add_to_buffer
JCXZ wait_for_key ; nothing to remove!
DEC CX
DEC DI
PUTC 8 ; backspace.
PUTC ' ' ; clear position.
PUTC 8 ; backspace again.
JMP wait_for_key
add_to_buffer:
CMP CX, DX ; buffer is full?
JAE wait_for_key ; if so wait for 'BACKSPACE' or 'RETURN'...
MOV [DI], AL
INC DI
INC CX
; print the key:
MOV AH, 0Eh
INT 10h
JMP wait_for_key
;============================
exit:
; terminate by null:
MOV [DI], 0
empty_buffer:
POP DX
POP DI
POP CX
POP AX
RET
GET_STRING ENDP
skip_proc_get_string:
DEFINE_GET_STRING ENDM
;***************************************************************
;***************************************************************
; this macro defines procedure to clear the screen,
; (done by scrolling entire screen window),
; and set cursor position to top of it:
DEFINE_CLEAR_SCREEN MACRO
LOCAL skip_proc_clear_screen
; protect from wrong definition location:
JMP skip_proc_clear_screen
CLEAR_SCREEN PROC NEAR
PUSH AX ; store registers...
PUSH DS ;
PUSH BX ;
PUSH CX ;
PUSH DI ;
MOV AX, 40h
MOV DS, AX ; for getting screen parameters.
MOV AH, 06h ; scroll up function id.
MOV AL, 0 ; scroll all lines!
MOV BH, 07 ; attribute for new lines.
MOV CH, 0 ; upper row.
MOV CL, 0 ; upper col.
MOV DI, 84h ; rows on screen -1,
MOV DH, [DI] ; lower row (byte).
MOV DI, 4Ah ; columns on screen,
MOV DL, [DI]
DEC DL ; lower col.
INT 10h
; set cursor position to top
; of the screen:
MOV BH, 0 ; current page.
MOV DL, 0 ; col.
MOV DH, 0 ; row.
MOV AH, 02
INT 10h
POP DI ; re-store registers...
POP CX ;
POP BX ;
POP DS ;
POP AX ;
RET
CLEAR_SCREEN ENDP
skip_proc_clear_screen:
DEFINE_CLEAR_SCREEN ENDM
;***************************************************************
;***************************************************************
; This macro defines a procedure that prints number in AX,
; used with PRINT_NUM_UNS to print signed numbers:
; Requires DEFINE_PRINT_NUM_UNS !!!
DEFINE_PRINT_NUM MACRO
LOCAL not_zero, positive, printed, skip_proc_print_num
; protect from wrong definition location:
JMP skip_proc_print_num
PRINT_NUM PROC NEAR
PUSH DX
PUSH AX
CMP AX, 0
JNZ not_zero
PUTC '0'
JMP printed
not_zero:
; the check SIGN of AX,
; make absolute if it's negative:
CMP AX, 0
JNS positive
NEG AX
PUTC '-'
positive:
CALL PRINT_NUM_UNS
printed:
POP AX
POP DX
RET
PRINT_NUM ENDP
skip_proc_print_num:
DEFINE_PRINT_NUM ENDM
;***************************************************************
; This macro defines a procedure that prints out an unsigned
; number in AX (not just a single digit)
; allowed values from 0 to 65535 (0FFFFh)
DEFINE_PRINT_NUM_UNS MACRO
LOCAL begin_print, calc, skip, print_zero, end_print, ten
LOCAL skip_proc_print_num_uns
; protect from wrong definition location:
JMP skip_proc_print_num_uns
PRINT_NUM_UNS PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
; flag to prevent printing zeros before number:
MOV CX, 1
; (result of "/ 10000" is always less or equal to 9).
MOV BX, 10000 ; 2710h - divider.
; AX is zero?
CMP AX, 0
JZ print_zero
begin_print:
; check divider (if zero go to end_print):
CMP BX,0
JZ end_print
; avoid printing zeros before number:
CMP CX, 0
JE calc
; if AX<BX then result of DIV will be zero:
CMP AX, BX
JB skip
calc:
MOV CX, 0 ; set flag.
MOV DX, 0
DIV BX ; AX = DX:AX / BX (DX=remainder).
; print last digit
; AH is always ZERO, so it's ignored
ADD AL, 30h ; convert to ASCII code.
PUTC AL
MOV AX, DX ; get remainder from last div.
skip:
; calculate BX=BX/10
PUSH AX
MOV DX, 0
MOV AX, BX
DIV CS:ten ; AX = DX:AX / 10 (DX=remainder).
MOV BX, AX
POP AX
JMP begin_print
print_zero:
PUTC '0'
end_print:
POP DX
POP CX
POP BX
POP AX
RET
ten DW 10 ; used as divider.
PRINT_NUM_UNS ENDP
skip_proc_print_num_uns:
DEFINE_PRINT_NUM_UNS ENDM
;***************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -