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:
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.
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.
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.
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.
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;
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:
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:
Ö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ı:
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.
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.
(20-01-2021, Saat: 00:49)Tuğrul HELVACI Adlı Kullanıcıdan Alıntı: Ellerinize sağlık. Nerelere gittim nerelere Int 27 TSR, Int 33 mouse kullanımı vb. DOS zamanında neler neler yapıyorduk. Yaşlanmışız.
(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 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 ?