לדלג לתוכן

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) של המעבד - לא ניתן לשנות את זה או להשתמש ברגיסטר אחר.