1.7 - קלט ופלט - פתרון
תרגיל 1 - read_key.asm¶
IDEAL
MODEL small
STACK 100h
CODESEG
start:
mov dx, 0x60 ; keyboard port address
in al, dx ; read a character from the port
mov ah, 0Eh ; BIOS display service
mov bh, 0
mov bl, 7
int 10h ; display the character
mov ax, 4C00h ; standard exit
int 21h
END start
תרגיל 2 - wait_and_read.asm¶
IDEAL
MODEL small
STACK 100h
CODESEG
start:
wait_key:
in al, 0x64 ; check the keyboard status port
test al, 1 ; is bit 0 on? (character ready?)
jz wait_key ; if not - keep waiting
in al, 0x60 ; read the character from the keyboard port
mov ah, 0Eh ; BIOS TTY service
mov bh, 0
mov bl, 7
int 10h ; display the character
mov ax, 4C00h
int 21h
END start
הסבר: הפקודה TEST AL, 1 מבצעת AND לוגי בין AL לבין 1 (ביט 0 בלבד). אם התוצאה היא 0 - סימן שאין תו מוכן, ו-JZ מחזיר אותנו ללולאה. כשביט 0 דולק - יש תו מוכן ואפשר לקרוא אותו מפורט 0x60.
תרגיל 3 - write_port.asm¶
IDEAL
MODEL small
STACK 100h
CODESEG
start:
mov dx, 0x300 ; address of the LED card port
mov al, 0b11001100 ; first value - turns on some of the LEDs
out dx, al ; send to the port
mov al, 0b00110011 ; second value - turns on other LEDs
out dx, al ; send to the port
mov ax, 4C00h ; standard exit
int 21h
END start
הסבר: בכל פקודת OUT, הערך שב-AL עובר דרך ה-Data Bus, וכתובת הפורט שב-DX עוברת דרך ה-Address Bus. ההתקן בפורט 0x300 מקבל את הערך ומדליק את הנוריות בהתאם לביטים הדולקים.
תרגיל 4 - keyboard_driver.asm¶
IDEAL
MODEL small
STACK 100h
CODESEG
start:
keyboard_loop:
in al, 0x64 ; check the keyboard status
test al, 1 ; is bit 0 on? (is a character ready?)
jz keyboard_loop ; if not - go back to the start of the loop
in al, 0x60 ; read the character from the keyboard port
mov ah, 0Eh ; BIOS TTY service
mov bh, 0
mov bl, 7
int 10h ; display the character on the screen
jmp keyboard_loop ; go back to the loop - keep reading characters
END start
הסבר: זהו דרייבר מקלדת פשוט שרץ בלולאה אינסופית. בכל סיבוב הוא בודק אם יש תו מוכן, ואם כן - קורא אותו ומציג אותו. שימו לב שהתוכנית לא מסתיימת - היא רצה לנצח כמו שדרייבר אמיתי היה עושה. בעולם האמיתי, דרייבר מקלדת עובד עם פסיקות ולא עם לולאת polling כזו, אבל העיקרון דומה.
תרגיל 5 - תשובות לשאלות ההבנה¶
1. מה עובר בכל Bus בפקודת OUT DX, AL?
- Data Bus - הערך שנמצא ב-AL (הנתון שנשלח להתקן)
- Address Bus - כתובת הפורט שנמצאת ב-DX
- Control Bus - אות IO Write (לא Memory Write) - שמציין שמדובר בכתיבה לפורט I/O ולא לזיכרון RAM
2. מה ההבדל בין Memory-Mapped I/O לבין Port-Mapped I/O?
- ב-Memory-Mapped I/O - התקני ה-I/O מקבלים כתובות בתוך מרחב הכתובות של ה-RAM. פונים אליהם עם אותן פקודות שפונים לזיכרון (MOV וכו').
- ב-Port-Mapped I/O (שבו אנחנו משתמשים ב-8086) - יש מרחב כתובות נפרד ייעודי ל-I/O. פונים אליו רק עם הפקודות
INו-OUT. ה-Control Bus מבדיל בין גישה לזיכרון לבין גישה ל-I/O.
3. כמה פורטים יכולים להיות ב-8086?
תאורטית - 64KB של פורטים (כתובות 0x0000 עד 0xFFFF, כי כתובת הפורט היא 16 ביט). בפועל, לרוב משתמשים ב-256 פורטים בלבד (כתובות 0x00 עד 0xFF).
4. למה DX משמש תמיד לכתובת הפורט?
זוהי מוסכמה קבועה של ארכיטקטורת x86. הפקודות IN ו-OUT תוכננו כך שהן תמיד משתמשות ב-DX לכתובת הפורט וב-AL/AX לנתון. זה חלק מהגדרת ה-ISA (Instruction Set Architecture) של המעבד - לא ניתן לשנות את זה או להשתמש ברגיסטר אחר.