Konuyu Oyla:
  • Derecelendirme: 5/5 - 1 oy
  • 1
  • 2
  • 3
  • 4
  • 5
Delphi ile İşletim Sistemi Yazımı
#1
DELPHI İLE İŞLETİM SİSTEMİ YAZMA
 
1. GİRİŞ
 
Merhaba,
 
Bu eğitim serisinde Delphi ile işletim sistemi yazacağız. Olabildiğince ileri gitmeyi hedefliyorum.
Orta seviye delphi bilgisi bu eğitim serisi için yeterli olacaktır. Az da olsa assembly bilgisi fena olmayacaktır. Zaten hem metin içinde hem de kodlar arasında gerekleri açıklamaları yapacağım.
 
Gerekli Yazılımlar
 
1. Her şeyden önce bir işletim sistemine ihtiyacımız var. Windows XP ve sonra bir işletim sistemi bize yeterli olacaktır. Çalışma ortamımız Windows’ta olacak.
2. Delphi’ye gelince, Delphi’nin 7. Sürümünden itibaren tüm sürümlerini kullanabilirsiniz.
3. Assembly dosyalarımızı derlemek için bir assembler'a ihtiyacımız olacak. Biz NASM (Netwide Assembler) kullanacağız. 
64 bit: https://www.nasm.us/pub/nasm/releasebuil...er-x64.exe 
32 bit: https://www.nasm.us/pub/nasm/releasebuil...er-x86.exe
Daha sonra sırası gelince NASM'ye değineceğiz.
4. Ayrıca yazdığımız işletim sistemini çalıştırmak için bize bir de emulator lazım olacak. Bunun için Qemu’yu kullanacağız. https://www.qemu.org/ adresinden qemu’yu indirebilirsiniz.
5. Son olarak bir hex editöre ihtiyacımız var. Hex editör oluşturmuş olduğumuz boot dosyasının bytelarını incelememiz için bize yardımcı olacak. Hex editör olarak HxD programını kullanabilirsiniz. İndirme linki: https://mh-nexus.de/en/downloads.php?product=HxD20
Başkaca bir programa şimdlik ihtiyaç ihtiyaç yok.
 
Başlıyoruz
 
Yapacağımız işletim sistemi 32 bit olacak. Delphi IDE’yı açıp yeni bir konsol uygulaması oluşturalım. Projemizin adı “xos” olsun.
 
Proje’nin uses kısmına SysUtils ve Classes’ı ekleyelim.
 
Projemizin görünümü şu şekilde olacak:
 

program xos;
{$APPTYPE CONSOLE}
uses
    SysUtils,Classes;
begin
    try
        
    except
        on E: Exception do System.Writeln(E.ClassName, ': ', E.Message);
    end;
end;

 
İmaj dosyasının oluşturulması bakımından Ekrem KOÇAK'ın hazırlamış olduğu https://forum.osdev.org/viewtopic.php?f=13&t=29437 adresindeki kodlar baz alınmıştır. Zekice hazırlanmış bu kodların mantığı delphi fonksiyonlarının adreslerine göre boot ve kernel oluşturmaktır.
 
Projeye kernelMain.pas adında bir unit ekleyelim. Görünümü şu şekilde olacak.
 

unit kernelMain;
interface
 
procedure kMain(); stdcall; //kernel’in başlangıcı
procedure loader; stdcall;//kernel’i yükleyen fonksiyon, başka bir deyişle kernel’in başlangıcı
procedure loader_end();//kernel’in sona erme adresini almak için
 
implementation
//Kernel kodu burada başlıyor
procedure loader; stdcall;
asm
  cli//kesmeleri(interrupt) durdur
  call kmain//kernel’i çağır
  hlt//sistemi durdur
end;
 
procedure kMain(); stdcall;
begin
     
end;
 
//kernel’in bitiş adresini elde etmek için boş bir prosedür oluşturuldu
procedure Loader_End(); begin end;
 
//Kernel’in sonu

end. 

Kernel prototipimizi oluşturduk. Şimdi dpr dosyamıza geri dönelim.
Dpr dosyasında yer alan kodlar kernelMain dosyasındaki kodlardan binary formatta boot edilebilir bir dosya oluşturacaktır.
 
Kodlar içinde açıklama yaparak anlatmaya çalışacağım:
 

program xos;
{$APPTYPE CONSOLE}
uses
  SysUtils,
  Classes,
  kernelMain in 'kernelMain.pas'; //kernelMain dosyamızı ekledik
 
type
  Tmultiboot_hdr=packed record //boot yapısı için struct oluşturduk
    magic:cardinal; //boot magic number. Multiboot için standard bir değerdir.
    flags:cardinal;//flags magic number ile kullanılıyor
    checksum:cardinal;//magic number ve flags aritmetiğinden checksum elde ediliyor.
    header_addr:cardinal; //boot yapısının hafızadaki adresini tutar
    load_addr:cardinal; //loader prosedürünün adresini tutar
    load_end_addr:cardinal;// loader_end prosedürünün adresini tutar
    bss_end_addr:cardinal;//bss bitiş adresi
    entry_addr:cardinal;//giriş adresi
    mode_type:cardinal;//0
    width:cardinal;//0
    height:cardinal;//0
    depth:cardinal;//0
  end;
 
var
    multiboot_hdr : Tmultiboot_hdr;//multiboot değişkeni
    size:cardinal;
    fsize:cardinal;
    buf:pointer;
    fnc:pointer;
    image_base:cardinal;
    image_size :cardinal;
    entry_addr: cardinal;
    f:file; //oluşturacağımız dosya binary olduğu file kullandık
begin//program başlangıcı
  try
       //xos.bin adında binary dosya oluşturacağız
      //dosyamızı f değişkenine aldık
      AssignFile(f,'xos.bin');  //binary dosyaımızın adı
      //dosya yazma işlemi yapacağız
      //dosya varsa içindekileri siler
      ReWrite(f, 1); //kayıt boyutu 1 olarak ayarlandı.
      //dosyada 1 bytelık bloklar bazında işlem yapılacak
 
 
      //image base    entry_addr       @loader      kernel boyutu  @loader_end
      //$400000  <->  $1DA0       <->  $401DA0  <-> $1E8(488) <->  $401F88
 
      //size  = entry_addr - bootheadersize = $1DA0 - $30 = $1D70  (7584-48=7536)
      //fsize = @loader_end - @loader = $401F88 - $401DA0 = $1E8 (488)
      //image size = size + $1000 (4096) = $1D70 + $1000(4096) =  $2D70 (11632)
 
      //programın image base adresi
      image_base:=$00400000;//varsayılan değer 4194304
      entry_addr:=cardinal(@loader)-cardinal(image_base); //7584,1DA0
      size:= entry_addr - sizeof(multiboot_hdr);
 
      fsize:= cardinal(@loader_end)-cardinal(@loader);//kernel boyutu
 
      image_size:= size+$1000;
 
      //multiboot yapısını ayarlayalım
      //multibot yapısını sıfırla
      fillchar(multiboot_hdr, sizeof(multiboot_hdr), 0);
 
      //bu kısım boot sabitlerini içerir
      //multiboot magic numarası sabittir. Bu kısmı değiştirmeyin.
      multiboot_hdr.magic:=($1BADB002); //multiboot magic number
      //multiboot bayrağını da değiştirmeye gerek yok.
      multiboot_hdr.flags:=(1 shl 16) ; //multiboot flag
      //bu aritmetik işlemine de dokunulmayacak
      multiboot_hdr.checksum:=cardinal(-multiboot_hdr.magic-multiboot_hdr.flags);
 
      multiboot_hdr.header_addr:=image_base;  //header adreessi base address: $00400000;
      multiboot_hdr.load_addr:=image_base;   //başlangıç adresi base address: $00400000;
      multiboot_hdr.load_end_addr:=cardinal(image_base+image_size); //programın sonunun adresini hesaplıyoruz
      multiboot_hdr.bss_end_addr:=cardinal(image_base+image_size); //bss adresini de programın sonu olarak ayarlıyoruz
      multiboot_hdr.entry_addr:=cardinal(image_base+entry_addr); //zaten bu loader'ın adresi oluyor
      //aşağıdaki dört satırı sıfırlamaya gerek yok.
      //Zaten yapıyı fillchar ile sıfırlamıştık
      //multiboot_hdr.mode_type:=0;
      //multiboot_hdr.width:=0;
      //multiboot_hdr.height:=0;
      //multiboot_hdr.depth:=0;
 
      //xos.bin yapısı
      //multiboot yapısı -> 0'lar -> 0'lar -> kernel verimiz
 
      //BlockWrite fonksiyonu binary dosyaya veri kaydetmek/yazmak için kullanılır
      //BlockWrite(dosya değişken, blok, blok büyüklüğü)
      //xos.bin dosyasına multiboot yapısını kaydet
      //böylece 48 byte'tan oluşan multiboot yapımız dosyaya kaydedilmiş oldu
      blockwrite(f, multiboot_hdr, sizeof(multiboot_hdr));
 
      getmem(buf, size);//multiboot'tan geriye kalan hafıza alanını oluştur
      fillchar(buf^, size, 0); //hafıza alanını nul yap
      blockwrite(f, buf^, size);
      freemem(buf);
 
      //buraya kadar toplamda entry_addr ($1DA0 byte) kadar veri dosyaya yazmış olduk
      //ilk 48 byte multiboot ve geriye kalan null olacak şekilde yazıldı
 
      fnc:=@loader; //kernel girişinin adresini aldık
      getmem(buf, $1000-fsize);   //4kb'den kernel boyutumuzu çıkardık ve bu sayıda hafıza alanı oluşturduk
      fillchar(buf^,$1000-fsize,0);//kernel alanı dışında kalan hafıza alanını null ile doldurduk
      blockwrite(f,fnc^, fsize);  //dosyaya kernel boyutu kadar kernel kodlarını yazdık
      blockwrite(f,buf^ ,$1000-fsize);//4kb'den geri kalan alanı da dosyaya yazdık
      freemem(buf);
 
      closefile(f);   //dosyayı kapatıyoruz
  except
    on E: Exception do System.Writeln(E.ClassName, ': ', E.Message);
  end;
end.
 
Programı çalıştırdığımızda xos.exe yanında xos.bin dosyası oluşacak. Bu dosya içinde hem bizim boot’umuz var hem de kernel kodlarımız var.
 
xos.bin dosyasını HxD programıyla açtığımızda şöyle bir görüntüyle karşılacağız:


00000000:        02 B0 AD 1B 00 00 01 00 FE 4F 51 E4 00 00 40 00 (boot başlangıcı)
                 00 00 40 00 70 2D 40 00 70 2D 40 00 A0 1D 40 00
                 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
…
…                00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
…
00001DA0:        FA E8 D2 01 00 00 F4 C3 55 8B EC 51 66 8B 55 08 (entry_addr) 1DA0:7584
…
…                00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
…
 


0. adresten itibaren bizi multibootloader yapısı karşılıyor. Dosyaya ilk multiboot yapısını kaydetmiştik.
 
multiboot_hdr.magic:=($1BADB002); = 02 B0 AD 1B
 
Hemen her ikili sayı grubunun bir byte’a işaret ettiğini belirtelim. Dikkat ederseniz. Delphideki hexedecimal cardnal sayımız dosyaya tersten yazılmış. Sistemin little endian olması nedeniyle bytelar bu şekilde yazılır. Cardinal 4 byte yer kapladığından yan yana 4 byte görmüş olduk.
 
Bir sonraki 4 byte’lık alan 00 00 01 00. Bu da multiboot yapısınıdaki flag’a işaret ediyor: multiboot_hdr.flags:=(1 shl 16); 1 sayısını sola doğru 16 kaydırdığımızda ikilik tabanda 000000001 00000000 00000000 sayısı elde edilir. flags cardinal olarak tanımlandığından 4 byte olarak düzenlendiğinde sayı 00000000 000000001 00000000 00000000 edecektir. Bu da 16’lık sistemde 00 01 00 00’a işaret edecek ve tersten 00 00 01 00 olarak dosyaya yazılmıştır.
 
7584 adresi yani 1DA0 adresi bizim kernel’imizin kodlarının başlangıç adresi. entry_addr olarak yukarıda tanımlanmıştı. Kernel’imizin başlangıcından itibaren 4kb alan ayrılmış ve kernel’in sona ermesinden itibaren kalan alan null yani 0 ile doldurulmuştur.
 
HxD programını kapatarak xos.exe dosyasını çalıştıralım. Oluşan xos.bin dosyamızı çalıştırmak için qemu’yu kullanacağız. cmd ya da powershell’i açıp qemu-system-x86_64 -kernel xos.bin komutunu çalıştırınca.”Booting From Rom” yazısını ekranda sürekli görüyorsanız işlem tamam demektir. Henüz kernel’imiz işlevsel bir kod içermiyor. Bir sonraki dersimizde ekrana yaz yazmayı göreceğiz.
 
Burada anlatılanları anlamak bir hayli zor olabilir. Mümkün mertebe sorularınıza yanıtlar vererek belirsizlikleri gidermeye çalışacağım.

Hakan DİMDİK
Cevapla
#2
2. EKRANA YAZI YAZDIRMA
 
Öncelikle sürekli cmd’ye ya da PowerShell’e “qemu-system-x86_64 -kernel xos.bin” komutunu yazmak yerine bu işi delphi’ye bırakalım.

xos.dpr dosyamızı açalım. Uses kısmına Windows ve ShellApi unitlerini ekleyelim.
closefile(f);   satırından sonra gelmek üzere

ShellExecute(0, nil, 'cmd.exe', '/C qemu-system-x86_64 -kernel xos.bin', nil, SW_HIDE);

Kodunu ekleyelim.

Böylelikle xos uygulamasını her çalıştırdığımızda xos.bin dosyasını oluşturup qemu’dan xos.bin dosyasını çalıştıracak ve işletim sistemimizi kolay bir şekilde kullanabileceğiz.

Dpr dosyamızın son halî aşağıdaki şekilde olacak:


program xos;
{$APPTYPE CONSOLE}
uses
  SysUtils,
  Classes,
  Windows,
  ShellApi,
  kernelMain in 'kernelMain.pas'; //kernelMain dosyamızı ekledik
 
type
  Tmultiboot_hdr=packed record //boot yapısı için struct oluşturduk
    magic:cardinal; //boot magic number. Multiboot için standard bir değerdir.
    flags:cardinal;//flags magic number ile kullanılıyor
    checksum:cardinal;//magic number ve flags aritmetiğinden checksum elde ediliyor.
    header_addr:cardinal; //boot yapısının hafızadaki adresini tutar
    load_addr:cardinal; //loader prosedürünün adresini tutar
    load_end_addr:cardinal;// loader_end prosedürünün adresini tutar
    bss_end_addr:cardinal;//bss bitiş adresi
    entry_addr:cardinal;//giriş adresi
    mode_type:cardinal;//0
    width:cardinal;//0
    height:cardinal;//0
    depth:cardinal;//0
  end;
 
var
    multiboot_hdr : Tmultiboot_hdr;//multiboot değişkeni
    size:cardinal;
    fsize:cardinal;
    buf:pointer;
    fnc:pointer;
    image_base:cardinal;
    image_size :cardinal;
    entry_addr: cardinal;
    f:file; //oluşturacağımız dosya binary olduğu file kullandık
begin//program başlangıcı
  try
      //xos.bin adında binary dosya oluşturacağız
      //dosyamızı f değişkenine aldık
               AssignFile(f,'xos.bin');  //binary dosyaımızın adı
      //dosya yazma işlemi yapacağız
      //dosya varsa içindekileri siler
                    ReWrite(f, 1); //kayıt boyutu 1 olarak ayarlandı.
                    //dosyada 1 bytelık bloklar bazında işlem yapılacak
 
 
      //image base    entry_addr       @loader      kernel boyutu  @loader_end
      //$400000  <->  $1DA0       <->  $401DA0  <-> $1E8(488) <->  $401F88
 
      //size  = entry_addr - bootheadersize = $1DA0 - $30 = $1D70  (7584-48=7536)
      //fsize = @loader_end - @loader = $401F88 - $401DA0 = $1E8 (488)
      //image size = size + $1000 (4096) = $1D70 + $1000(4096) =  $2D70 (11632)
 
      //programın image base adresi
      image_base:=$00400000;//varsayılan değer 4194304
      entry_addr:=cardinal(@loader)-cardinal(image_base); //7584,1DA0
      size:= entry_addr - sizeof(multiboot_hdr);
 
      fsize:= cardinal(@loader_end)-cardinal(@loader);//kernel boyutu
 
      image_size:= size+$1000;
 
      //multiboot yapısını ayarlayalım
      //multibot yapısını sıfırla
      fillchar(multiboot_hdr, sizeof(multiboot_hdr), 0);
 
      //bu kısım boot sabitlerini içerir
      //multiboot magic numarası sabittir. Bu kısmı değiştirmeyin.
      multiboot_hdr.magic:=($1BADB002); //multiboot magic number
      //multiboot bayrağını da değiştirmeye gerek yok.
      multiboot_hdr.flags:=(1 shl 16); //multiboot flag
      //bu aritmetik işlemine de dokunulmayacak
      multiboot_hdr.checksum:=cardinal(-multiboot_hdr.magic-multiboot_hdr.flags);
 
      multiboot_hdr.header_addr:=image_base;  //header adreessi base address: $00400000;
      multiboot_hdr.load_addr:=image_base;   //başlangıç adresi base address: $00400000;
      multiboot_hdr.load_end_addr:=cardinal(image_base+image_size); //programın sonunun adresini hesaplıyoruz
      multiboot_hdr.bss_end_addr:=cardinal(image_base+image_size); //bss adresini de programın sonu olarak ayarlıyoruz
      multiboot_hdr.entry_addr:=cardinal(image_base+entry_addr); //zaten bu loader'ın adresi oluyor
      //aşağıdaki dört satırı sıfırlamaya gerek yok.
      //Zaten yapıyı fillchar ile sıfırlamıştık
      //multiboot_hdr.mode_type:=0;
      //multiboot_hdr.width:=0;
      //multiboot_hdr.height:=0;
      //multiboot_hdr.depth:=0;
 
      //xos.bin yapısı
      //multiboot yapısı -> 0'lar -> 0'lar -> kernel verimiz
 
      //BlockWrite fonksiyonu binary dosyaya veri kaydetmek/yazmak için kullanılır
      //BlockWrite(dosya değişken, blok, blok büyüklüğü)
      //xos.bin dosyasına multiboot yapısını kaydet
      //böylece 48 byte'tan oluşan multiboot yapımız dosyaya kaydedilmiş oldu
      blockwrite(f, multiboot_hdr, sizeof(multiboot_hdr));
 
      getmem(buf, size);//multiboot'tan geriye kalan hafıza alanını oluştur
      fillchar(buf^, size, 0); //hafıza alanını nul yap
      blockwrite(f, buf^, size);
      freemem(buf);
 
      //buraya kadar toplamda entry_addr ($1DA0 byte) kadar veri dosyaya yazmış olduk
      //ilk 48 byte multiboot ve geriye kalan null olacak şekilde yazıldı
 
      fnc:=@loader; //kernel girişinin adresini aldık
      getmem(buf, $1000-fsize);   //4kb'den kernel boyutumuzu çıkardık ve bu sayıda hafıza alanı oluşturduk
      fillchar(buf^,$1000-fsize,0);//kernel alanı dışında kalan hafıza alanını null ile doldurduk
      blockwrite(f,fnc^, fsize);  //dosyaya kernel boyutu kadar kernel kodlarını yazdık
      blockwrite(f,buf^ ,$1000-fsize);//4kb'den geri kalan alanı da dosyaya yazdık
      freemem(buf);
 
      closefile(f);   //dosyayı kapatıyoruz
 
      ShellExecute(0, nil, 'cmd.exe', '/C qemu-system-x86_64 -kernel xos.bin', nil, SW_HIDE);
  except
    on E: Exception do System.Writeln(E.ClassName, ': ', E.Message);
  end;
 
end.
 

Artık run diyerek programı delphi’den çalıştırdığımızda ya da xos.exe dosyasına çift tıkladığımızda otomatik olarak xos.bin dosyası oluşacak ve qemu’da işletim sistemimiz açılacak.
 
 
Şimdi gelelim kernelimize kod yazmaya. Bunun için kernelMain.pas dosyamızı açalım. Dosyanın son hâli şu şekilde idi:
 

unit kernelMain;
interface
procedure kMain(); stdcall; //kernel’in başlangıcı
procedure loader; stdcall;//kernel’i yükleyen fonksiyon, başka bir deyişle kernel’in başlangıcı
procedure loader_end();//kernel’in sona erme adresini almak için
  
implementation
//Kernel kodu burada başlıyor
procedure loader; stdcall;
asm
  cli//kesmeleri(interrupt) durdur
  call kmain//kernel’i çağır
  hlt//sistemi durdur
end;
  
procedure kMain(); stdcall;
begin
      
end;
  
//kernel’in bitiş adresini elde etmek için boş bir prosedür oluşturuldu
procedure Loader_End(); begin end;
  
//Kernel’in sonu
 
end.
 
Ekrana yazı yazdırma kodlarını kMain(); prosedürü içine yazacağız.
Hemen önemli bir bilgi verelim. $B8000 adresinde ekranımız bulunmakta. Ekrana yazı yazdırmak için bu adresi kullanmamız gerekiyor.
 
ekranAdresi: PAnsiChar; diyerek ekran adresimi tanımlıyorum ve daha sonra ekranAdresi:=PAnsiChar($B8000); diyerek ekran adresinin atamasını gerçekleştiriyorum. Artık ekranAdresi pointerını kullanarak ekrana bir şeyler yazdırabiliriz.
 
kMain prosedürümüzü şu şekilde düzenledim.
 

procedure kMain(); stdcall;
var
  ekranAdresi: PAnsiChar;
begin
  ekranAdresi:= PAnsiChar($B8000);
  ekranAdresi[0]:= 'A';
end;

 
Ekranın sol üst köşesinde A yazısını görmüş olacaksınız. Ancak Qemu’nun ekran çıktısı da ekranda göründüğünden hemen farkedemeyebilirsiniz.
 
kMain prosedürünü şu şekilde değiştirelim:
 

procedure kMain(); stdcall;
var
  ekranAdresi: PAnsiChar;
begin
  ekranAdresi:=PAnsiChar($B8000);
  ekranAdresi[0]:= 'A';
  ekranAdresi[2]:= 'B';
  ekranAdresi[4]:= 'C';
  ekranAdresi[6]:= 'D';
  ekranAdresi[8]:= 'E';
  ekranAdresi[10]:= 'F';
  ekranAdresi[12]:= 'G';
end;

 
Ekranın sol üst köşesinde ABCDEFG yazısını göreceksiniz. Peki neden indekslemeyi 2’şer 2’şer yaptık? Çünkü karakterlerden sonra gelen indisler renkleri içermektedir. Biraz renk katalım o halde:
 

procedure kMain(); stdcall;
var
  ekranAdresi: PAnsiChar;
begin
  ekranAdresi:= PAnsiChar($B8000);
  ekranAdresi[0]:= 'A';
  ekranAdresi[1]:= AnsiChar(01); // mavi
  ekranAdresi[2]:= 'B';
  ekranAdresi[3]:= AnsiChar(02); // yeşil
  ekranAdresi[4]:= 'C';
  ekranAdresi[5]:= AnsiChar(03); // cyan
  ekranAdresi[6]:= 'D';
  ekranAdresi[7]:= AnsiChar(04); // kırmızı
  ekranAdresi[8]:= 'E';
  ekranAdresi[9]:= AnsiChar(05); // magenta
  ekranAdresi[10]:= 'F';
  ekranAdresi[11]:= AnsiChar(06); // kahverengi
  ekranAdresi[12]:= 'G';
  ekranAdresi[13]:= AnsiChar(07); // açık gri
end;

 
Ekranın sol üst köşesine DelphiCan yazalım:
 

procedure kMain(); stdcall;
var
  ekranAdresi: PAnsiChar;
begin
  ekranAdresi:= PAnsiChar($B8000);
  ekranAdresi[0]:= 'D';
  ekranAdresi[1]:= AnsiChar(01); // mavi
  ekranAdresi[2]:= 'e';
  ekranAdresi[3]:= AnsiChar(02); // yeşil
  ekranAdresi[4]:= 'l';
  ekranAdresi[5]:= AnsiChar(03); // cyan
  ekranAdresi[6]:= 'p';
  ekranAdresi[7]:= AnsiChar(04); // kırmızı
  ekranAdresi[8]:= 'h';
  ekranAdresi[9]:= AnsiChar(05); // magenta
  ekranAdresi[10]:= 'i';
  ekranAdresi[11]:= AnsiChar(06); // kahverengi
  ekranAdresi[12]:= 'C';
  ekranAdresi[13]:= AnsiChar(07); // açık gri
  ekranAdresi[14]:= 'a';
  ekranAdresi[15]:= AnsiChar(08); // koyu gri
  ekranAdresi[16]:= 'n';
  ekranAdresi[17]:= AnsiChar(09); // açık mavi
end;
 

Ekran’da Qemu’nun yazıları üstüne gelecek şekilde sol üst köşede renki bir şekilde DelphiCan yazısını göreceksiniz.
 
Ekranımız genişlik 80 ve yükseklik 25 ebatlarında şu aşamada. Şu aşamada yazdıklarımız sadece x düzleminde yatay olarak ilerledi.

 
Şimdi bütün ekranı temlzleyelim ve ekranı maviye boyaylım. Daha sonra ekrana DelphiCan yazısını yazdıralım:


 
procedure kMain(); stdcall;
var
  ekranAdresi: PAnsiChar;
  i:integer;
begin
  ekranAdresi:= PAnsiChar($B8000);
 
  i:=0;
  while i< 80 * 25 * 2 do begin //80 genşilik, 25 yükseklik, 2: karakter ve renk kodu için 
    ekranAdresi[i]:= ' ';
    ekranAdresi[i+1]:= AnsiChar(1 shl 4); //arka plan rengi için sola doğru 4 bit kaydırıyoruz
    inc(i,2);
  end;
 
  ekranAdresi[0]:= 'D';
  ekranAdresi[1]:= AnsiChar(01); // mavi
  ekranAdresi[2]:= 'e';
  ekranAdresi[3]:= AnsiChar(02); // yeşil
  ekranAdresi[4]:= 'l';
  ekranAdresi[5]:= AnsiChar(03); // cyan
  ekranAdresi[6]:= 'p';
  ekranAdresi[7]:= AnsiChar(04); // kırmızı
  ekranAdresi[8]:= 'h';
  ekranAdresi[9]:= AnsiChar(05); // magenta
  ekranAdresi[10]:= 'i';
  ekranAdresi[11]:= AnsiChar(06); // kahverengi
  ekranAdresi[12]:= 'C';
  ekranAdresi[13]:= AnsiChar(07); // açık gri
  ekranAdresi[14]:= 'a';
  ekranAdresi[15]:= AnsiChar(08); // koyu gri
  ekranAdresi[16]:= 'n';
  ekranAdresi[17]:= AnsiChar(09); // açık mavi
end;

Böylece ekranda qemu’nun yazılarından eser kalmayacak. DelphiCan yazısını daha rahat görebileceğiz ekranda.
 
Şu ekran temizleme işi için ayrı bir fonksiyon yazalım. Ayrıca ekranAdresi pointerını global düzeye alalım. kernelMain.pas’ın son hali:


 
unit kernelMain;
interface
 
 
procedure kMain; stdcall;
procedure loader; stdcall;
procedure loader_end;
 
implementation
 
var
  ekranAdresi: PAnsiChar;
 
//Kernel başlangıcı
 
procedure loader; stdcall;
asm
  cli
  call kmain
  hlt
end;
 
procedure Cls;
var
  i:integer;
begin
  i:=0;
  while i< 80 * 25 * 2 do begin
    ekranAdresi[i]:= ' ';
    ekranAdresi[i+1]:= AnsiChar(1 shl 4); //arka plan rengi için sola doğru 4 bit kaydırıyoruz
    inc(i,2);
  end;
end;
 
 
 
procedure kMain; stdcall;
var
  i:integer;
begin
  ekranAdresi:= PAnsiChar($B8000);
 
  Cls;
 
  ekranAdresi[0]:= 'D';
  ekranAdresi[1]:= AnsiChar(01); // mavi
  ekranAdresi[2]:= 'e';
  ekranAdresi[3]:= AnsiChar(02); // yeşil
  ekranAdresi[4]:= 'l';
  ekranAdresi[5]:= AnsiChar(03); // cyan
  ekranAdresi[6]:= 'p';
  ekranAdresi[7]:= AnsiChar(04); // kırmızı
  ekranAdresi[8]:= 'h';
  ekranAdresi[9]:= AnsiChar(05); // magenta
  ekranAdresi[10]:= 'i';
  ekranAdresi[11]:= AnsiChar(06); // kahverengi
  ekranAdresi[12]:= 'C';
  ekranAdresi[13]:= AnsiChar(07); // açık gri
  ekranAdresi[14]:= 'a';
  ekranAdresi[15]:= AnsiChar(08); // koyu gri
  ekranAdresi[16]:= 'n';
  ekranAdresi[17]:= AnsiChar(09); // açık mavi
end;
 
//yalnızca hesaplama için oluşturduk
procedure Loader_End(); begin end;
 
//Kernel sonu
 
end.

 

Ekran resmi:


Ek Dosyalar Resimler
   
Cevapla
#3
3. EKRANA YAZI YAZDIRMA – DEVAMI

Tekrar Merhaba,

Bir önceki dersimizde ekran temizlemeyi ve ekrana basitçe yazı yazdırmayı gördük. Şimdi biraz daha ilerleme kaydedelim.

Biliyorsunuz ekranımız $B8000 adresinde yer alıyordu. Bunu sabit olarak tanımlayalım. Ayrıca Ekran genişliğimizi ve yüksekliğimizi de sabit olarak tanımlayalım. Bununla birlikte ekran arka planı ve karakterler için kullanacağımız renkleri de sabit olarak tanımlayalım.

const
 //Ekran Hücrelerinin Başlangıç Adresi
 ekranAdresi= PAnsiChar($B8000);
 //Ekran
 Ekran_Genislih      = 80;
 Ekran_Yukselik      = 25;
 //Renkler
 Renk_Siyah          = 0;
 Renk_Mavi           = 1;
 Renk_Yesil          = 2;
 Renk_Camgobegi      = 3;
 Renk_Kirmizi        = 4;
 Renk_Eflatun        = 5;
 Renk_Kahverengi     = 6;
 Renk_AcikGri        = 7;
 Renk_KoyuGri        = 8;
 Renk_AcikMavi       = 9;
 Renk_AcikYesil      = 10;
 Renk_AcikCamgobegi  = 11;
 Renk_Turuncu        = 12;
 Renk_Pembe          = 13;
 Renk_Sari           = 14;
 Renk_Beyaz          = 15;


Ayrıca renklerimizin ayarlamasını yapacağımız bir de fonksiyon tanımlayalım:

//Renk Ayarla
function RenkAyarla(OnPlan,ArkaPlan:Byte):AnsiChar;
begin
   //arka plan renk kodunu 4 bit sola kaydırma nedeni:
   //1 byte/8 bit= 0000 0000
   // 4 biti arka plan 4 biti ön plan
   //0000       0000
   //arkaplan   ön plan
   Result:= AnsiChar(OnPlan or ArkaPlan shl 4);
end;


Ekran temizleme için kullandığımız Cls fonksiyonunun adını Temizle olarak değiştirdim ve RenkAyarla fonksiyonunu burada kullandım:

//Ekranı temizle
procedure Temizle;
var
 i:integer;
begin
 i:=0;
 while i< 4000 do begin   { Ekran Boyutu: 80 * 25 * 2 = 4000}
   ekranAdresi[i]:= ' ';
   ekranAdresi[i+1]:= RenkAyarla(Renk_Mavi,Renk_Mavi); //arka plan rengi için sola doğru 4 bit kaydırıyoruz
   inc(i,2);
 end;
end;


Ayrıca koordinatlarını belirttiğimiz yere karakter yazmamızı sağlayan bir fonksiyon:

procedure KarakterYaz(X, Y: integer; karakter:AnsiChar;Renk:Byte); stdcall;
var
 address: Word;
begin
 //yatay x 160 hücreden oluşuyor ve herbir hücre karakter ve renk kodu içeriyoruz.
 //bu yüzden *2
 //y*160 olmasının sebebi Y*2*80
 //Aslında Y üzerinde ilerlemek x üzerinde de satırı tamamlamak anlamına geliyor
 address:= X*2 + Y * 160;
 ekranAdresi[address]:= karakter;
 ekranAdresi[address+1]:= RenkAyarla(Renk,Renk_Mavi);
end;

Şimdi KarakterYaz fonksiyonumuzu kullanalım:

procedure kMain; stdcall;
begin
   Temizle; //ekranı temizle
KarakterYaz(0,0,'D',Renk_Camgobegi);
 KarakterYaz(0,1,'E',Renk_AcikCamgobegi);
 KarakterYaz(0,2,'L',Renk_Kirmizi);
 KarakterYaz(0,3,'P',Renk_Pembe);
 KarakterYaz(0,4,'H',Renk_Eflatun);
 KarakterYaz(0,5,'I',Renk_Turuncu);
 KarakterYaz(0,6,'C',Renk_Kahverengi);
 KarakterYaz(0,7,'A',Renk_AcikGri);
 KarakterYaz(0,8,'N',Renk_KoyuGri);

end;

Satırların en başında alt alta renkli bir şekilde DELPHICAN yazacaktır. x koordinatının 0'da kaldığına ve y'lerin birer birer arttığına dikkat edin.

Bir de çaprazlama yazalım:

procedure kMain; stdcall;
begin

  Temizle; //ekranı temizle

  KarakterYaz(0,0,'D',Renk_Camgobegi);
  KarakterYaz(1,1,'E',Renk_AcikCamgobegi);
  KarakterYaz(2,2,'L',Renk_Kirmizi);
  KarakterYaz(3,3,'P',Renk_Pembe);
  KarakterYaz(4,4,'H',Renk_Eflatun);
  KarakterYaz(5,5,'I',Renk_Turuncu);
  KarakterYaz(6,6,'C',Renk_Kahverengi);
  KarakterYaz(7,7,'A',Renk_AcikGri);
  KarakterYaz(8,8,'N',Renk_KoyuGri);
end;

kernelMain.pas dosyamızın son hali şu şekilde:

unit kernelMain;
interface

const
 //Ekran Hücrelerinin Başlangıç Adresi
 ekranAdresi= PAnsiChar($B8000);
 //Ekran
 Ekran_Genislih      = 80;
 Ekran_Yukselik      = 25;
 //Renkler
 Renk_Siyah          = 0;
 Renk_Mavi           = 1;
 Renk_Yesil          = 2;
 Renk_Camgobegi      = 3;
 Renk_Kirmizi        = 4;
 Renk_Eflatun        = 5;
 Renk_Kahverengi     = 6;
 Renk_AcikGri        = 7;
 Renk_KoyuGri        = 8;
 Renk_AcikMavi       = 9;
 Renk_AcikYesil      = 10;
 Renk_AcikCamgobegi  = 11;
 Renk_Turuncu        = 12;
 Renk_Pembe          = 13;
 Renk_Sari           = 14;
 Renk_Beyaz          = 15;





procedure kMain; stdcall;
procedure loader; stdcall;
procedure loader_end;

implementation


//Kernel başlangıcı
procedure loader; stdcall;
asm
 cli
 call kmain
 hlt
end;

//Renk Ayarla
function RenkAyarla(OnPlan,ArkaPlan:Byte):AnsiChar;
begin
   //arka plan renk kodunu 4 bit sola kaydırma nedeni:
   //1 byte/bit= 0000 0000
   // 4 biti arka plan 4 biti ön plan
   //0000       0000
   //arkaplan   ön plan
   Result:= AnsiChar(OnPlan or ArkaPlan shl 4);
end;

//Ekranı temizle
procedure Temizle;
var
 i:integer;
begin
 i:=0;
 while i< 4000 do begin   { Ekran Boyutu: 80 * 25 * 2 = 4000}
   ekranAdresi[i]:= ' ';
   ekranAdresi[i+1]:= RenkAyarla(Renk_Mavi,Renk_Mavi); //arka plan rengi için sola doğru 4 bit kaydırıyoruz
   inc(i,2);
 end;
end;

procedure KarakterYaz(X, Y: integer; karakter:AnsiChar;Renk:Byte); stdcall;
var
 address: Word;
begin
 //yatay x 160 hücreden oluşuyor ve herbir hücre karakter ve renk kodu içeriyoruz.
 //bu yüzden *2
 //y*160 olmasının sebebi Y*2*80
 //Aslında Y üzerinde ilerlemek x üzerinde de satırı tamamlamak anlamına geliyor
 address:= X*2 + Y * 160;
 ekranAdresi[address]:= karakter;
 ekranAdresi[address+1]:= RenkAyarla(Renk,Renk_Mavi);
end;


//kernel başla
procedure kMain; stdcall;
begin

 Temizle; //ekranı temizle

 KarakterYaz(0,0,'D',Renk_Camgobegi);
 KarakterYaz(1,1,'E',Renk_AcikCamgobegi);
 KarakterYaz(2,2,'L',Renk_Kirmizi);
 KarakterYaz(3,3,'P',Renk_Pembe);
 KarakterYaz(4,4,'H',Renk_Eflatun);
 KarakterYaz(5,5,'I',Renk_Turuncu);
 KarakterYaz(6,6,'C',Renk_Kahverengi);
 KarakterYaz(7,7,'A',Renk_AcikGri);
 KarakterYaz(8,8,'N',Renk_KoyuGri);
end;

//yalnızca hesaplama için oluşturduk
procedure Loader_End(); begin end;

//Kernel sonu

end.

4. EKRANA YAZI YAZDIRMA – DEVAMI

Şimdi biraz kodumuzda moduler yapıya gidelim.

Sabitlerimiz için bir unit oluşturalım ve adın uConsts.pas diyelim:

unit uConsts;



interface



const

 //Ekran Hücrelerinin Başlangıç Adresi

 ekranAdresi= PAnsiChar($B8000);

 //Ekran

 Ekran_Genislih      = 80;

 Ekran_Yukselik      = 25;

 //Renkler

 Renk_Siyah          = 0;

 Renk_Mavi           = 1;

 Renk_Yesil          = 2;

 Renk_Camgobegi      = 3;

 Renk_Kirmizi        = 4;

 Renk_Eflatun        = 5;

 Renk_Kahverengi     = 6;

 Renk_AcikGri        = 7;

 Renk_KoyuGri        = 8;

 Renk_AcikMavi       = 9;

 Renk_AcikYesil      = 10;

 Renk_AcikCamgobegi  = 11;

 Renk_Turuncu        = 12;

 Renk_Pembe          = 13;

 Renk_Sari           = 14;

 Renk_Beyaz          = 15;



implementation


end.

Yine ekran fonksiyonlarımız için inc dosyası oluşturalım ve adına uEkran.inc diyelim:

//Renk Ayarla

function RenkAyarla(OnPlan,ArkaPlan:Byte):AnsiChar;

begin

   //arka plan renk kodunu 4 bit sola kaydırma nedeni:

   //1 byte/bit= 0000 0000

   // 4 biti arka plan 4 biti ön plan

   //0000       0000

   //arkaplan   ön plan

   Result:= AnsiChar(OnPlan or ArkaPlan shl 4);

end;



//Ekranı temizle

procedure Temizle;

var

 i:integer;

begin

 i:=0;

 while i< 4000 do begin   { Ekran Boyutu: 80 * 25 * 2 = 4000}

   ekranAdresi[i]:= ' ';

   ekranAdresi[i+1]:= RenkAyarla(Renk_Mavi,Renk_Mavi); //arka plan rengi için sola doğru 4 bit kaydırıyoruz

   inc(i,2);

 end;

end;



procedure KarakterYaz(X, Y: integer; karakter:AnsiChar;Renk:Byte); stdcall;

var

 address: Word;

begin

 //yatay x 160 hücreden oluşuyor ve herbir hücre karakter ve renk kodu içeriyoruz.

 //bu yüzden *2

 //y*160 olmasının sebebi Y*2*80

 //Aslında Y üzerinde ilerlemek x üzerinde de satırı tamamlamak anlamına geliyor

 address:= X*2 + Y * 160;

 ekranAdresi[address]:= karakter;

 ekranAdresi[address+1]:= RenkAyarla(Renk,Renk_Mavi);
end;

Bu uEkran.inc dosyamızı kernelMain.pas dosyasına loader prosedüründen sonra gelmek üzere {$I uEkran.inc} şeklinde ekleyelim.

Şimdi uEkran.inc dosyamızda bir de MetinYaz adında bir prosedür oluşturalım:

procedure MetinYaz(X,Y: integer; metin: PAnsiChar; Renk: Byte);  stdcall;

var

 address: Word;

 i: integer;

begin

 i:=0;

 repeat

   address:= X*2 + Y * 160;

   ekranAdresi[address]:= (metin[i]);

   ekranAdresi[address+1]:= RenkAyarla(Renk,Renk_Mavi);

   inc(x);

   inc(i);

  until metin[i] = #0
end;

kernelMain.pas dosyaımızda kMain prosedürüne MetinYaz(0,9,'DELPHICAN',Renk_Sari); kodunu ekleyelim.

kernelMain.pas dosyamızın son hali şu şekilde olmalı:

unit kernelMain;

interface



procedure kMain; stdcall;

procedure loader; stdcall;

procedure loader_end;



implementation



uses

 uconsts;





//Kernel başlangıcı

procedure loader; stdcall;

asm

 cli

 call kmain

 hlt

end;



{$I uEkran.inc}



//kernel başla

procedure kMain; stdcall;

begin



 Temizle; //ekranı temizle



 KarakterYaz(0,0,'D',Renk_Camgobegi);

 KarakterYaz(1,1,'E',Renk_AcikCamgobegi);

 KarakterYaz(2,2,'L',Renk_Kirmizi);

 KarakterYaz(3,3,'P',Renk_Pembe);

 KarakterYaz(4,4,'H',Renk_Eflatun);

 KarakterYaz(5,5,'I',Renk_Turuncu);

 KarakterYaz(6,6,'C',Renk_Kahverengi);

 KarakterYaz(7,7,'A',Renk_AcikGri);

 KarakterYaz(8,8,'N',Renk_KoyuGri);



 MetinYaz(0,9,'DELPHICAN',Renk_Sari);

end;



//yalnızca hesaplama için oluşturduk

procedure Loader_End(); begin end;



//Kernel sonu


end.

Ekran resmi:


Ek Dosyalar Resimler
       
Cevapla
#4
5. KLAVYE

Artık klavyeden veri okumaya başlayabiliriz.

Önce bilgisayarın herhangi bir portundan veri okuyan ve yazan fonksiyonlarımızı yazalım:

function PortOku(port:word):byte;
asm
  mov dx, port //port numarasından veriyi çekip dx'e al
  in al, dx    //in ile al'ye veriyi al
end;

procedure PortYaz(Port: word; Value: Word);
var
 tmp:Ansichar;
begin
 tmp:=Ansichar(Value);
 asm
     mov dx, port
     mov al, tmp
     out dx, al  //out ile donanıma veri gönderiyoruz
 end;
end;


Şimdi bir de klavyeden veri okuyan fonksiyonumuzu yazalım:

function KlavyeOku: PAnsiChar;
var
 buffStr: array [0..3999] of AnsiChar;
 i:byte;
 x,y:byte;
begin
 x:=0;
 y:=0;
 i:=0;
 while (true) do begin
   if (PortOku($64) and $1)=1 then begin  //klavye komutu geliyorsa
       case PortOku($60) of
           //üstteki rakam tuşları
           2: begin   //1
               KarakterYaz(x,y,'1',Renk_Beyaz);   
               buffStr[i]:='1'; 
               inc(i);
               inc(x);
           end;
           3: begin   //2
               KarakterYaz(x,y,'2',Renk_Beyaz);   
               buffStr[i]:='2'; 
               inc(i);
               inc(x);
           end;
           4: begin  //3
               KarakterYaz(x,y,'3',Renk_Beyaz);   
               buffStr[i]:='3'; 
               inc(i);
               inc(x);
           end;
           5: begin  //4
               KarakterYaz(x,y,'4',Renk_Beyaz);   
               buffStr[i]:='4'; 
               inc(i);
               inc(x);
           end;
           6: begin  //5
               KarakterYaz(x,y,'5',Renk_Beyaz);   
               buffStr[i]:='5'; 
               inc(i);
               inc(x);
           end;
           7: begin //6 
               KarakterYaz(x,y,'6',Renk_Beyaz);   
               buffStr[i]:='6'; 
               inc(i);
               inc(x);
           end;
           8: begin   //7
               KarakterYaz(x,y,'7',Renk_Beyaz);   
               buffStr[i]:='7'; 
               inc(i);
               inc(x);
           end;
           9: begin   //8
               KarakterYaz(x,y,'8',Renk_Beyaz);   
               buffStr[i]:='8'; 
               inc(i);
               inc(x);
           end;
           10: begin  //9
               KarakterYaz(x,y,'9',Renk_Beyaz);   
               buffStr[i]:='9'; 
               inc(i);
               inc(x);
           end;
           11: begin   //0
               KarakterYaz(x,y,'0',Renk_Beyaz);   
               buffStr[i]:='0'; 
               inc(i);
               inc(x);
           end;
           12: begin //* 
               KarakterYaz(x,y,'*',Renk_Beyaz);   
               buffStr[i]:='*'; 
               inc(i);
               inc(x);
           end;
           13: begin //tire 
               KarakterYaz(x,y,'-',Renk_Beyaz);   
               buffStr[i]:='-'; 
               inc(i);
               inc(x);
           end;
           14: begin //backspace-sola doğru silme 
               if i>0 then dec(i);
               if x>0 then dec(x);
               
               KarakterYaz(x,y,' ',Renk_Beyaz);  
               buffstr[i] := ' ';
               buffstr[i+1] := #0;
           end;
           //tab-q-w-e-r-t-y tuşları
           15: begin //tab
               //imleci 8 karakter ileri götür
               MetinYaz(x,y,'        ',Renk_Beyaz);
               buffStr[i]:=' '; 
               buffStr[i+1]:=' ';  
               buffStr[i+2]:=' '; 
               buffStr[i+3]:=' ';
               buffStr[i+4]:=' ';
               buffStr[i+5]:=' ';
               buffStr[i+6]:=' ';
               buffStr[i+7]:=' ';
               inc(i,8);
               inc(x,8);
           end;
           16: begin //q
               KarakterYaz(x,y,'q',Renk_Beyaz);   
               buffStr[i]:='q'; 
               inc(i);
               inc(x);
           end;
           17: begin //w
               KarakterYaz(x,y,'w',Renk_Beyaz);   
               buffStr[i]:='w'; 
               inc(i);
               inc(x);
           end;
           18: begin //e
               KarakterYaz(x,y,'e',Renk_Beyaz);   
               buffStr[i]:='e'; 
               inc(i);
               inc(x);
           end;
           19: begin //r 
               KarakterYaz(x,y,'r',Renk_Beyaz);   
               buffStr[i]:='r'; 
               inc(i);
               inc(x);
           end;
           20: begin //t 
               KarakterYaz(x,y,'t',Renk_Beyaz);   
               buffStr[i]:='t'; 
               inc(i);
               inc(x);
           end;
           21: begin //y 
               KarakterYaz(x,y,'y',Renk_Beyaz);   
               buffStr[i]:='y'; 
               inc(i);
               inc(x);
           end;
           22: begin //u 
               KarakterYaz(x,y,'u',Renk_Beyaz);   
               buffStr[i]:='u'; 
               inc(i);
               inc(x);
           end;
           23: begin //ı 
               KarakterYaz(x,y,'i',Renk_Beyaz); 
               buffStr[i]:='i'; 
               inc(i);
               inc(x);
           end;
           24: begin //o 
               KarakterYaz(x,y,'o',Renk_Beyaz); 
               buffStr[i]:='o'; 
               inc(i);
               inc(x);
           end;
           25: begin //p 
               KarakterYaz(x,y,'p',Renk_Beyaz); 
               buffStr[i]:='p'; 
               inc(i);
               inc(x);
           end;
           26: begin //ğ 
               KarakterYaz(x,y,'g',Renk_Beyaz); 
               buffStr[i]:='g'; 
               inc(i);
               inc(x);
           end;
           27: begin //ü 
               KarakterYaz(x,y,'u',Renk_Beyaz); 
               buffStr[i]:='u'; 
               inc(i);
               inc(x);
           end;
           28: begin //enter tuşu
               x:=0;
               inc(y);
           end;
           //29:LEFT CONTROL
           //a-s-d-f-g tuşları
           30: begin
               KarakterYaz(x,y,'a',Renk_Beyaz); 
               buffStr[i]:='a';
               inc(i);    
               inc(x);
           end;
           31: begin
               KarakterYaz(x,y,'s',Renk_Beyaz); 
               buffStr[i]:='s'; 
               inc(i);    
               inc(x);
           end;
           32: begin
               KarakterYaz(x,y,'d',Renk_Beyaz); 
               buffStr[i]:='d'; 
               inc(i);   
               inc(x); 
           end;
           33: begin
               KarakterYaz(x,y,'f',Renk_Beyaz); 
               buffStr[i]:='f'; 
               inc(i);    
               inc(x);
           end;
           34: begin
               KarakterYaz(x,y,'g',Renk_Beyaz); 
               buffStr[i]:='g'; 
               inc(i);   
               inc(x); 
           end;
           35: begin
               KarakterYaz(x,y,'h',Renk_Beyaz); 
               buffStr[i]:='h'; 
               inc(i);  
               inc(x);  
           end;
           36: begin
               KarakterYaz(x,y,'j',Renk_Beyaz); 
               buffStr[i]:='j'; 
               inc(i);    
               inc(x);
           end;
           37: begin
               KarakterYaz(x,y,'k',Renk_Beyaz); 
               buffStr[i]:='k'; 
               inc(i);    
               inc(x);
           end;
           38: begin
               KarakterYaz(x,y,'l',Renk_Beyaz); 
               buffStr[i]:='l'; 
               inc(i);    
               inc(x);
           end;
           39: begin  //ş
               KarakterYaz(x,y,'s',Renk_Beyaz); 
               buffStr[i]:='s'; 
               inc(i);    
               inc(x);
           end;
           40: begin  //i
               KarakterYaz(x,y,'i',Renk_Beyaz); 
               buffStr[i]:='i'; 
               inc(i);  
               inc(x);  
           end;
           41: begin  //,
               KarakterYaz(x,y,',',Renk_Beyaz); 
               buffStr[i]:=','; 
               inc(i);  
               inc(x);  
           end;
           //42 LEFT SHIFT
           43: begin  //<
               KarakterYaz(x,y,',',Renk_Beyaz); 
               buffStr[i]:=','; 
               inc(i);   
               inc(x); 
           end;
           44: begin  //z
               KarakterYaz(x,y,'z',Renk_Beyaz); 
               buffStr[i]:='z'; 
               inc(i);    
               inc(x);
           end;
           45: begin  //x
               KarakterYaz(x,y,'x',Renk_Beyaz); 
               buffStr[i]:='x'; 
               inc(i);    
               inc(x);
           end;
           46: begin  //c
               KarakterYaz(x,y,'c',Renk_Beyaz); 
               buffStr[i]:='c'; 
               inc(i);   
               inc(x); 
           end;
           47: begin  //v
               KarakterYaz(x,y,'v',Renk_Beyaz); 
               buffStr[i]:='v'; 
               inc(i);   
               inc(x); 
           end;
           48: begin  //b
               KarakterYaz(x,y,'b',Renk_Beyaz); 
               buffStr[i]:='b'; 
               inc(i);    
               inc(x);
           end;
           49: begin  //n
               KarakterYaz(x,y,'n',Renk_Beyaz); 
               buffStr[i]:='n'; 
               inc(i);    
               inc(x);
           end;
           50: begin  //m
               KarakterYaz(x,y,'m',Renk_Beyaz); 
               buffStr[i]:='m'; 
               inc(i);    
               inc(x);
           end;
           51: begin  //ö
               KarakterYaz(x,y,'o',Renk_Beyaz); 
               buffStr[i]:='o'; 
               inc(i);    
               inc(x);
           end;
           52: begin  //ç
               KarakterYaz(x,y,'c',Renk_Beyaz); 
               buffStr[i]:='c'; 
               inc(i);    
               inc(x);
           end;
           53: begin  //.
               KarakterYaz(x,y,'.',Renk_Beyaz); 
               buffStr[i]:='.'; 
               inc(i);    
               inc(x);
           end;
           //56 RIGHT SHIFT YA DA LEFT ALT
           57: begin  //SPACE BAR
               KarakterYaz(x,y,' ',Renk_Beyaz); 
               buffStr[i]:=' '; 
               inc(i);  
               inc(x);  
           end;
       end;//case
   end;
 end; //while
 buffstr[i-1] := #0; 
 Result:=buffstr;
end;


PortOku($64) diyerek klavyemizden bir komut gelip gelmediğini kontrol ediyoruz. Eğer klavyeden komut geliyorsa PortOku($60) ile gelen veriyi alıyoruz. $64 komut, $60 portu ise veri içindir.

PortOku($60) fonksiyonumuzdan gelen veri 2 ise klavyenin üstündeki 1 tuşuna basılmış demektir. Ekrana 1 yazdırıyoruz:


case PortOku($60) of
           //üstteki rakam tuşları
           2: begin   //1
               KarakterYaz(x,y,'1',Renk_Beyaz);   
               buffStr[i]:='1'; 
               inc(i);
               inc(x);
           end;
           ....
end;

Bu şekilde tek tek gelen veriye göre ekrana karakterleri yazdırıyoruz.

Bu fonksiyonlarımız için uKlavye.inc adında bir dosya oluşturalım ve yukarıdaki fonksiyonların hepsini içine yazalım. uKlavye.inc dosyamızın içeriği şu şekilde olmalı:


function PortOku(port:word):byte;
asm
  mov dx, port //port numarasından veriyi çekip dx'e al
  in al, dx    //in ile al'ye veriyi al
end;

procedure PortYaz(Port: word; Value: Word);
var
 tmp:Ansichar;
begin
 tmp:=Ansichar(Value);
 asm
     mov dx, port
     mov al, tmp
     out dx, al  //out ile donanıma veri gönderiyoruz
 end;
end;


function KlavyeOku: PAnsiChar;
var
 buffStr: array [0..3999] of AnsiChar;
 i:byte;
 x,y:byte;
begin
 x:=0;
 y:=0;
 i:=0;
 while (true) do begin
   if (PortOku($64) and $1)=1 then begin  //klavye komutu geliyorsa
       case PortOku($60) of
           //üstteki rakam tuşları
           2: begin   //1
               KarakterYaz(x,y,'1',Renk_Beyaz);   
               buffStr[i]:='1'; 
               inc(i);
               inc(x);
           end;
           3: begin   //2
               KarakterYaz(x,y,'2',Renk_Beyaz);   
               buffStr[i]:='2'; 
               inc(i);
               inc(x);
           end;
           4: begin  //3
               KarakterYaz(x,y,'3',Renk_Beyaz);   
               buffStr[i]:='3'; 
               inc(i);
               inc(x);
           end;
           5: begin  //4
               KarakterYaz(x,y,'4',Renk_Beyaz);   
               buffStr[i]:='4'; 
               inc(i);
               inc(x);
           end;
           6: begin  //5
               KarakterYaz(x,y,'5',Renk_Beyaz);   
               buffStr[i]:='5'; 
               inc(i);
               inc(x);
           end;
           7: begin //6 
               KarakterYaz(x,y,'6',Renk_Beyaz);   
               buffStr[i]:='6'; 
               inc(i);
               inc(x);
           end;
           8: begin   //7
               KarakterYaz(x,y,'7',Renk_Beyaz);   
               buffStr[i]:='7'; 
               inc(i);
               inc(x);
           end;
           9: begin   //8
               KarakterYaz(x,y,'8',Renk_Beyaz);   
               buffStr[i]:='8'; 
               inc(i);
               inc(x);
           end;
           10: begin  //9
               KarakterYaz(x,y,'9',Renk_Beyaz);   
               buffStr[i]:='9'; 
               inc(i);
               inc(x);
           end;
           11: begin   //0
               KarakterYaz(x,y,'0',Renk_Beyaz);   
               buffStr[i]:='0'; 
               inc(i);
               inc(x);
           end;
           12: begin //* 
               KarakterYaz(x,y,'*',Renk_Beyaz);   
               buffStr[i]:='*'; 
               inc(i);
               inc(x);
           end;
           13: begin //tire 
               KarakterYaz(x,y,'-',Renk_Beyaz);   
               buffStr[i]:='-'; 
               inc(i);
               inc(x);
           end;
           14: begin //backspace-sola doğru silme 
               if i>0 then dec(i);
               if x>0 then dec(x);
               
               KarakterYaz(x,y,' ',Renk_Beyaz);  
               buffstr[i] := ' ';
               buffstr[i+1] := #0;
           end;
           //tab-q-w-e-r-t-y tuşları
           15: begin //tab
               //imleci 8 karakter ileri götür
               MetinYaz(x,y,'        ',Renk_Beyaz);
               buffStr[i]:=' '; 
               buffStr[i+1]:=' ';  
               buffStr[i+2]:=' '; 
               buffStr[i+3]:=' ';
               buffStr[i+4]:=' ';
               buffStr[i+5]:=' ';
               buffStr[i+6]:=' ';
               buffStr[i+7]:=' ';
               inc(i,8);
               inc(x,8);
           end;
           16: begin //q
               KarakterYaz(x,y,'q',Renk_Beyaz);   
               buffStr[i]:='q'; 
               inc(i);
               inc(x);
           end;
           17: begin //w
               KarakterYaz(x,y,'w',Renk_Beyaz);   
               buffStr[i]:='w'; 
               inc(i);
               inc(x);
           end;
           18: begin //e
               KarakterYaz(x,y,'e',Renk_Beyaz);   
               buffStr[i]:='e'; 
               inc(i);
               inc(x);
           end;
           19: begin //r 
               KarakterYaz(x,y,'r',Renk_Beyaz);   
               buffStr[i]:='r'; 
               inc(i);
               inc(x);
           end;
           20: begin //t 
               KarakterYaz(x,y,'t',Renk_Beyaz);   
               buffStr[i]:='t'; 
               inc(i);
               inc(x);
           end;
           21: begin //y 
               KarakterYaz(x,y,'y',Renk_Beyaz);   
               buffStr[i]:='y'; 
               inc(i);
               inc(x);
           end;
           22: begin //u 
               KarakterYaz(x,y,'u',Renk_Beyaz);   
               buffStr[i]:='u'; 
               inc(i);
               inc(x);
           end;
           23: begin //ı 
               KarakterYaz(x,y,'i',Renk_Beyaz); 
               buffStr[i]:='i'; 
               inc(i);
               inc(x);
           end;
           24: begin //o 
               KarakterYaz(x,y,'o',Renk_Beyaz); 
               buffStr[i]:='o'; 
               inc(i);
               inc(x);
           end;
           25: begin //p 
               KarakterYaz(x,y,'p',Renk_Beyaz); 
               buffStr[i]:='p'; 
               inc(i);
               inc(x);
           end;
           26: begin //ğ 
               KarakterYaz(x,y,'g',Renk_Beyaz); 
               buffStr[i]:='g'; 
               inc(i);
               inc(x);
           end;
           27: begin //ü 
               KarakterYaz(x,y,'u',Renk_Beyaz); 
               buffStr[i]:='u'; 
               inc(i);
               inc(x);
           end;
           28: begin //enter tuşu
               x:=0;
               inc(y);
           end;
           //29:LEFT CONTROL
           //a-s-d-f-g tuşları
           30: begin
               KarakterYaz(x,y,'a',Renk_Beyaz); 
               buffStr[i]:='a';
               inc(i);    
               inc(x);
           end;
           31: begin
               KarakterYaz(x,y,'s',Renk_Beyaz); 
               buffStr[i]:='s'; 
               inc(i);    
               inc(x);
           end;
           32: begin
               KarakterYaz(x,y,'d',Renk_Beyaz); 
               buffStr[i]:='d'; 
               inc(i);   
               inc(x); 
           end;
           33: begin
               KarakterYaz(x,y,'f',Renk_Beyaz); 
               buffStr[i]:='f'; 
               inc(i);    
               inc(x);
           end;
           34: begin
               KarakterYaz(x,y,'g',Renk_Beyaz); 
               buffStr[i]:='g'; 
               inc(i);   
               inc(x); 
           end;
           35: begin
               KarakterYaz(x,y,'h',Renk_Beyaz); 
               buffStr[i]:='h'; 
               inc(i);  
               inc(x);  
           end;
           36: begin
               KarakterYaz(x,y,'j',Renk_Beyaz); 
               buffStr[i]:='j'; 
               inc(i);    
               inc(x);
           end;
           37: begin
               KarakterYaz(x,y,'k',Renk_Beyaz); 
               buffStr[i]:='k'; 
               inc(i);    
               inc(x);
           end;
           38: begin
               KarakterYaz(x,y,'l',Renk_Beyaz); 
               buffStr[i]:='l'; 
               inc(i);    
               inc(x);
           end;
           39: begin  //ş
               KarakterYaz(x,y,'s',Renk_Beyaz); 
               buffStr[i]:='s'; 
               inc(i);    
               inc(x);
           end;
           40: begin  //i
               KarakterYaz(x,y,'i',Renk_Beyaz); 
               buffStr[i]:='i'; 
               inc(i);  
               inc(x);  
           end;
           41: begin  //,
               KarakterYaz(x,y,',',Renk_Beyaz); 
               buffStr[i]:=','; 
               inc(i);  
               inc(x);  
           end;
           //42 LEFT SHIFT
           43: begin  //<
               KarakterYaz(x,y,',',Renk_Beyaz); 
               buffStr[i]:=','; 
               inc(i);   
               inc(x); 
           end;
           44: begin  //z
               KarakterYaz(x,y,'z',Renk_Beyaz); 
               buffStr[i]:='z'; 
               inc(i);    
               inc(x);
           end;
           45: begin  //x
               KarakterYaz(x,y,'x',Renk_Beyaz); 
               buffStr[i]:='x'; 
               inc(i);    
               inc(x);
           end;
           46: begin  //c
               KarakterYaz(x,y,'c',Renk_Beyaz); 
               buffStr[i]:='c'; 
               inc(i);   
               inc(x); 
           end;
           47: begin  //v
               KarakterYaz(x,y,'v',Renk_Beyaz); 
               buffStr[i]:='v'; 
               inc(i);   
               inc(x); 
           end;
           48: begin  //b
               KarakterYaz(x,y,'b',Renk_Beyaz); 
               buffStr[i]:='b'; 
               inc(i);    
               inc(x);
           end;
           49: begin  //n
               KarakterYaz(x,y,'n',Renk_Beyaz); 
               buffStr[i]:='n'; 
               inc(i);    
               inc(x);
           end;
           50: begin  //m
               KarakterYaz(x,y,'m',Renk_Beyaz); 
               buffStr[i]:='m'; 
               inc(i);    
               inc(x);
           end;
           51: begin  //ö
               KarakterYaz(x,y,'o',Renk_Beyaz); 
               buffStr[i]:='o'; 
               inc(i);    
               inc(x);
           end;
           52: begin  //ç
               KarakterYaz(x,y,'c',Renk_Beyaz); 
               buffStr[i]:='c'; 
               inc(i);    
               inc(x);
           end;
           53: begin  //.
               KarakterYaz(x,y,'.',Renk_Beyaz); 
               buffStr[i]:='.'; 
               inc(i);    
               inc(x);
           end;
           //56 RIGHT SHIFT YA DA LEFT ALT
           57: begin  //SPACE BAR
               KarakterYaz(x,y,' ',Renk_Beyaz); 
               buffStr[i]:=' '; 
               inc(i);  
               inc(x);  
           end;
       end;//case
   end;
 end; //while
 buffstr[i-1] := #0; 
 Result:=buffstr;
end;


Daha sonra kernelMain dosyamıza gelelim. {$I uEkran.inc} satırının altına {$I uKlavye.inc} satırını ekleyelim. Ayrıca kMain prosedüründe KlavyeOku; diyerek klavye girişini okuyalım. kernelMain.pas dosyamız da şu şekilde olmalı:

unit kernelMain;
interface

procedure kMain; stdcall;
procedure loader; stdcall;
procedure loader_end;

implementation

uses
 uConsts, uTypes;


//Kernel başlangıcı
procedure loader; stdcall;
asm
 cli
 call kmain
 hlt
end;

{$I uEkran.inc}
{$I uKlavye.inc}

//kernel başla
procedure kMain; stdcall;
begin

 Temizle; //ekranı temizle
 KlavyeOku;
end;

//yalnızca hesaplama için oluşturduk
procedure Loader_End(); begin end;

//Kernel sonu



end.

Delphi'den run diyerek ya da xos.exe dosyasını çalıştırarak işletim sistemimizin qemu ile açılmasını gerçekleştirelim. Artık ekrana bir şeyler yazabiliyoruz.
Cevapla
#5
Konuya verdiğiniz önem ve dolayısıyla konunun sabitlenmesi çok hoşuma gitti. Teşekkür ederim. Vakit buldukça yazmaya devam edeceğim.
Cevapla
#6
Selamlar hocam,
Çok güzel bir konu. Teşekkürler, bazen yeni şeyler öğreniyoruz, bazen bilgilerimizi tazeliyoruz. Şimdilik çokça eskiyi yâd ediyoruz, ilerledikçe muhtemelen çok daha öğretici olacak. Bizi TP dönemine götürdünüz.
Cevapla
#7
Beğenmeniz benim çok önemli. Ayrıca anlatırken birçok şeyi ben de öğreniyorum. Konu çok geniş, programlamaya sağlam bir hakimiyet gerektiriyor.
Cevapla
#8
Ellerinize sağlık. Nerelere gittim nerelere Smile Int 27 TSR, Int 33 mouse kullanımı vb. DOS zamanında neler neler yapıyorduk. Yaşlanmışız.
Mal sahibi, mülk sahibi
Hani bunun ilk sahibi ?
Mal da yalan mülk de yalan
Var biraz da sen oyalan...
WWW
Cevapla
#9
(20-01-2021, Saat: 00:49)Tuğrul HELVACI Adlı Kullanıcıdan Alıntı: Ellerinize sağlık. Nerelere gittim nerelere Smile Int 27 TSR, Int 33 mouse kullanımı vb. DOS zamanında neler neler yapıyorduk. Yaşlanmışız.

Yıllar çabuk geçiyor üstadım.
Cevapla
#10
(20-01-2021, Saat: 02:51)PROGRAMADOR35 Adlı Kullanıcıdan Alıntı:
(20-01-2021, Saat: 00:49)Tuğrul HELVACI Adlı Kullanıcıdan Alıntı: Ellerinize sağlık. Nerelere gittim nerelere Smile Int 27 TSR, Int 33 mouse kullanımı vb. DOS zamanında neler neler yapıyorduk. Yaşlanmışız.

Yıllar çabuk geçiyor üstadım.

Büyük Merakla takip ediyorum. emeğinize sağlık. Devamı gelecek mi üstat ?
Cevapla


Konu ile Alakalı Benzer Konular
Konular Yazar Yorumlar Okunma Son Yorum
  Delphi Direktif Kullanımı narkotik 14 6.206 20-12-2024, Saat: 13:55
Son Yorum: frmman
  Delphi ile .Net Ortamında geliştirilen dll içerisindeki fonksiyon kullanımı yhackup 10 10.316 09-04-2023, Saat: 02:17
Son Yorum: gogo72
  Delphi ve Protocol Buffers SimaWB 10 9.273 10-12-2022, Saat: 15:04
Son Yorum: SimaWB
  Delphi AES 128 ECB PKCS5 Padding ile sorun aegean 1 1.707 28-11-2022, Saat: 13:07
Son Yorum: aegean
  Delphi IDE'sine Eklenti Yapmak - 2 SimaWB 29 26.649 03-07-2022, Saat: 16:40
Son Yorum: enigma



Konuyu Okuyanlar: