【8086汇编基础】05--常用函数库文件--emu8086.inc

时间:2024-03-04 22:44:53

8086汇编语言初学者教程(第5部分)

常用函数库 - emu8086.inc 

通过引用一些常用函数,可以使你编程更加方便。

在你的程序中使用其他文件中的函数的方法是

INCLUDE后面接上你要引用的文件名。编译器

会自动在你源程序所在的文件夹中查找你引用

的文件,如果没有找到,它将搜索Inc 文件夹。

通常你无法完全理解 emu8086.inc(位于Inc文件夹)

但是这没有关系,你只用知道它能做什么就足够了。

要使用emu8086.inc中的函数,你应当在你程序的开

头加上

include \'emu8086.inc\' 



emu8086.inc 定义了如下的宏:

  • PUTC char - 将一个ascii字符输出到光标当前位值,只有一个
                       参数的宏

  • GOTOXY col, row - 设置当前光标位置,有两个参数

  • PRINT string - 输出字符串,一个参数

  • PRINTN string - 输出字符串,一个参数。与print功能相同,
                            不同在于输出之后自动回车

  • CURSOROFF - 关闭文本光标

  • CURSORON - 打开文本光标

使用上述宏的方法是:在你需要的位值写上宏名称加上参数。例如:


include emu8086.inc

ORG 100h

PRINT \'Hello World!\'

GOTOXY 10, 5

PUTC 65 ; 65 - ASCII 码的 \'A\'
PUTC \'B\'

RET ; 返回操作系统
END ; 停止编译器


当编译器运行你的代码时,它首先找到声明中的

emu8086.inc文件,然后将代码中的宏用实际的

代码替换掉。通常来说,宏都是比较小的代码段,

经常使用宏会使得你的可执行程序特别大

(对于降低文件大小来说使用过程更好)



emu8086.inc 同样定义了如下过程:

  • PRINT_STRING - 在当前光标位置输出一个字符串字符串地址由DS:SI 寄存器给出使用时,需要在END前面声明DEFINE_PRINT_STRING 才能使用.

  • PTHIS - 在当前光标位置输出一个字符串(同 PRINT_STRING)

    一样,不同之处在于它是从堆栈接收字符串。字符串终止符

    应在call之后定义。例如

       CALL PTHIS
       db \'Hello World!\', 0 

    使用时,需要在 END 前面声明 DEFINE_PTHIS 。
  • GET_STRING - 从用户输入得到一个字符串,输入的字符串写入 DS:DI 指出的缓冲,缓冲区的大小由 DX设置。回车作为输入结束。使用时,需要在END前面声明    DEFINE_GET_STRING 。

  • CLEAR_SCREEN - 清屏过程(滚过整个屏幕),然后将光标设置在左上角. 使用时,需要在END前面声明DEFINE_CLEAR_SCREEN  。
     
  • SCAN_NUM - 取得用户从键盘输入的多位有符号数,并将输入存放
    CX寄存器。 使用时,需要在 END前面声明      DEFINE_SCAN_NUM

  • PRINT_NUM - 输出AX寄存器中的有符号数
    使用时,需要在END 前面声明 DEFINE_PRINT_NUM以及 DEFINE_PRINT_NUM_UNS.

  • PRINT_NUM_UNS - 输出AX寄存器中的无符号数。使用时,需要在END 前面声明DEFINE_PRINT_NUM_UNS.

使用上述过程,必须在你源程序的底部(但是在END之前!!!)声明这些函数,使用CALL指令后面接上过程名称来调用。例如:

include \'emu8086.inc\'

ORG 100h

LEA SI, msg1 ; 要求输入数字
CALL print_string ;
CALL scan_num ; 读取数字放入cx

MOV AX, CX ; CX存放数值拷贝到AX

; 输入如下字符
CALL pthis
DB 13, 10, \'You have entered: \', 0

CALL print_num ; 输出 AX中的字符

RET ; 返回操作系统

msg1 DB \'Enter the number: \', 0

DEFINE_SCAN_NUM
DEFINE_PRINT_STRING
DEFINE_PRINT_NUM
DEFINE_PRINT_NUM_UNS ; print_num函数要求的
DEFINE_PTHIS

END ; 结束



首先,编译器运行声明(对于宏只是展开)。当编译器遇到CALL指令,它

将用过程声明中的地址来替代过程名。程序在执行过程中遇到这个过程,便

会直接跳转到过程。这是非常有用的,比如,即使在你的代码中执行100次

一个过程,编译后的可执行文件也不会因此而增大多少。这样看起来很

划算,是不是?后面你会学到更多的,现在只需要了解一点点基本原理。

 

emu8086.inc文件内容如下:

emu8086.inc
  1 ; emu8086.inc - macro definitions library for easy input/output
  2 
  3 
  4 
  5 
  6 ; Note, that some declarations of "emu8086.inc" are macro procedure declarations, and you
  7 ; have to use "DEFINE_..." macro somewhere in your program if you want to use these functions:
  8 
  9 ;   CALL SCAN_NUM
 10 ;   CALL PRINT_STRING
 11 ;   CALL PTHIS
 12 ;   CALL GET_STRING
 13 ;   CALL CLEAR_SCREEN
 14 ;   CALL PRINT_NUM
 15 ;   CALL PRINT_NUM_UNS
 16 
 17 ; You can define all these procedures in your source code, but compilation time may slow down
 18 ; sufficiently because of that, only declare functions that you plan to use:
 19 
 20 
 21 ;   DEFINE_SCAN_NUM
 22 ;   DEFINE_PRINT_STRING
 23 ;   DEFINE_PTHIS
 24 ;   DEFINE_GET_STRING
 25 ;   DEFINE_CLEAR_SCREEN
 26 ;   DEFINE_PRINT_NUM
 27 ;   DEFINE_PRINT_NUM_UNS
 28 
 29 ;  The above declarations should be made in  your code once only! Better somewhere
 30 ;  in the end of your file, but before "END"  directive. You can also declare them
 31 ;  in the beginning of the file, but it should  be after "ORG 100h" directive for COM files,
 32 ;  or inside the code segment for EXE files.
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 ; this macro prints a char in AL and advances
 43 ; the current cursor position:
 44 PUTC    MACRO   char
 45         PUSH    AX
 46         MOV     AL, char
 47         MOV     AH, 0Eh
 48         INT     10h     
 49         POP     AX
 50 ENDM
 51 
 52 
 53 ; this macro prints a string that is given as a parameter, example:
 54 ; PRINT \'hello world!\'
 55 ; new line is NOT added.
 56 PRINT   MACRO   sdat
 57 LOCAL   next_char, s_dcl, printed, skip_dcl
 58 
 59 PUSH    AX      ; store registers...
 60 PUSH    SI      ;
 61 
 62 JMP     skip_dcl        ; skip declaration.
 63         s_dcl DB sdat, 0
 64 
 65 skip_dcl:
 66         LEA     SI, s_dcl
 67         
 68 next_char:      
 69         MOV     AL, CS:[SI]
 70         CMP     AL, 0
 71         JZ      printed
 72         INC     SI
 73         MOV     AH, 0Eh ; teletype function.
 74         INT     10h
 75         JMP     next_char
 76 printed:
 77 
 78 POP     SI      ; re-store registers...
 79 POP     AX      ;
 80 ENDM
 81 
 82 
 83 ; this macro prints a string that is given as a parameter, example:
 84 ; PRINTN \'hello world!\'
 85 ; the same as PRINT, but new line is automatically added.
 86 PRINTN   MACRO   sdat
 87 LOCAL   next_char, s_dcl, printed, skip_dcl
 88 
 89 PUSH    AX      ; store registers...
 90 PUSH    SI      ;
 91 
 92 JMP     skip_dcl        ; skip declaration.
 93         s_dcl DB sdat, 13, 10, 0
 94 
 95 skip_dcl:
 96         LEA     SI, s_dcl
 97         
 98 next_char:      
 99         MOV     AL, CS:[SI]
100         CMP     AL, 0
101         JZ      printed
102         INC     SI
103         MOV     AH, 0Eh ; teletype function.
104         INT     10h
105         JMP     next_char
106 printed:
107 
108 POP     SI      ; re-store registers...
109 POP     AX      ;
110 ENDM
111 
112 
113 ; turns off the cursor:
114 CURSOROFF       MACRO
115         PUSH    AX
116         PUSH    CX
117         MOV     AH, 1
118         MOV     CH, 28h
119         MOV     CL, 09h
120         INT     10h
121         POP     CX
122         POP     AX
123 ENDM
124 
125 
126 
127 ; turns on the cursor:
128 CURSORON        MACRO
129         PUSH    AX
130         PUSH    CX
131         MOV     AH, 1
132         MOV     CH, 08h
133         MOV     CL, 09h
134         INT     10h
135         POP     CX
136         POP     AX
137 ENDM
138 
139 ; sets current cursor
140 ; position:
141 GOTOXY  MACRO   col, row
142         PUSH    AX
143         PUSH    BX
144         PUSH    DX
145         MOV     AH, 02h
146         MOV     DH, row
147         MOV     DL, col
148         MOV     BH, 0
149         INT     10h
150         POP     DX
151         POP     BX
152         POP     AX
153 ENDM
154 
155 
156 ;***************************************************************
157 
158 ; This macro defines a procedure that gets the multi-digit SIGNED number from the keyboard,
159 ; and stores the result in CX register:
160 DEFINE_SCAN_NUM         MACRO
161 LOCAL make_minus, ten, next_digit, set_minus
162 LOCAL too_big, backspace_checked, too_big2
163 LOCAL stop_input, not_minus, skip_proc_scan_num
164 LOCAL remove_not_digit, ok_AE_0, ok_digit, not_cr
165 
166 ; protect from wrong definition location:
167 JMP     skip_proc_scan_num
168 
169 SCAN_NUM        PROC    NEAR
170         PUSH    DX
171         PUSH    AX
172         PUSH    SI
173         
174         MOV     CX, 0
175 
176         ; reset flag:
177         MOV     CS:make_minus, 0
178 
179 next_digit:
180 
181         ; get char from keyboard
182         ; into AL:
183         MOV     AH, 00h
184         INT     16h
185         ; and print it:
186         MOV     AH, 0Eh
187         INT     10h
188 
189         ; check for MINUS:
190         CMP     AL, \'-\'
191         JE      set_minus
192 
193         ; check for ENTER key:
194         CMP     AL, 13  ; carriage return?
195         JNE     not_cr
196         JMP     stop_input
197 not_cr:
198 
199 
200         CMP     AL, 8                   ; \'BACKSPACE\' pressed?
201         JNE     backspace_checked
202         MOV     DX, 0                   ; remove last digit by
203         MOV     AX, CX                  ; division:
204         DIV     CS:ten                  ; AX = DX:AX / 10 (DX-rem).
205         MOV     CX, AX
206         PUTC    \' \'                     ; clear position.
207         PUTC    8                       ; backspace again.
208         JMP     next_digit
209 backspace_checked:
210 
211 
212         ; allow only digits:
213         CMP     AL, \'0\'
214         JAE     ok_AE_0
215         JMP     remove_not_digit
216 ok_AE_0:        
217         CMP     AL, \'9\'
218         JBE     ok_digit
219 remove_not_digit:       
220         PUTC    8       ; backspace.
221         PUTC    \' \'     ; clear last entered not digit.
222         PUTC    8       ; backspace again.        
223         JMP     next_digit ; wait for next input.       
224 ok_digit:
225 
226 
227         ; multiply CX by 10 (first time the result is zero)
228         PUSH    AX
229         MOV     AX, CX
230         MUL     CS:ten                  ; DX:AX = AX*10
231         MOV     CX, AX
232         POP     AX
233 
234         ; check if the number is too big
235         ; (result should be 16 bits)
236         CMP     DX, 0
237         JNE     too_big
238 
239         ; convert from ASCII code:
240         SUB     AL, 30h
241 
242         ; add AL to CX:
243         MOV     AH, 0
244         MOV     DX, CX      ; backup, in case the result will be too big.
245         ADD     CX, AX
246         JC      too_big2    ; jump if the number is too big.
247 
248         JMP     next_digit
249 
250 set_minus:
251         MOV     CS:make_minus, 1
252         JMP     next_digit
253 
254 too_big2:
255         MOV     CX, DX      ; restore the backuped value before add.
256         MOV     DX, 0       ; DX was zero before backup!
257 too_big:
258         MOV     AX, CX
259         DIV     CS:ten  ; reverse last DX:AX = AX*10, make AX = DX:AX / 10
260         MOV     CX, AX
261         PUTC    8       ; backspace.
262         PUTC    \' \'     ; clear last entered digit.
263         PUTC    8       ; backspace again.        
264         JMP     next_digit ; wait for Enter/Backspace.
265         
266         
267 stop_input:
268         ; check flag:
269         CMP     CS:make_minus, 0
270         JE      not_minus
271         NEG     CX
272 not_minus:
273 
274         POP     SI
275         POP     AX
276         POP     DX
277         RET
278 make_minus      DB      ?       ; used as a flag.
279 ten             DW      10      ; used as multiplier.
280 SCAN_NUM        ENDP
281 
282 skip_proc_scan_num:
283 
284 DEFINE_SCAN_NUM         ENDM
285 ;***************************************************************
286 
287 
288 ;***************************************************************
289 ; this macro defines a procedure to print a null terminated
290 ; string at current cursor position, receives address of string in DS:SI
291 DEFINE_PRINT_STRING     MACRO
292 LOCAL   next_char, printed, skip_proc_print_string
293 
294 ; protect from wrong definition location:
295 JMP     skip_proc_print_string
296 
297 PRINT_STRING PROC NEAR
298 PUSH    AX      ; store registers...
299 PUSH    SI      ;
300 
301 next_char:      
302         MOV     AL, [SI]
303         CMP     AL, 0
304         JZ      printed
305         INC     SI
306         MOV     AH, 0Eh ; teletype function.
307         INT     10h
308         JMP     next_char
309 printed:
310 
311 POP     SI      ; re-store registers...
312 POP     AX      ;
313 
314 RET
315 PRINT_STRING ENDP
316 
317 skip_proc_print_string:
318 
319 DEFINE_PRINT_STRING     ENDM
320 ;***************************************************************
321 
322 
323 ;***************************************************************
324 ; This macro defines a procedure to print a null terminated
325 ; string at current cursor position.
326 ; The ZERO TERMINATED string should be defined just after the CALL. For example:
327 ;
328 ; CALL PTHIS
329 ; db \'Hello World!\', 0
330 ;
331 ; Address of string is stored in the Stack as return address.
332 ; Procedure updates value in the Stack to make return
333 ; after string definition.
334 DEFINE_PTHIS     MACRO
335 LOCAL   next_char, printed, skip_proc_pthis, temp1
336 
337 ; protect from wrong definition location:
338 JMP     skip_proc_pthis
339 
340 PTHIS PROC NEAR
341 
342 MOV     CS:temp1, SI  ; store SI register.
343 
344 POP     SI            ; get return address (IP).
345 
346 PUSH    AX            ; store AX register.
347 
348 next_char:      
349         MOV     AL, CS:[SI]
350         INC     SI            ; next byte.
351         CMP     AL, 0
352         JZ      printed        
353         MOV     AH, 0Eh       ; teletype function.
354         INT     10h
355         JMP     next_char     ; loop.
356 printed:
357 
358 POP     AX            ; re-store AX register.
359 
360 ; SI should point to next command after
361 ; the CALL instruction and string definition:
362 PUSH    SI            ; save new return address into the Stack.
363 
364 MOV     SI, CS:temp1  ; re-store SI register.
365 
366 RET
367 temp1  DW  ?    ; variable to store original value of SI register.
368 PTHIS ENDP
369 
370 skip_proc_pthis:
371 
372 DEFINE_PTHIS     ENDM
373 ;***************************************************************
374 
375 
376 ;***************************************************************
377 ; This macro defines a procedure to get a null terminated
378 ; string from user, the received string is written to buffer
379 ; at DS:DI, buffer size should be in DX.
380 ; Procedure stops the input when \'Enter\' is pressed.
381 DEFINE_GET_STRING       MACRO
382 LOCAL   empty_buffer, wait_for_key, skip_proc_get_string
383 LOCAL   exit, add_to_buffer
384 
385 ; protect from wrong definition location:
386 JMP     skip_proc_get_string
387 
388 GET_STRING      PROC    NEAR
389 PUSH    AX
390 PUSH    CX
391 PUSH    DI
392 PUSH    DX
393 
394 MOV     CX, 0                   ; char counter.
395 
396 CMP     DX, 1                   ; buffer too small?
397 JBE     empty_buffer            ;
398 
399 DEC     DX                      ; reserve space for last zero.
400 
401 
402 ;============================
403 ; loop to get and processes key presses:
404 
405 wait_for_key:
406 
407 MOV     AH, 0                   ; get pressed key.
408 INT     16h
409 
410 CMP     AL, 13                  ; \'RETURN\' pressed?
411 JZ      exit
412 
413 
414 CMP     AL, 8                   ; \'BACKSPACE\' pressed?
415 JNE     add_to_buffer
416 JCXZ    wait_for_key            ; nothing to remove!
417 DEC     CX
418 DEC     DI
419 PUTC    8                       ; backspace.
420 PUTC    \' \'                     ; clear position.
421 PUTC    8                       ; backspace again.
422 JMP     wait_for_key
423 
424 add_to_buffer:
425 
426         CMP     CX, DX          ; buffer is full?
427         JAE     wait_for_key    ; if so wait for \'BACKSPACE\' or \'RETURN\'...
428 
429         MOV     [DI], AL
430         INC     DI
431         INC     CX
432         
433         ; print the key:
434         MOV     AH, 0Eh
435         INT     10h
436 
437 JMP     wait_for_key
438 ;============================
439 
440 exit:
441 
442 ; terminate by null:
443 MOV     [DI], 0
444 
445 empty_buffer:
446 
447 POP     DX
448 POP     DI
449 POP     CX
450 POP     AX
451 RET
452 GET_STRING      ENDP
453 
454 
455 skip_proc_get_string:
456 
457 DEFINE_GET_STRING       ENDM
458 ;***************************************************************
459 
460 ;***************************************************************
461 ; this macro defines procedure to clear the screen,
462 ; (done by scrolling entire screen window),
463 ; and set cursor position to top of it:
464 DEFINE_CLEAR_SCREEN     MACRO
465 LOCAL skip_proc_clear_screen
466 
467 ; protect from wrong definition location:
468 JMP     skip_proc_clear_screen
469 
470 CLEAR_SCREEN PROC NEAR
471         PUSH    AX      ; store registers...
472         PUSH    DS      ;
473         PUSH    BX      ;
474         PUSH    CX      ;
475         PUSH    DI      ;
476 
477         MOV     AX, 40h
478         MOV     DS, AX  ; for getting screen parameters.
479         MOV     AH, 06h ; scroll up function id.
480         MOV     AL, 0   ; scroll all lines!
481         MOV     BH, 07  ; attribute for new lines.
482         MOV     CH, 0   ; upper row.
483         MOV     CL, 0   ; upper col.
484         MOV     DI, 84h ; rows on screen -1,
485         MOV     DH, [DI] ; lower row (byte).
486         MOV     DI, 4Ah ; columns on screen,
487         MOV     DL, [DI]
488         DEC     DL      ; lower col.
489         INT     10h
490 
491         ; set cursor position to top
492         ; of the screen:
493         MOV     BH, 0   ; current page.
494         MOV     DL, 0   ; col.
495         MOV     DH, 0   ; row.
496         MOV     AH, 02
497         INT     10h
498 
499         POP     DI      ; re-store registers...
500         POP     CX      ;
501         POP     BX      ;
502         POP     DS      ;
503         POP     AX      ;
504 
505         RET
506 CLEAR_SCREEN ENDP
507 
508 skip_proc_clear_screen:
509 
510 DEFINE_CLEAR_SCREEN     ENDM
511 ;***************************************************************
512 
513 
514 ;***************************************************************
515 
516 ; This macro defines a procedure that prints number in AX,
517 ; used with PRINT_NUM_UNS to print signed numbers:
518 ; Requires DEFINE_PRINT_NUM_UNS !!!
519 DEFINE_PRINT_NUM        MACRO
520 LOCAL not_zero, positive, printed, skip_proc_print_num
521 
522 ; protect from wrong definition location:
523 JMP     skip_proc_print_num
524 
525 PRINT_NUM       PROC    NEAR
526         PUSH    DX
527         PUSH    AX
528 
529         CMP     AX, 0
530         JNZ     not_zero
531 
532         PUTC    \'0\'
533         JMP     printed
534 
535 not_zero:
536         ; the check SIGN of AX,
537         ; make absolute if it\'s negative:
538         CMP     AX, 0
539         JNS     positive
540         NEG     AX
541 
542         PUTC    \'-\'
543 
544 positive:
545         CALL    PRINT_NUM_UNS
546 printed:
547         POP     AX
548         POP     DX
549         RET
550 PRINT_NUM       ENDP
551 
552 skip_proc_print_num:
553 
554 DEFINE_PRINT_NUM        ENDM
555 
556 ;***************************************************************
557 
558 ; This macro defines a procedure that prints out an unsigned
559 ; number in AX (not just a single digit)
560 ; allowed values from 0 to 65535 (0FFFFh)
561 DEFINE_PRINT_NUM_UNS    MACRO
562 LOCAL begin_print, calc, skip, print_zero, end_print, ten
563 LOCAL skip_proc_print_num_uns
564 
565 ; protect from wrong definition location:
566 JMP     skip_proc_print_num_uns
567 
568 PRINT_NUM_UNS   PROC    NEAR
569         PUSH    AX
570         PUSH    BX
571         PUSH    CX
572         PUSH    DX
573 
574         ; flag to prevent printing zeros before number:
575         MOV     CX, 1
576 
577         ; (result of "/ 10000" is always less or equal to 9).
578         MOV     BX, 10000       ; 2710h - divider.
579 
580         ; AX is zero?
581         CMP     AX, 0
582         JZ      print_zero
583 
584 begin_print:
585 
586         ; check divider (if zero go to end_print):
587         CMP     BX,0
588         JZ      end_print
589 
590         ; avoid printing zeros before number:
591         CMP     CX, 0
592         JE      calc
593         ; if AX<BX then result of DIV will be zero:
594         CMP     AX, BX
595         JB      skip
596 calc:
597         MOV     CX, 0   ; set flag.
598 
599         MOV     DX, 0
600         DIV     BX      ; AX = DX:AX / BX   (DX=remainder).
601 
602         ; print last digit
603         ; AH is always ZERO, so it\'s ignored
604         ADD     AL, 30h    ; convert to ASCII code.
605         PUTC    AL
606 
607 
608         MOV     AX, DX  ; get remainder from last div.
609 
610 skip:
611         ; calculate BX=BX/10
612         PUSH    AX
613         MOV     DX, 0
614         MOV     AX, BX
615         DIV     CS:ten  ; AX = DX:AX / 10   (DX=remainder).
616         MOV     BX, AX
617         POP     AX
618 
619         JMP     begin_print
620         
621 print_zero:
622         PUTC    \'0\'
623         
624 end_print:
625 
626         POP     DX
627         POP     CX
628         POP     BX
629         POP     AX
630         RET
631 ten             DW      10      ; used as divider.      
632 PRINT_NUM_UNS   ENDP
633 
634 skip_proc_print_num_uns:
635 
636 DEFINE_PRINT_NUM_UNS    ENDM
637 ;***************************************************************
638 
639 
640 
                                                                                                                                                                                                             

 

<<< 上一部分 <<<【8086汇编基础】04--中断

>>> 下一部分 >>>【8086汇编基础】06--算术运算与逻辑指令