שאלה בנוגע לאסמבלי

just a girl21

New member
../images/Emo35.gif שאלה בנוגע לאסמבלי

שאלה קצת מתוסבכת, מקווה שאני אסביר אותה כראוי... אנחנו בונים פסיקה, שתפקידה לקלוט 2 מספרים מהמשתמש, הראשון בין 0 ל9999, והשני בין 0 ל255, המספר הראשון נכנס לAx, והמספר השני נכנס לBL, אחריזה מתבצעת הפקודה div BL. הפסיקה שלנו אמורה לגרום לכך שגם אם התוצאה גדולה מכדי להכנס לAL תתבצע הפקודה. את רוב הפסיקה בניתי, אבל נתקעתי ב2 דברים עיקריים: 1. איך אני מקדם את IP? (כי כשביצעתי inc IP, וגם add byte prt ip,2 קיבלתי הודעת שגיאה) 2. אחרי שקלטתי את המספר, איך אני מרכיב את הקוד האסקי שקיבלתי למספר? תודה מראש, ומקווה שהשאלה הובנה
 

EmbeddedGuy

New member
תגובה...

ראשית, תמיד כששואלים שאלה באסמבלי, כדאי לציין את סוג המעבד, כי השפה הזו תלויית מעבד ספציפי (בניגוד נניח לשפות "גבוהות" יותר כמו C, אשר שם המעבד "לא חשוב" כי זהו תפקיד הקומפיילר (מהדר) להמיר את הטקסט שכתבת ב-C לשפת אסמבלי שמתאימה למעבד עליו מיועדת לרוץ התוכנה). אני מניח (לפי שמות הרגיסטרים) שאתה מתכוון למעבד ממשפחת 808X. אגב, למה אתה מנסה לקרוא ערכים בתוך פסיקה? האם זו פסיקת מקלדת או משהו כזה? בקשר לשאלה 1: כבר מזמן לא עבדתי עם האסמבלי של המעבד הזה, אבל אם אני לא טועה אין לך אפשרות לבצע פעולות מתמטיות על מצביע-הפקודה (IP) אלא מקסימום לטעון אליו ערך מסויים. אם אתה מעוניין לבצע משהו בכתובת מסויימת ואז להתקדם לכתובת הבאה ולבצע שם משהו, לדעתי אתה צריך להשתמש בזוג [DS:[BX, אני לא זוכר את צורת הכתיב המדוייק (כאמור, הרבה זמן לא השתמשתי באסמבלי הזה) אבל אני בטוח שאם תסתכל בדוגמאות קוד, מיד תבין כיצד להשתמש בזה, ואני בטוח שלבצע INC BX לא יהווה בעיה למהדר. בקשר לשאלה 2: השאלה לא כל-כך מובנת לי, נסה לחדד אותה. אם כבר קלטת את המספר, אז באיזה "פורמט" הוא במקור? האם זה "קוד מקש" (SCAN CODE) כלשהו או שזה ערך מספרי (נניח המקש "3" במקלדת מייצר בפסיקה שלך קלט בעל הערך 3). תסביר בדיוק מהו הקלט שלך ולאיזה פורמט אתה רוצה להמיר אותו, ואני אכתוב לך כיצד לבצע זאת.
 

pipfreak

New member
מממ....

קודם כל, תודה על התגובה! סליחה ששכחתי לציין, אחת האסמבלי שאני מדבר עליו הוא 80X86\88 עכשיו בנוגע לשאלות: הפסיקה לא אמורה לקלוט מספרים, אלא במידה ומתבצעת חלוקה של מספר בעל 4 סיביות במספר עם 2 סיביות במקום לקבל את הפסיקה "Divide by zero" לגרום לכך שתתבצע החלוקה. אז ככה: 1) איפה אפשר למצוא דוגמת קוד כמו שציינת? 2) אני קולט מספר בעזרת פונקציית דוס 0Ah, המספר נקלט לפי הקוד האסקי שלו, לאחר מכן אני רוצה לקחת את הקוד האסקי ולהפוך אותו למספר אמיתי (ולא לצירוף של קודים אסקיים...), לדוגמא אם נקלט המספר 8088 אז בזיכרון ימצא המספר 38, 38, 30, 38.... הבעיה להפוך את המספר בהניתן העובדה שאין לי מושג מכמה סיביות מורכב המספר, מספר הסיביות נע בין 0 ל4.... מקווה שהסברתי בצורה מספיק מדוייקת, ותודה מראש!
 

EmbeddedGuy

New member
תגובה...

דוגמאות קוד שמשתמשות ב-[DS:[BX אמורות להיות לך מהכיתה, זה אחד הדברים הבסיסיים שלומדים כאשר מלמדים אותך על אסמבלי של 808X. כמו-כן כמובן שיש את "גוגל" ושם זה לא בעיה לחפש משהו כמו "8086 source code" או "code samples 8086" ואז פשוט לעבור על התוצאות עד שתמצא משהו שמתאים לך. בקשר להפיכת הספרות למספר - לא כל-כך הבנתי למה שתכוונת כשרשמת "מספר הסיביות נע בין 0 ל-4..", איפה יש כאן משהו עם מספר סיביות משתנה? בכל-אופן, אם אתה קולט את הספרות הבודדות בתור ASCII, אז מה שאתה צריך לעשות זה להפחית מהערך ASCII של כל ספרה את הערך 30h וזה ייתן לך את ערך הספרה עצמה (למשל: "1" = 31h, אם תחסיר ממנו 30h תקבל 1) ואז כשיש לך את הערך של הספרה, אתה צריך לכפול אותה ב-10 בחזקת המיקום שלה. כלומר, אם זו הסיפרה הראשונה במספר, אתה כופל אותה ב-1, אם זו הספרה השניה אתה כופל אותה ב-10, אם זו השלישית כופל ב-100 וכך הלאה. סכום כל המכפלות ייתן לך את ערך המספר שהוכנס... אם לדוגמא קלטת מהמשתמש את הספרות 1,2,3,4 (הספרה 1 נקלטה ראשונה) אז אתה צריך לכפול את 4 ב-1, לכפול את 3 ב-10, את 2 ב-100 ואת 1 ב-1000. סכום המכפלות יתן לך את הערך 1234 וזהו בעצם המספר המבוקש.
 

pipfreak

New member
אמממ..

קודם כל, מסתבר שזה לא הדבר הראשון שלומדים בכיתה... לא למדנו הסבת סיגמנט בגלל שזה לא נמצא בחומר הלימוד של הנדסאי אלק' לטענת המכללה... אבל תודה על העצה בכל אופן, אחפש בגוגל... ובנוגע לשאלה השניה... התוכנה מבקשת מהמשתמש להכניס מספר בין 0 ל9999, ולאחר מכן מספר בין 0 ל255... אני משתמש בפונקציה 0AH.... עכשיו אני לא יודע מה מספר הספרות של המספר שהקיש המשתמש (אומנם הספרות שהוקשו נכנסות לזיכרון בסיום הפונקציה, אבל אני לא יודע איך להמשיך משם...), איך להרכיב את המספר אני יודע, אני לא יודע איך לעשות אתזה בתלות בספרות שהקיש המשתמש... מקווה שהשאלה הובנה יותר....
 

EmbeddedGuy

New member
תגובה...

הפונקציה 0AH מוסברת כאן בקצרה (חיפוש של 10 שניות בגוגל). לפי מה שמוסבר, אתה צריך לספק Buffer שהזוג DS:DX מצביע אליו. הבית הראשון בחוצץ הזה, מציין את הכמות המקסימלית של תווים שניתן לקלוט (שים שם 5 למשל). לפי ההסבר המופיע שם, אני מבין שהקלט נמשך עד שהמשתמש לוחץ על המקש <ENTER> (שגורם להכנסת התו carriage return לתוך החוצץ וסיום הקלט). לאחר סיום הקלט, הבייט השני בחוצץ אמור להכיל את כמות התווים שנקלטו, לא כולל הלחיצה על ה-<ENTER>. החל מהבייט השלישי והלאה בתוך החוצץ, אמורים להופיע הערכים של התווים שנקלטו. עכשיו נותר לך לחשב את ערך המספר: קח רגיסטר מסויים שיחזיק את הסכום ואפס אותו. קח רגיסטר אחר, תן לו את הערך 1, הכפל אותו בערך הראשון שנקלט והוסף אותו למשתנה הסכום. הכפל את הרגיסטר הזה ב-10 והכפל אותו בערך השני שנקלט והוסף לסכום. הכפל שוב את הרגיסטר ב-10 והכפל אותו בערך השלישי שנקלט וכך הלאה, עד שתגיע לספרה האחרונה שנקלטה (כאמור, אתה יודע כמה ספרות נקלטו וכמובן שיש לבצע את כל התהליך בתוך לולאה). בסוף התהליך, הערך שיש בתוך הרגיסטר "סכום", הוא ערך המספר המתקבל מצירוף כל הספרות שנקלטו... זהו. זה לא כל-כך מסובך, גם אם אתה לא מבין בדיוק את מה שכתבתי נסה לחשוב על זה רגע בעצמך ולהבין את ההגיון שמאחורי פעולת הפיכת ספרות בודדות למספר, ברגע שתבין את "הפטנט" אז תוכל לבצע את ההמרה בלי בעיות.
 

pipfreak

New member
תודה, אבל...

את כל זה כבר למדנו בכיתה, ויישמתי אתזה, אבל... הקוד שעשיתי מסרב להיבדק בdegud.... הוא מבצע פקודות שלא ביקשתי, אני אכניס את הקוד ותודיע אם נראה לך הגיוני שזה יעבוד?

mov bx,0 lea dx,num1 mov si,dx mov bl,[si+1] add si,2 dec bx mov dx,0 spoin1: mov ax,0 mov al,[si+bx] mov cx,dx sub al,30h cmp cx,0 jz spoin3 spoin2: mul num dec cx jnz spoin2 spoin3: add out1,ax inc dx dec bx jnz spoin1​
תודה מראש!
 

EmbeddedGuy

New member
מצטער, אבל...

אני לא ממש מצליח להבין מה הקוד שלך עושה.. בתיכנות מסודר נהוג לרשום הערות ליד כל שורה על-מנת לציין בקצרה את תפקידה (אם אני זוכר טוב, הערות באסמבלר מתחילות עם התו ";" לדוגמא: mov bx,0 ;Initialize the sum) למשל, אתה משתמש בתוכניתך בתווית "num1", אבל היא לא הוגדרה בשום מקום אחר בתוכנית, איך אני אמור לדעת מה זה מציין? אם אתה לא רוצה לשים הערה על כל שורה אז לפחות תשים לפני כל קטע. אין לי דרך לנחש מה היה "הרעיון" שרצית לממש בתוכנית ולכן אני לא יכול לדעת אם מה שכתבת הוא שגוי או לא...
 

EmbeddedGuy

New member
ואגב...

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

pipfreak

New member
אז ככה:

מה שצרפתי היה רק הקטע שאמור להפוך למספר... אתה צודק בזה שלא הוספתי הערות, אתוודה שאנלא תומך נלהב שלהם
הקוד עדין לא גמור, אם כי אני אתוודה שהוא בשלבי סיום... אצרף אותו, ואציין שהחלק האחרון (שעדין לא גמור) הוא החלק של הדפסת התו על המסך... כך שאם מה שעשיתי עד כה נכון זה אמור לעבוד... אז הנה הקוד:
.model small .stack 100h .data num1 dw 9999 num2 db 100 div_zero db 'Divide By ZERO!$' flag db 1 dup (0) .code div_int:cmp bl,0 jnz divide lea dx,div_zero mov ah,9 int 21h divide: mov flag,1 mov bp,sp add word ptr [bp],2 next: iret start: mov ax,@data mov ds,ax mov ax,0 mov ax,es:[0] push ax mov ax,es:[2] push ax mov ax,0 mov es,ax mov ax,offset div_int mov es:[0],ax mov ax,seg div_int mov es:[2],ax mov ax,[num1] mov bl,[num2] div bl cmp flag,1 jne no_div mov bh,0 div bx no_div: mov cx,0 mov si,1000h again: mov dx,0 mov bx,0 mov dl,[si] inc cx inc si cmp ax,0 jnz again print1: mov ax,0 pop ax mov es:[2],ax pop ax mov es:[0],ax mov ah,4ch int 21h end start​
מקווה שהפעם זה קצת יותר ברור
ושוב אציין שהתוכנית לא גמורה.... נשארה ההדפסה של המספר (תחת התווית print1), וקטע הקוד שלאחריו משחזר את הפסיקה שקדמה לפסיקה שאני יצרתי....
 

pipfreak

New member
אופס...

זה הקובץ לפני שהוספתי את השימוש בפונקציה.... אני צריך עוד לעבור על התוכנה החדשה כי היא מלאה בשטויות....
 

d70

Well-known member
מחסנית? ניתן לבצע ע"י PUSH ואז RET.... דוחפים (PUSH) את קוד סגמנט וה IP שרוצים שיגיע אליו. פקודת RET (שאמורה להחזיר אותנו מתת-שגרה) מתבצע תהליך הפוך שבו הקוד סגמנט וה IP שדחפנו מחסנית קודם יטען אל האוגרים CS:IP ...
 
למעלה