8086 Assembler Tutorial for Beginners (Part 5)

Library of common functions - emu8086.inc

הדרכה בתכנות אסמבלר 8086 למתחילים (חלק 5)  

ספריות של פונקציות משותפות - emu8086.inc

To make programming easier there are some common functions that can be included in your program. To make your program use functions defined in other file you should use the INCLUDE directive followed by a file name. Compiler automatically searches for the file in the same folder where the source file is located, and if it cannot find the file there - it searches in Inc folder.

Currently you may not be able to fully understand the contents of the emu8086.inc (located in Inc folder), but it's OK, since you only need to understand what it can do.

To use any of the functions in emu8086.inc you should have the following line in the beginning of your source file:

   include 'emu8086.inc'
על-מנת לכתוב תוכניות בצורה קלה יותר קיימות פונקציות נפוצות היכולות להיכלל בתוכנית שלך.

ליצירת התוכנית שלך משתמשים בפונקציות שהוגדרו בקובץ אחר. אתה צריך להשתמש בפקודת INCLUDE בצרוף שם הקובץ.

המהדר מחפש באופן אוטומטי את מיקום קובץ המקור, ובמידה ולא מצא אותו אז הוא יחפש בתיקיית INC של אותו אזור.

בשלב זה אינך חייב להבין לעומק את תוכן הקובץ emu8086.inc (שנמצא תיקייה INC), אך זה בסדר, כי אתה רק צריך להבין מה זה מבצע.

לצורך שימוש בפונקציות של emu8086.inc אתה חייב להוסיף בראשית התוכנית שלך את השורה:

      '
include 'emu8086.inc

emu8086.inc defines the following macros:

  • PUTC char - macro with 1 parameter, prints out an ASCII char at current cursor position.

  • GOTOXY col, row - macro with 2 parameters, sets cursor position.

  • PRINT string - macro with 1 parameter, prints out a string.

  • PRINTN string - macro with 1 parameter, prints out a string. The same as PRINT but automatically adds "carriage return" at the end of the string.

  • CURSOROFF - turns off the text cursor.

  • CURSORON - turns on the text cursor.

To use any of the above macros simply type its name somewhere in your code, and if required parameters, for example:

קובץ emu8086.inc מגדיר את פונקציות המקרו הבאות:

  • PUT char - מקרו עם פרמטר 1, מדפיס אות אסקי במקום הנוכחי של הסמן במסך.

  • שורה, עמודה GOTOXY - מקרו עם 2 פרמטרים, מגדיר את מיקום הסמן במסך.

  • מחרוזת PRINT - מקרו עם פרמטר 1, מדפיס מחרוזת במסך.

  • מחרוזת PRINTN - מקרו עם פרמטר 1, מדפיס מחרוזת. כמו PRINT אבל באופן אוטומטי מוסיף סימן של שורה חדשה ותחילת שורה בסיום של המחרוזת.

  • CURSOROFF - מכבה את סמן האותיות.

  • CURSORON - מדליק את סמן האותיות.

 

לצורך שימוש בכל אחת מפונקציות המקרו למעלה פשוט מקלידים את שם הפונקציה  איפשהו בתוכנית שלך, ואם נדרש יש להקליד גם את הפרמטרים המתאימים, למשל:

 
 include emu8086.inc

 ORG    100h

 PRINT 'Hello World!'

 GOTOXY 10, 5
                   ;        'A' הכנס צופן אסקי של אות
 PUTC 65           ; 65 - is an ASCII code for 'A'
 PUTC 'B'
                   ;   חזרה למערכת הפעלה וסיום ההידור
 RET               ; return to operating system.
 END               ; directive to stop the compiler.
When compiler process your source code it searches the emu8086.inc file for declarations of the macros and replaces the macro names with real code. Generally macros are relatively small parts of code, frequent use of a macro may make your executable too big (procedures are better for size optimization).

emu8086.inc also defines the following procedures:

כאשר המהדר מעבד את הצופן שלך, הוא סורק את הקובץ emu8086.inc, מחפש את ההצהרות של המקרו ומחליף את שמות המקרו תמורת פקודות אמת. בדרך כלל פקודות מקרו הם חלקים קטנים של התוכנית,  באופן יחסי לתוכנית הכוללת. שימוש רב של פקודות מקרו יכול לעשות את תוכנית הביצוע גדולה מדי (רצוי להשתמש בפרוצדורות לאופטימיזציה גדולה יותר).

קובץ enu8086.inc מגדיר גם את הפרוצדורות הבאות:

  • PRINT_STRING - procedure to print a null terminated string at current cursor position, receives address of string in DS:SI register. To use it declare: DEFINE_PRINT_STRING before END directive.

  • PTHIS - procedure to print a null terminated string at current cursor position (just as PRINT_STRING), but receives address of string from Stack. The ZERO TERMINATED string should be defined just after the CALL instruction. For example:

    CALL PTHIS
    db 'Hello World!', 0

    To use it declare: DEFINE_PTHIS before END directive.

  • GET_STRING - procedure to get a null terminated string from a 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. To use it declare: DEFINE_GET_STRING before END directive.

  • CLEAR_SCREEN - procedure to clear the screen, (done by scrolling entire screen window), and set cursor position to top of it. To use it declare: DEFINE_CLEAR_SCREEN before END directive.

  • SCAN_NUM - procedure that gets the multi-digit SIGNED number from the keyboard, and stores the result in CX register. To use it declare: DEFINE_SCAN_NUM before END directive.

  • PRINT_NUM - procedure that prints a signed number in AX register. To use it declare: DEFINE_PRINT_NUM and DEFINE_PRINT_NUM_UNS before END directive.

  • PRINT_NUM_UNS - procedure that prints out an unsigned number in AX register. To use it declare: DEFINE_PRINT_NUM_UNS before END directive.
  • PRINT_STRING - פרוצדורה להדפסת מחרוזת המסתיימת בסימן ניל, במקום הנוכחי של הסמן. פרוצדורה זו מקבלת את כתובת המחרוזת בזוג האוגרים DS:SI . לשימוש זה הגדר לפני פקודת ה-END את DEFINE_PRINT_STRING.

  • PTHIS - פרוצדורה להדפסת מחרוזת המסתיימת בסימן ניל, במקום הנוכחי של הסמן (בדיוק כמו בפקודה הקודמת), אך היא מקבלת את כתובת התחלה של המחרוזת דרך המחסנית. המחרוזת חייבת להסתיים באפס כנתון אחרון וחייבת להיות מוגדרת אחרי פקודת ה- CALL. למשל:

              CALL PTHIS
    db 'Hello World!', 0

    קרא להגדרת DEFINE_PTHIS לפני פקודת ה- END.

  • GET_STRING - פרוצדורה לקבלת מחרוזת מהמשתמש, המסתיימת בסימן ניל, (המחרוזת חייבת להסתיים באפס כנתון אחרון), המחרוזת מתקבלת בחוצץ בכתובת התחלה המוגדרת בזוג האוגרים DS:SI. הפרוצדורה מסיימת את פעולת הקלט כאשר נלחץ כפתור "Enter".
    קרא להגדרת DEFINE_
    GET_STRING לפני פקודת ה- END.

  • CLEAR_SCREEN - פרוצדורה לניקוי המסך, (שנעשה על ידי גלילת חלון שלם של המסך), וקובעת את מיקום הסמן בחלק העליון של המסך.
    קרא להגדרת DEFINE_
    GET_STRING לפני פקודת ה- END.

  • SCAN_NUM - פרוצדורה לקבלת מספר מסומן רב-ספרות מהמקלדת, ומאחסנת את התוצאה באוגר CX .
    קרא להגדרת DEFINE_
    SCAN_NUM לפני פקודת ה- END.

  • PRINT_NUM - פרוצדורה להדפסת מספר מסומן הנמצא באוגר AX .
    קרא להגדרת DEFINE_
    PRINT_NUM ו-  DEFINE_PRINT_NUM_UNS לפני פקודת ה- END.

  • PRINT_NUM_UNS - פרוצדורה להדפסת מספר לא מסומן הנמצא באוגר AX .
    קרא להגדרת DEFINE_
    PRINT_NUM_UNS לפני פקודת ה- END.

To use any of the above procedures you should first declare the function in the bottom of your file (but before END!!), and then use CALL instruction followed by a procedure name. For example: לצורך שימוש בפרוצדורות ראשית עליך להגדיר את הפונקציה בסוף של התוכנית (אך לפני ה- END!!), ואז להשתמש בפקודת CALL ולאחריה שם הפרוצדורה. למשל:

 include 'emu8086.inc'

 ORG    100h

 LEA    SI, msg1       ; ask for the number    -     בקש מספר
 CALL   print_string   ;
 CALL   scan_num       ; get number in CX     CX-הכנס מספר ב

 MOV    AX, CX         ; copy the number to AX  -   AX-העתק ל

 ; print the following string:   -   :הדפס את המחרוזת שבהמשך
 CALL   pthis
 DB  13, 10, 'You have entered: ', 0

 CALL   print_num      ; print number in AX -  AX-הדפס מספר מ
                       ;            חזרה למערכת הפעלה
 RET                   ; return to operating system.

 msg1   DB  'Enter the number: ', 0

 DEFINE_SCAN_NUM
 DEFINE_PRINT_STRING
 DEFINE_PRINT_NUM
 DEFINE_PRINT_NUM_UNS  ; required for print_num       -דרוש ל
 DEFINE_PTHIS
                       ;                   פקודה לסיום ההידור
 END                   ; directive to stop the compiler.
First, compiler processes the declarations (these are just regular the macros that are expanded to procedures). When compiler gets to CALL instruction it replaces the procedure name with the address of the code where the procedure is declared. When CALL instruction is executed control is transferred to procedure. This is quite useful, since even if you call the same procedure 100 times in your code you will still have relatively small executable size. Seems complicated, isn't it? That's ok, with the time you will learn more, currently it's required that you understand the basic principle.

 בהתחלת ההידור המהדר מעבד את ההצהרות (ופקודות המקרו מפושטות לפרוצדורות).
כאשר המהדר מגיע לפקודת CALL הוא מחליף את השם של הפרוצדורה עם הכתובת של הצופן במקום בו הפרוצדורה מוצהרת.
כאשר הוראת CALL מבוצעת, השליטה מועברת לפרוצדורה.
דבר זה מאוד שימושי, כי אם אתה קורא לאותה פרוצדורה 100 פעמים בצופן התוכנית, גודל התוכנית יהיה עדיין קטן (באופן יחסי).
נראה מסובך נכון ? זה בסדר, עם הזמן אתה תלמד יותר, לפי שעה נידרש שתבין את העיקרון היסודי בלבד.

<<< to Part 4 <<   >> to Part 6 >>>

<<< לחלק 6 <<   >> לחלק 4 >>>