SEN2201 · 6. hafta · The von Neumann Model (I/O basics)

Giriş/çıkış temelleri: memory-mapped I/O ve polling

Klavye ve ekranın LC-3'e nasıl bağlandığı: KBSR/KBDR/DSR/DDR register'ları, ready bit, polling döngüsü, interrupt farkı ve TRAP servis rutinlerine giriş.

input/output (I/O)memory-mapped I/Odevice registerKBSRKBDRDSRDDRready bitpollinginterrupt-driven I/OasynchronoussynchronousTRAPservice routinetrap vector table

Bir bilgisayar sadece hesap yapsaydı işe yaramazdı: veriyi bir yerden almalı, sonucu bir yere vermeli. von Neumann modelinin input ve output parçaları bu işi yapar. Bu sayfada LC-3’ün klavye ve ekranla nasıl konuştuğunu öğreneceksin. Mekanizma basit: aygıtın iki register’ı var, biri “hazır mısın?” sorusunun cevabını, diğeri karakterin kendisini tutar.

Bu konu 7-8. haftanın LC-3 komutlarını (LDI, STI, BR) kullanır. Henüz o komutları görmediysen bu sayfayı onlardan sonra tekrar oku; burada her komutun ne yaptığını tek cümleyle açıklıyoruz.

Aygıt register’ları

Her I/O aygıtının en az iki register’ı vardır:

  • Data register: aktarılan veri (karakter).
  • Status register: aygıtın durumu, özellikle “hazır” bilgisi.

LC-3’te klavyenin ve ekranın register’ları:

RegisterAdresİçerik
KBSR (keyboard status)xFE00bit 15: yeni karakter var mı
KBDR (keyboard data)xFE02bit 7:0: basılan karakterin ASCII kodu
DSR (display status)xFE04bit 15: ekran yeni karakter almaya hazır mı
DDR (display data)xFE06bit 7:0: ekrana yazılacak karakter

Memory-mapped I/O

Bazı işlemcilerde I/O için özel komutlar vardır (IN, OUT gibi). LC-3 bunu yapmaz: aygıt register’larına bellek adresi verilir. İşlemci onlara normal bellek gibi yükleme ve saklama komutlarıyla erişir. Bellek arayüzü adresin xFE00 bölgesinde olduğunu görünce isteği belleğe değil aygıta yönlendirir. Buna memory-mapped I/O denir.

Sonuç: “klavyeden oku” = “xFE02 adresini oku”. “Ekrana yaz” = “xFE06 adresine yaz”.

Neden LDI ve STI?

LD ve ST komutları PC’nin yakınındaki bir adrese erişebilir: PC + offset, offset 9 bit, yani -256..+255. Programın x3000 civarında. xFE00 çok uzak. Çözüm: aygıtın adresini programın yanına bir pointer olarak koy ve dolaylı (indirect) eriş.

KBSRP   .FILL xFE00     ; KBSR'nin adresi programın içinde
...
        LDI  R1, KBSRP  ; R1 ← M[M[KBSRP]] = M[xFE00] = KBSR

LDI R1, KBSRP iki adımda okur: önce KBSRP’deki değeri (xFE00) alır, sonra o adresin içeriğini R1’e koyar. STI aynı şeyi yazma için yapar.

Senkronizasyon: ready bit

Klavye asenkrondur: kullanıcının ne zaman tuşa basacağı belli değil. İşlemci ise saniyede milyarlarca komut çalıştırır. İkisinin uyumlu çalışması için bir el sıkışma (handshake) gerekir. Bunu ready bit sağlar.

Klavye tarafı:

  1. Kullanıcı tuşa basar. Klavye ASCII kodu KBDR’ye koyar ve KBSR[15] = 1 yapar.
  2. İşlemci KBDR’yi okur. Okuma anında KBSR[15] otomatik olarak 0 olur.
  3. KBSR[15] = 0 iken klavye yeni karakteri KBDR’ye yazmaz; böylece okunmamış karakter ezilmez.

Ekran tarafı:

  1. DSR[15] = 1 ise ekran hazır.
  2. İşlemci DDR’ye karakteri yazar. DSR[15] = 0 olur.
  3. Ekran karakteri bastıktan sonra DSR[15] = 1 olur.

İPUCU · Neden BRzp? Ready bit bit 15, yani 16 bitlik sayının işaret biti. Hazırsa register’a yüklenen değer negatiftir (N). Hazır değilse 0 ya da pozitif (Z ya da P). “Hazır olmadığı sürece bekle” = BRzp ile başa dön.

Polling

İşlemcinin ready bit’ini bir döngüde tekrar tekrar okumasına polling denir.

Klavyeden bir karakter oku:

POLL    LDI  R1, KBSRP   ; R1 ← KBSR
        BRzp POLL        ; bit 15 = 0 → hazır değil, tekrar sor
        LDI  R0, KBDRP   ; R0 ← KBDR (karakter)

Ekrana bir karakter yaz:

POLL2   LDI  R1, DSRP    ; R1 ← DSR
        BRzp POLL2       ; ekran meşgul, bekle
        STI  R0, DDRP    ; DDR ← R0

Çözümlü örnek: echo

Klavyeden bir karakter oku ve ekrana yaz.

        .ORIG x3000
START   LDI  R1, KBSRP
        BRzp START
        LDI  R0, KBDRP
ECHO    LDI  R1, DSRP
        BRzp ECHO
        STI  R0, DDRP
        HALT
KBSRP   .FILL xFE00
KBDRP   .FILL xFE02
DSRP    .FILL xFE04
DDRP    .FILL xFE06
        .END

Kullanıcı k yazınca:

k

Program bitince R0 = x006B (‘k’ ASCII kodu), R1 = x8000 (son okunan DSR, hazır), condition code N.

Polling ile interrupt farkı

PollingInterrupt-driven
Kim sorar?İşlemci sürekli ready bit’ini okurAygıt hazır olunca işlemciye sinyal gönderir
Bekleme sırasında işlemciDöngüde boşa dönerBaşka program çalıştırır
VerimDüşük (çoğu döngü boşuna)Yüksek
BasitlikÇok basitKesme mekanizması gerekir

Bir insan saniyede belki 5 tuşa basar, işlemci o sürede milyarlarca komut çalıştırabilir. Polling bu zamanın neredeyse tamamını boşa harcar. Interrupt’ta işlemci kendi işini yapar, aygıt hazır olunca kısa bir servis rutini çalışır ve işlemci kaldığı yere döner.

TRAP: işletim sistemine bırak

Her programda bu polling döngülerini yazmak hem zahmetli hem tehlikeli (bir kullanıcı programının aygıt register’larıyla oynamasını istemezsin). LC-3’te bu iş işletim sistemindeki servis rutinlerine bırakılır. Kullanıcı programı TRAP komutuyla bunları çağırır.

TRAPTakma adNe yapar?
x20GETCBir karakter oku, R0’a koy (ekrana yazmaz)
x21OUTR0[7:0]‘daki karakteri ekrana yaz
x22PUTSR0’daki adresten başlayan string’i x0000’a kadar yaz
x23INİstem yaz, bir karakter oku, ekrana da yaz, R0’a koy
x25HALTMakineyi durdur

TRAP x23 çalışınca:

  1. Dönüş adresi saklanır: R7 ← PC (zaten artmış PC).
  2. PC ← M[x0023]. x0000-x00FF arası trap vector table’dır; her satırda bir servis rutininin başlangıç adresi var.
  3. Servis rutini kendi polling döngüsüyle işini yapar.
  4. Sonunda RET (= JMP R7) ile kullanıcı programına döner.

Çözümlü örnek: klavyeden bir rakam oku, iki katını yaz.

        GETC                ; R0 ← '3' = x33
        LD   R1, NEG30      ; R1 ← -48
        ADD  R2, R0, R1     ; R2 ← 3 (sayı)
        ADD  R0, R2, R2     ; R0 ← 6
        LD   R1, POS30      ; R1 ← 48
        ADD  R0, R0, R1     ; R0 ← '6'
        OUT
        HALT
NEG30   .FILL #-48
POS30   .FILL #48

Kullanıcı 3 yazarsa:

6

TUZAK · R7’yi ezmek. TRAP, dönüş adresini R7’ye yazar. Programında R7’de önemli bir değer tutuyorsan TRAP’ten sonra kaybolur. Önce başka yere kaydet.

Sık yapılan hatalar

Yanlış düşünceDoğrusu
Ready bit bit 0Bit 15 (işaret biti)
Hazırken değer pozitifBit 15 = 1 → negatif, N
Bekleme döngüsü BRn ileHazır olmadığı sürece dön: BRzp
LD R1, xFE00 çalışıroffset9 o kadar uzağa ulaşmaz; LDI + .FILL
KBDR okumak KBSR’yi değiştirmezOkuyunca KBSR[15] = 0 olur
DSR’ye bakmadan DDR’ye yazEkran meşgulse karakter kaybolur
Polling işlemciyi serbest bırakırİşlemci döngüde boşa döner
TRAP dönüş adresini yığına atarR7’ye yazar

Kendini test et

Sınavdaki gibi İngilizce sorular. Önce kâğıt kalemle çöz, sonra cevabı aç.

Soru 1kolay

What is memory-mapped I/O?

Cevabı göster
Device registers are assigned memory addresses and accessed with load/store instructions

Aygıt register'ları (KBSR, KBDR, DSR, DDR) bellek adreslerine yerleştirilir. İşlemci ayrı I/O komutları kullanmaz; aynı LD/ST ailesiyle (LDI, STI) bu adreslere erişir. Bellek arayüzü adres xFE00 ve üstüne gelince isteği belleğe değil aygıta yönlendirir.

Soru 2kolay

Give the LC-3 memory-mapped addresses of KBSR, KBDR, DSR and DDR.

Cevabı göster
xFE00, xFE02, xFE04, xFE06

Klavye: status xFE00, data xFE02. Ekran: status xFE04, data xFE06. Status register'larında hazır bitini, data register'larında karakteri (bitler [7:0]) bulursun.

Soru 3kolay

Which bit of KBSR tells the processor that a new character is available?

Cevabı göster
Bit 15

KBSR[15] ready bit'idir. Tuşa basılınca klavye karakteri KBDR'ye koyar ve KBSR[15] = 1 yapar. İşlemci KBDR'yi okuyunca bu bit otomatik olarak 0'lanır.

Soru 4orta

A polling loop is: POLL LDI R1, KBSRP followed by BRzp POLL. Why is BRzp the right branch?

Cevabı göster
Ready bit is bit 15, so the value is negative when ready; loop while zero or positive

LDI ile KBSR R1'e yüklenir ve condition code'lar ayarlanır. Bit 15 = 1 ise 16 bitlik değer 2's complement'te negatiftir (N). Hazır değilse değer 0 ya da pozitif (Z/P). BRzp, hazır olmadığı sürece başa döner; hazır olunca düşüp sonraki komuta geçer.

Soru 5orta

Why does the program use LDI R1, KBSRP (with KBSRP .FILL xFE00) instead of LD R1, xFE00?

Cevabı göster
xFE00 is out of range of the 9-bit PC-relative offset

LD'nin adresi PC + offset9, yani PC'nin -256..+255 yakınında. x3001'den xFE00'a uzaklık 52735, sığmaz. Bu yüzden adres yakındaki bir konuma .FILL ile yazılır ve LDI ile dolaylı (indirect) okunur.

Soru 6kolay

When the keyboard is ready and KBSR = x8000, what condition code is set by LDI R1, KBSRP?

Cevabı göster
N

x8000 = 1000 0000 0000 0000, MSB 1 → negatif. Yüklenen değere göre N = 1, Z = P = 0. Hazır değilken KBSR = x0000 → Z.

Soru 7orta

Why must the program check DSR[15] before writing a character into DDR?

Cevabı göster
The display is slower; writing before it is ready would lose characters

İşlemci ekrandan çok daha hızlıdır. DDR'ye yazılan karakter ekrana basılırken DSR[15] = 0 olur. Bitmeden yeni karakter yazarsan öncekinin üstüne yazar, karakter kaybolur. DSR[15] = 1 olunca yazmak güvenlidir.

Soru 8orta

What is the difference between polling and interrupt-driven I/O?

Cevabı göster
Polling: CPU repeatedly checks the ready bit; interrupt: the device signals the CPU when ready

Polling'de işlemci bir döngüde ready bit'ini sürekli okur, bu sürede başka iş yapamaz (zaman kaybı). Interrupt-driven I/O'da işlemci kendi işine devam eder; aygıt hazır olunca işlemciyi keser, işlemci kısa bir servis rutini çalıştırıp kaldığı yere döner.

Soru 9kolay

Is keyboard input synchronous or asynchronous? Why?

Cevabı göster
Asynchronous

Kullanıcı tuşlara işlemcinin saatine göre değil, kendi hızında basar. Karakterin ne zaman geleceği bilinmez. Bu yüzden ready bit gibi bir el sıkışma (handshake) mekanizması gerekir.

Soru 10orta

The program below reads two characters and prints each one plus 1. If the user types HI, what is printed?

        AND  R2, R2, #0
        ADD  R2, R2, #2
AGAIN   LDI  R1, KBSRP
        BRzp AGAIN
        LDI  R0, KBDRP
        ADD  R0, R0, #1
WAIT    LDI  R1, DSRP
        BRzp WAIT
        STI  R0, DDRP
        ADD  R2, R2, #-1
        BRp  AGAIN
        HALT
Cevabı göster
IJ

R2 sayaç (2). Her turda bir karakter okunur, ASCII kodu 1 artırılır, ekrana yazılır. 'H' = x48 → x49 = 'I'. 'I' = x49 → x4A = 'J'. R2 0 olunca BRp düşer, HALT.

Soru 11zor

In the program above, why is the counter decremented right before BRp AGAIN and not earlier?

Cevabı göster
BRp tests the condition codes of the last instruction that wrote a register, the ADD R2

Condition code'ları register'a yazan son komut belirler. ADD R2, R2, #-1 hemen önce olduğu için BRp, R2'nin yeni değerine bakar. Araya LDI R1 gibi bir yükleme girseydi BRp R1'e göre karar verirdi ve döngü bozulurdu.

Soru 12zor

A user program executes TRAP x23. Where does the processor find the starting address of the service routine?

Cevabı göster
In memory location x0023 (trap vector table)

TRAP komutu 8 bitlik trapvect'i 16 bite sıfırla genişletir ve o adresteki değeri PC'ye yükler: PC ← M[x0023]. x0000-x00FF arası trap vector table'dır. Ayrıca dönüş adresi R7'ye kaydedilir (R7 ← artmış PC).

Doğrulama: Polling programları ve TRAP örneği kendi LC-3 simülatörümüzde (klavye ve ekran register'ları xFE00-xFE06 adreslerine eşlenmiş olarak) çalıştırıldı; çıktılar, register değerleri ve condition code'lar oradan alındı (verify/SEN2201/06.mjs).

Deftere not kartı

Memory-mapped I/O: aygıt register'ları = bellek adresleri, LDI/STI ile eriş KBSR xFE00 | KBDR xFE02 | DSR xFE04 | DDR xFE06 Ready bit = bit 15. Hazırsa değer NEGATİF (N) Klavye: KBSR[15]=1 -> karakter KBDR[7:0]'da; KBDR okununca KBSR[15]=0 Ekran: DSR[15]=1 -> DDR'ye yaz; yazınca DSR[15]=0 olur Okuma: POLL LDI R1,KBSRP / BRzp POLL / LDI R0,KBDRP Yazma: POLL2 LDI R1,DSRP / BRzp POLL2 / STI R0,DDRP KBSRP .FILL xFE00 (LD uzaktan erişemez, offset9 = -256..255) Polling: CPU sürekli sorar (zaman kaybı) | Interrupt: aygıt CPU'yu keser Klavye asenkron -> handshake (ready bit) TRAP x20 GETC | x21 OUT | x22 PUTS | x23 IN | x25 HALT TRAP: R7 <- PC, PC <- M[trapvect] (tablo x0000-x00FF); dönüş: RET (JMP R7)