Merhaba arkadaşlar.
Konu başlığından da anlaşılacağı üzere bu bölümü temsil eden yazı, kafamdaki müfredat için bir ekstra niteliğindedir. Lütfen aşağıdaki yazılanları irdelerken ezber değil, olayı anlama yöntemini tercih edin. İhtiyacınız olacak tüm açıklamaları tıpkı önceki yazılarımda olduğu gibi ekleyeceğim.
Not: Programı anlamakta zorlanırsanız veya sınavda kafanızın karışabileceğini düşünürseniz, ilgili rutinlerin çıktısını yanınıza alın. Sınavdaki sorunun birkaç küçük değişikliği olursa uydurmaya çalışmak daha güvenli olur.
Özel Bölüm 1 - NMI Kesmesi
NMI Kesmesinin Özelliği
NMI kesmesinin işleyişinin öteki kesmelerden herhangi bir farkı yoktur. Etkin hale gelmesi hususunda ise 8259 PIC(Programmable Interrupt Controller) yongasının ürettiği donanım kesmelerinden tek farkı, işlemci üzerindeki FLAGS yazmacında yer alan Interrupt Flag(Kesme Bayrağı)'ın değerinden bağımsız olarak çalışmasıdır. Öteki donanım kesmelerinin tamamı, ancak IF=1 olduğu durumlarda çalışırlar.
Genel olarak kesmelerin çalışmaları, kesme vektöründe(bkz. Bölüm - 4 - COM ve EXE Dosya Biçimleri - PSP ve Yapısı bölümündeki dip notlar) yer alan adresin CALL FAR xxxx:yyyy şeklinde çağırılması şeklinde olmasına karşın, normal alt program çağırımına ek olarak FLAGS yazmacını da yığına atarlar. Bu durumun açık sebebi, kesmenin ne zaman ve nasıl meydana geleceğinin belli olmamasıdır. Aksi takdirde zamansız gelen bir kesme, bayrakları göz önünde bulundurarak işlem yapan bir program parçacığının istenenin dışında sonuç üretmesine zemin hazırlayabilir.
NMI Kesmesi ile Dışarıdan Anahtarlamalı Çoklu Görev (External Switched Multitasking)
Windows ve benzeri işletim sistemleri tarafından işlemci ve yazılım özellikleri ile çoklu görev sağlanmasına karşın, giriş ve çıkış birimlerinin kısıtlı olduğu veya bulunmadığı denetim sistemlerinde çoklu görev için NMI kesmesini kullanmak uygun bir çözüm olabilir. Bu gibi bir kullanımda NMI kesmesi hizmet programı, "tıkırı tıkırına" işleyen bir çoklu görev sisteminin yöneticisi olarak kabul edilebilir.
NMI kesmesi ile çoklu görev sağlamak, işlemciyi bir nevi aldatmaya benzer. Kesme hizmet programı her çağırıldığında, kendisinin çağırılışı esnasında yığına atılan CS, IP, FLAGS değerlerini, önceden bilinen bir bellek bölgesindeki alt program konumları ile değiştirmelidir. Ancak başta SP olmak üzere, geri kalan tüm genel amaçlı yazmaçlar da programın konumunu ve işleyişini doğrudan ilgilendirir. Dolayısıyla tüm bu yazmaçların da korunumu gereklidir.
Aşağıda, 4 programın zaman paylaşımlı olarak çalıştırılabilmesi için gerekli olan vektörler tablo halinde verilmiştir.
|
Öğe |
Konum Ofseti |
|
Program 1 - AX |
xxxx:0000 |
|
Program 1 - BX |
xxxx:0002 |
|
Program 1 - CX |
xxxx:0004 |
|
Program 1 - DX |
xxxx:0006 |
|
Program 1 - SP |
xxxx:0008 |
|
Program 1 - BP |
xxxx:000A |
|
Program 1 - SI |
xxxx:000C |
|
Program 1 - DI |
xxxx:000E |
|
Program 2 - AX |
xxxx:0100 |
|
Program 2 - BX |
xxxx:0102 |
|
Program 2 - CX |
xxxx:0104 |
|
Program 2 - DX |
xxxx:0106 |
|
Program 2 - SP |
xxxx:0108 |
|
Program 2 - BP |
xxxx:010A |
|
Program 2 - SI |
xxxx:010C |
|
Program 2 - DI |
xxxx:010E |
|
Program 3 - AX |
xxxx:0200 |
|
Program 3 - BX |
xxxx:0202 |
|
Program 3 - CX |
xxxx:0204 |
|
Program 3 - DX |
xxxx:0206 |
|
Program 3 - SP |
xxxx:0208 |
|
Program 3 - BP |
xxxx:020A |
|
Program 3 - SI |
xxxx:020C |
|
Program 3 - DI |
xxxx:020E |
|
Program 4 - AX |
xxxx:0300 |
|
Program 4 - BX |
xxxx:0302 |
|
Program 4 - CX |
xxxx:0304 |
|
Program 4 - DX |
xxxx:0306 |
|
Program 4 - SP |
xxxx:0308 |
|
Program 4 - BP |
xxxx:030A |
|
Program 4 - SI |
xxxx:030C |
|
Program 4 - DI |
xxxx:030E |
|
Çalışan programın numarası (0 - 3) |
xxxx:0400 |
Tablo - 1 Genel Açıklama Tablosu(Global Descriptor Table)
Kesme hizmet programı, her çağırıldığında xxxx:0400 numaralı bellek gözünü okuyarak aktif programın ve geçiş yapılacak programın (0-3 arasında) hangisi olduğunu öğrenecek ve gerekli değişiklikleri yapacaktır.
Aşağıdaki program, xxxx segment değerini D000 kabul ederek ilk koşullamaları yapar.
;Cihan
Atıl Namlı
;NMI
Çoklu Görev - Ön Koşullama Rutini
;Bu
program, D000:0000 adresinden başlayan 1030 baytlık bölgeyi tampon bellek
olarak
;kullanır.
;Tampon
bellekte, paralel çalışacak olan görevlerin konum bilgileri saklanmaktadır.
;Her
bir görev, COM dosya biçimindedir. Dolayısıyla 64k'lık bellek sınırlaması
altındadır ve
;segment
adres değerleri birbirine eşittir(CS=DS=SS).
;Bu
dosya biçiminden ötürü segment içerisindeki IP'nin başlangıç değeri 0100H'tır.
;Görevlerin
segment adresleri sırasıyla: 1000H, 2000H, 3000H ve 4000H'tır.
;Görevler,
250 baytlık yığın kapasitesine sınırlandırılmıştır.
;Programın
çalıştırılacağı hedef platform 80286 - Gerçek Kip'tir.
;
push
ds ; Rutinin çalışmasının öncesinde, kullanılacak kritik yazmaçların
push
es ; değerleri korunmalıdır. Ancak bu bir kesme rutini olmadığından, içeride
push
di ; kullanılan AX’i korumaya gerek yoktur. Değeri önemli
ise, AX’in
; ; korunmasından
rutini çağıran program sorumludur.
;
mov
ax, D000 ; Tampon
belleğin segmenti seçiliyor.
mov ds,
ax
;
xor di, di ; Her bir programın
başlangıç IP adresleri kaydediliyor.
mov
ax, 0100
mov
[di], ax
add
di, 100
mov
[di], ax
add
di, 100
mov
[di], ax
add
di, 100
mov
[di], ax
;
mov
di, 0002 ; Her bir
programın segment adresleri kaydediliyor.
mov
ax, 1000 ; Programın
segmenti belirtiliyor.
mov
[di], ax ; Tampondaki
ilgili noktaya bu değer yazılıyor.
;
add
di, 100 ; Aynı kategoride
sıradaki değer, 100H(256) bayt sonra gelir. Dolayısıyla
mov
ax, 2000 ; DI'ya bu değeri
eklemek yeterlidir.
mov
[di], ax
;
add
di, 100
mov
ax, 3000
mov
[di], ax
;
add
di, 100
mov
ax, 4000
mov
[di], ax
;
mov
di, 000e ; Her bir programın
başlangıç yığın işaretçileri kaydediliyor.
mov
ax, FFFE ; Bu değer, COM
programlarında sabit olarak FFFE'dir.
mov
[di], ax ; İlgili noktaya
bu değer yazılıyor.
;
add
di, 100 ; Aynı şekilde
öteki programlar için de...
mov
[di], ax
add
di, 100
mov
[di], ax
add
di, 100
mov
[di], ax
;
xor
ax, ax ; NMI rutini
ilk çağrıldığında zaten 1. program çalışıyor olacaktır.
stosw ; Dolayısıyla çalışan
programın numarası = 0.
;
pop
di ; Başlangıçta
korunan değerler, FILO(First In Last Out) düzeninde geri
pop
es ; yüklenir.
pop
ds
Yukarıdaki ön koşullama rutini, NMI kesmesi ile donanım anahtarlamasının başlangıcından evvel çalıştırılmalıdır. Dolayısıyla rutinin monitör programına yerleştirilmesi gerekir. Monitör programından kasıt, sistem hazır olana dek çalışan ve gerekli ayarlamaları yapan uygulamadır. Kullanmakta olduğumuz bilgisayarlarda, yönetim işletim sistemine devredilene dek çalışan, gerekli denetim ve ayarlamaları yapan BIOS buna bir örnektir.
Aşağıdaki kod, NMI kesmesi geldiğinde çağırılacağı varsayılan alt programdır.
; Cihan Atıl Namlı
; NMI Çoklu Görev - Anahtarlama Rutini
; Bu
programı/uygulamayı pratikte kullanmak için kod başlangıcındaki CS ve IP
değerleri,
; bellekte 0000:0008 konumuna sırayla yerleştirilmelidir.
; NMI kesmesi çağırıldığında sırasıyla FLAGS, CS ve IP yazmaçları yığına atılır.
; Kesme
rutininin görevi, tampon bellekteki program konum bilgilerini, henüz yığına
atılmış
; bilgiler ile değiştirmektir.
; Çalışmakta
olan programlar için mutlak olan eşitlik, CS = SS = DS = ES eşitliğidir.
; Dolayısıyla
yığının yeri, koda ve veriye bitişiktir. Ayrıca 64k’lık sınırlama dışındaki
veriye
; erişilmemektedir.
; Programda kullanılan tüm sayısal sabit değerler 16'lık tabandadır.
;
Bu kesmenin içeriğinde zaten tüm yazmaçların önce korunması, sonra da
yenileri ile
; değiştirilmesi
söz konusu olacaktır. Dolayısıyla başlangıçta herhangi "genel" bir
korumaya
; ihtiyaç duyulmamaktadır.
;
push ax
;
;
Aslında kullanılmakta olan yığın, durdurulan programın yığınıdır.
; Eğer
SP'nin göreceli negatif bölmelerinde yerel değişkenler saklanıyorsa bu işlem
soruna yol
; açabilir.
;
Dolayısıyla, mecbur olunmadıkça yığına başvurulmamalı; bunun yerine bellek
bölgeleri veya
;
boştaki yazmaçlar kullanılmalıdır.
;
mov ax, D000 ; Tampon bölgenin segmenti seçiliyor.
mov ds, ax
mov [0402], di ; DI'yi korumalıyız.
mov di, [0400] ; Çalışan program öğreniliyor.
mov ax, cx ; CX'i korumalıyız.
mov cl, 8
shl
di, cl ; Programların
tampondaki yerlerine erişmek için değerler 100H ile
; ; çarpılıyor( x << 8 = x * 256 ).
mov cx, ax ; CX'i geri alalım.
;
mov [0404],
bp ; BP korunuyor.
mov
bp, sp
mov
ax, [bp+2] ;
Kesilen programın IP adresi
mov
[di], ax ; Kaydediliyor...
mov
ax, [bp+4] ;
Kesilen programın CS adresi
mov
[di+2], ax ; Kaydediliyor...
mov
ax, [bp+6] ;
Kesilen programın FLAGS konumu
mov
[di+4], ax ; Kaydediliyor...
pop
ax ; Orijinal AX
geri alınıyor.
mov
[di+6], ax ; Kaydediliyor.
mov
[di+8], bx
mov
[di+a], cx
mov
[di+c], dx
mov
[di+e], sp
mov
bp, [0404] ; Korunan BP geri
alınıyor.
mov
[di+10], bp
mov
[di+12], si
mov
ax, [0402] ; Önceden
sakladığımız orijinal DI.
mov
[di+14], ax ; AX = Orijinal DI
;
;
Programın konumu korundu. Şimdi yeni programa ilişkin bilgiler
giriliyor. Yazmaçların
;
değerleri gönül rahatlığı ile değiştirilebilir.
;
mov di, [0400] ; Durdurulan programın numarası.
cmp di, 3 ; Çalışan programın sonuncu olup olmadığı inceleniyor.
je reset ; Sonuncu ise program numarası 0 yapılacak.
inc di ; DI artık geçişin yapılacağı programın numarasını gösteriyor.
jmp break ; Değişim tamamlandı.
reset: ; Durdurulan program sonuncu olduğu için başa dönülecek.
xor di, di ; DI geçişin yapılacağı 0 numaralı programı gösteriyor.
break:
mov [0400], di ; Yeni çalışan programın numarası tablodaki yerine yazılıyor.
mov cl, 8 ; Bu numara 100H ile çarpılarak tablodaki ilgili yere erişilecek.
shl di, cl ; Bit kaydırma yöntemiyle DI = DI * 100H
;
mov
ax, [di+2] ; Çalışmaya
başlayacak olan programın CS adresi
mov
ss, ax ; Yığın segmenti
çok önemli.
mov ds,
ax ; Veri segmenti de bir
o kadar önemli.
mov bx, [di+8]
mov cx, [di+a]
mov dx, [di+c]
mov sp, [di+e]
mov si, [di+12]
;
mov bp, sp
mov
ax, [di] ; IP, CS ve FLAGS
yazmaçları, yığın üzerindeki dönüş noktalarına
mov [bp], ax ; yerleştiriliyor.
mov ax, [di+2]
mov [bp+2], ax
mov ax, [di+4]
mov [bp+4], ax
;
mov ax, [di+6] ; Son olarak da BP, DI ve AX yazmaçları yerlerine geçiyorlar.
mov bp, [di+10]
mov di, [di+14]
pop di
;
IRET ; Geçmiş olsun...
Sıradaki program artık çalışıyor...
; ; Kod uzunluğu: 112 bayt
Yukarıda yazılı olan kod, NMI Çoklu Görev sistemi için anahtarlama işlemlerini gerçekleştirmektedir. NMI'ye gelen her darbe işareti sonucu bu rutin çalıştırılmakta ve işlemci zamanından pay almaktadır. Dolayısıyla NMI'nin çok yüksek frekanslar ile tetiklenmesi, programların iş yapmalarından çok yukarıdaki rutinin çalışmasına neden olacak ve verimsizlik doğacaktır. Burada yapılması gereken, yukarıdaki programın bir çalışmasının kaç işlemci çevrimi ve saniye sürdüğünü hesaplamak; ardından bu zamana göre NMI'nin tetiklenme frekansını ayarlamaktır. Yumuşak geçişli bir çoklu görev ortamında bu frekans yüksek olmalıyken, yüksek verim hedeflendiğinde bu değerin oldukça düşük seçilmesi gerekir. Basit bir örnekle bu durum daha iyi anlaşılabilir.
NMI Anahtarlama Rutini, yaklaşık 200 çevrim sürmektedir(20uS@10MHz). Bu durumda 1 saniye içinde maksimum 50.000 sefer başarılı NMI darbesi değerlendirilebilir. Söz konusu işlem kısa süreceğinden, programların çalışması için her seferinde 1 milisaniye verimlilik açısından uygun olacak ve sonuç olarak 1kHz'lik bir saat sinyali ile yapılan NMI tetiklemesi, mühendislik yaklaşımları ile oldukça bağdaşacaktır.
Herkese sınavında başarılar dilerim...
Saygılarımla
Cihan Atıl Namlı