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([email protected]). 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ı