Merhaba. Bu yazıya, 80'lerin Monospace fontlarla yazılmış bilgisayar kitaplarından çıkmış gibi duran bir başlık seçtim, çünkü bu kez oldukça düşük seviye bir yaklaşımla 80'lerin teknolojisinden bahsedeceğim.
![]() |
80'lerin Teknolojisi (temsili) [1] |
Daha anlaşılabilir bir şekilde, VGA Text modunda smooth scroll nasıl yapılır, kesme (interrupt) kullanmadan doğrudan VGA belleği ve yazmaçları (register) nasıl kullanılır ona değindim. Ama önce VGA'ya kısa giriş yaptım ve bazı yazmaçları anlattım, arada biraz da geyik yaptım. Haliyle yazı düşündüğümden uzun oldu, ben de ikiye böldüm. Smooth scroll'un özü sonraki yazıya kaldı, çünkü kaydırmayla birlikte double buffering'den bahsetmek istiyorum. Bu da uzunca bir konu.
Uyarı: VGA yazmaçlarına, kullanılan donanıma uygun olmayan değerler yazmak donanıma kalıcı zarar verebilir. Burada verilen bilgiler gerçek bir tüplü monitörde denenmemiştir ve bunları kullanmanın riski yalnızca size aittir. Herhangi bir zarar ihtimali varsa, metnin yazarı sizi uyarmakta ve bundan sonrası için sorumluluk kabul etmemektedir.
![]() |
Orjinal VGA Kart (wikipedia) |
Giriş
VGA kartına genellikle int 10h BIOS arayüzünü kullanarak erişiyoruz. Ekran modunu seçmekten, imleci hareket ettirmeye veya büyüklüğünü ayarlamaya kadar herşey bu kesmeyle yapılabiliyor. Kesmenin yaptığı da zaten VGA yazmaçlarına "doğru biçimde" erişmek. VGA BIOS, gerekirse int 10h rutinlerini karta uygun şekilde değiştirebiliyor.
Int 10h'un ciddi bir yavaşlık getirdiğini düşünmüyorum (putpixel vb. işlemler hariç), hatta kesmeyi tercih etmenin bir avantajı da kodda karmaşıklıktan kaçınmak. VGA'nın çok sayıda yazmacı var [3]*. Bunların bazısının işlevini anlamak için temel CRT bilgisi gerekiyor. Diğer yandan bu yazı için DOSBox kullandığımı belirttim. DOSBox bir çok VGA registerini doğru emüle edebilse de bazı (standart dışı) efektleri düzgün gösteremiyor. Dolayısıyla bazı DOS oyunları düzgün çalışmıyor (konfigürasyon hatalarını bir kenara). Yine de DOSBox'un hakkını teslim etmek gerek, Vmware veya VirtualBox'la karşılaştırıldığında daha uyumlu (evet elmayla armudu karşılaştırdım: biri DOS'a özel, diğerleri genel sanallaştırma).
* Adı geçen kaynakta 300+ yazmaçtan bahsediliyor ama 100 tane bile dökümante edilmemiş. Muhtemelen, farklı üreticilerin kendi ekledikleri standart dışı yazmaçlar sayılıyor. Standart yazmaçlar yaklaşık 60 tane, ama bu da az değil.
VGA Yazmaçları ve Karta Erişmek
Yukarıda da yazdığım gibi bir çok VGA yazmacı var. Şu linkte yazmaçlar altı grupta toplanıyor. Bu yazıda ben çoğunlukla CRT denetleyici (CRT controller - CRTC) yazmaçlarına erişeceğim. Gruplar kabaca erişimde kullanılan port numaralarına göre oluşturuluyor.
Bu yazmaçlara, kabaca 6 çift donanım portu üzerinden erişiliyor. Yani altmış yazmacın her birine bir port atanmamış. [3]'te portların bir listesi var. Genel olarak erişim, 0x3DX'e yazmaç index numarasını girdikten sonra, 0x3DX+1'den yazmaçtaki değeri okumak veya değere yazmak şeklinde. 0x3D0'ın bir istisnası var ama ona değinmeyeceğim. Yazının ileriki bölümlerinde bu yazmaçlarla ilgili örnek göstereceğim.
Burada tüm yazmaçlara yer verip yazıyı bir referans kitabı haline getirmek istemedim. O yüzden sadece ilgilendiğim kısma odaklanacağım. Örneğin: CRTC'ye, 0x3D4 ve 0x3D5 portları üzerinden ulaşılıyor. 0x3D4 yazmaç seçme, 0x3D5 ise veri okuma ve yazma portu [5].
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
CD | Cursor Scan Line Start |
Şimdi [6]'daki imleci devre dışı bırakma kodunu ele alalım:
{
outb(0x3D4, 0x0A);
outb(0x3D5, 0x20);
}
Önce 0x3D4 portuna 0xA yazmacına erişeceğimizi bildiriyoruz. Ardından bu yazmaca 0x3D5 portu aracılığıyla 0x20 değerini yazıyoruz. Bu değer 0xA'nın 5. bitini yani Cursor Disable bitini set ediyor [5]. Oldukça basit.
Cursor Scan Line Start, imlecin hangi pixelden başlayacağını gösteriyor. Standart 80x25 karakter ekran modunda (Mod 3), her karakter ve imlecin kendisi 8x16 pixelden oluşan bir görsel. Bu görseller değiştirilerek DOS'ta font yüklenebilir. Aşağıda, DOS için bir font düzenleme programından aldığım ekran görüntüsünde, örnek bir karakter yakından görülüyor. Font tablosu VGA BIOS'ta bulunuyor (meraklısına Int 10h / 1130h) ve özel fontlar bu alana geçici olarak yazılıyor (bilgisayar yeniden başlatılana kadar). Fontlar başlı başına bir yazı konusu, daha fazla detaylandırmayacağım.
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Cursor Skew | Cursor Scan Line End |
Bu yazmaç imlecin alt pixel satırını tutar. Peki eğer bir karakter 16 pixel uzunluğundaysa neden 5 bit? VGA, metin modunda aslında 32 pixele kadar olan karakterleri destekler [6]. Örn. VGA font tablosu 8 KB uzunluktadır: Karakterlerin sayısı (256) * yüksekliği (32 px) * genişliği (8 px) / bit per byte (8). Bu yüzden imleç için de yazmaçta 5 bit yer ayrılmıştır, ancak dördüncü bitin hiçbir metin modunda anlamı yoktur. Cursor Skew bitleri EGA uyumluluğu için bırakılmıştır, yine VGA'da bir anlamı yoktur.
Anlaşılması kolay başka bir yazmaç çifti de Cursor Location High (0xE) ve Cursor Location Low (0xF) yazmaçlarıdır. İmlecin ekrandaki doğrusal konum bilgisini tutarlar. Bu değer, ekranın karakter çözünürlüğüne (bizim örneğimizde 80) kalanlı bölündüğünde bölüm, imlecin y-eksenindeki; ve kalan, imlecin x-eksenindeki yerini verir. Tersi ifadeyle D = Y * 80 + X. Bu yazmaçlar byte uzunlukta olduklarından D'nin yüksek anlamlı byte'ı 0xE'ye, düşük anlamlı byte'ı 0xF'e yazılır.
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Cursor Location High |
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Cursor Location Low |
80'lere Geri Dönüş: QBasic
Şimdi bu iki çift yazmaçla küçük bir demo yapacağım ve bunun için ilginç bir şekilde QBasic kullanacağım. Aslında ben de pek çok kişi gibi programlamayı Basic'le öğrendim. Biraz C64 Basic, sonrasında GW-Basic (o zamanın TRT'si sağolsun, TRT4 Açıköğretim Bilgisayar derslerı) ve son olarak QBasic. Ve iddia ediyorum ki 80'lerde doğup 90'larda bilgisayarı olan herkes aşağıdaki IDE'yi en az bir kere görmüştür. Ben 90'larda .bat dosyaların yetersiz kaldığı durumlarda betiklerimi QB ile yazardım. Sonrasında QBasic'in hızı bir çok şey için yetersiz gelince, bu beni C ve Assembly öğrenmeye itmişti. -Arada kısa bir Pascal dönemim de oldu.- Bu arada QBasic bir yorumlayıcıydı (interpreter) ve .exe dosya üretememesi benim için başka bir eksiklikti. C ile yakın zamanlarda Quick Basic v4.5 ile tanışsam da, C'nin açtığı ufuk bambaşkaydı. Ayrıca o zamanlarda Quick Basic 4.5 IDE'yi bulmak da -en azından benim için- oldukça zordu.
Ve neredeyse on yıldır blog yazıp, bu yazılarda bir sürü dilde örnek program yazmama rağmen, tek bir QB örneği vermediğimi fark ettim. Oysa bu tür basit kod parçaları için QB bence daha kolay, çünkü ne Assembly kadar çok satıra gerek var, ne de C'deki gibi include ekle, type cast'lere dikkat et, buffer'ı kontrol et gibi konular yok. Kısacası bu kadar retrospective yeter. Bu yazıdaki örneği QB ile veriyorum:
DECLARE SUB DISABLECURSOR ()
DECLARE SUB MOVECURSOR (CURSORX%, CURSORY%)
FOR X% = 0 TO 15
FOR Y% = X% TO 15
CALL ENABLECURSOR(X%, Y%)
SLEEP 1
CALL DISABLECURSOR
SLEEP 1
NEXT Y%
NEXT X%
CALL ENABLECURSOR(0, 15)
FOR Y% = 0 TO 10
FOR X% = 0 TO 10
CALL MOVECURSOR(X%, Y%)
SLEEP 1
NEXT X%
NEXT Y%
SUB DISABLECURSOR
OUT &H3D4, &HA
OUT &H3D5, &H20
END SUB
SUB ENABLECURSOR (CURSTART%, CUREND%)
OUT &H3D4, &HA
CS1% = INP(&H3D5)
OUT &H3D5, (CS1% AND &HC0) OR CURSTART%
OUT &H3D4, &HB
CE1% = INP(&H3D5)
OUT &H3D5, (CE1% AND &HE0) OR CUREND%
END SUB
SUB MOVECURSOR (CURSORX%, CURSORY%)
POSITION% = CURSORY% * 80 + CURSORX%
OUT &H3D4, &HF
OUT &H3D5, POSITION% AND 255
OUT &H3D4, &HE
OUT &H3D5, POSITION% \ 256
END SUB
Kod biraz uzun ama genel olarak [4]'teki kodları içeriyor. İlk bölümde imlecin alabileceği kombinasyonları bir for döngüsünde oluşturdum. Parametreler ENABLECURSOR alt programında ilgili yazmaçlara gönderiliyor. Bu arada döngü içerisinde bir saniyelik bekleme (SLEEP) CTRL tuşu basılı tutularak geçilebilir.
İlk for döngüsünden sonra rahat görülebilmesi için imleci büyütüp, MOVECURSOR alt programıyla ekranın 10 x 10'luk bölümünde hareket ettirdim. MOVECURSOR'de ekranın 80 karakter genişlikte olduğunu varsayıp, (X, Y) koordinatlarından imlecin doğrusal konumunu hesaplattım.
Bir sonraki yazıda başta yumuşak kaydırma için gereken yazmaçlar olmak üzere diğer VGA yazmaçlarına değineceğim ve QB ile başka örnekler vereceğim. Ancak kaydırma işlemi yüksek hız gerektirdiği için onu Assembly + C ile yazdım, ve yazının başlarında değineceğimi söylediğim waitretrace fonksiyonunu kullandım.
[1]: DEC PDP8 Family User's Guide TSS/8 (1970). Link
[2]: https://retrocomputing.stackexc....damage-my-vga-card-by-programming-it-in-assembly-throu
[3]: http://wiki.osdev.org/VGA_Hardware
[4]: http://wiki.osdev.org/Text_Mode_Cursor
[5]: http://www.osdever.net/FreeVGA/vga/crtcreg.htm
[6]: https://en.wikipedia.org/wiki/VGA_text_mode#Fonts