ROM RUTİNLERİ
NEREDEN : İSTANBUL NİCK / GRUP(LAR) : HADES / HI3S WEB SİTE : WWW.HI3S.ORG HTTP://HADES6510.SITEMYNET.COM
(Programlar C64ASM V1.1 ile compile edilecek şekilde yazılmıştır) ROM rutinlerini tanıtmaya devam ediyoruz. İlk adresimiz $A3BF (41919). ADRES : $A3BF (41919) GÖREVİ : Data blok taşıma. Bu adresi bellekteki bir bölgeyi başka bir yere taşıma amaçlı olarak kullanabilirsiniz. Zero Page’de bulunan 6 adet adresi kullanıp istediğiniz uzunluktaki bir bölgeyi taşıyabilirsiniz. Şimdi bir örnek ile bu adresin nasıl kullanıldığını öğrenelim. Örneğimizde $c000-$c750 arasındaki bölgeyi $2600-$2d50 arasına taşıyalım. *=$0801 .word nextline .word 2004 ; 2004 .byte $9e ; SYS .text "2061" ; 2061 .byte 0 ; komutu nextline .word 0 transfer1 lda #$00 ;Başlangıç adresi LOW byte ldx #$c0 ;Başlangıç adresi HIGH byte sta $5f ;Başlangıç LOW byte pointer stx $60 ;Başlangıç HIGH byte pointer lda #$50 ;Bitiş adresi LOW byte ldx #$c7 ;Bitiş adresi HIGH byte sta $5a ;Bitiş LOW byte pointer stx $5b ;Bitiş HIGH byte pointer lda #$50 ;Hedef bitiş adresi LOW byte ldx #$2d ;Hedef bitiş adresi HIGH byte sta $58 ;Hedef bitiş LOW byte pointer stx $59 ;Hedef bitiş HIGH byte pointer jsr $a3bf rts Transfer işlemini yapan rutin 28 byte yer kaplamaktadır. Bu adresin kullanılışı şöyledir. Kopyalayacağınız bölgenin başlangıç adresi $5f-$60 adreslerine, bitiş adresi $5a-$5b adreslerine, yeni bölgenin bitiş adresi ise $58-$59 adreslerine yazılır ve rutin çağrılır. Bu rutini kullanacağınız zaman BASIC ROM'un devrede olması gereklidir. Aynı taşıma işlemini bir de başka rutin yazarak yapalım. Taşınacak bölgenin uzunluğu $c750-$c000=$0750 byte olup 8 döngüde rahatça transfer edebiliriz.
transfer2
ldx
#$08
;Döngü sayacı
ldy
#$00
;Byte sayacı
kaynak
lda
$c000,y
;Kaynak adresi
hedef
sta
$2600,y
;Hedef adresi
iny
bne
kaynak
inc
kaynak+2
inc
hedef+2
dex
bne
kaynak
rts
Transfer2 rutinimiz 23 byte uzunluğundadır. Yani üstteki rutinden
5 byte daha kısadır. Ama bana göre 2 dezavantajı vardır. Birincisi : Transfer1
rutininde istediğiniz uzunlukta byte transfer edebilirken, transfer2 rutininde
transfer edilen byte uzunluğu 256'nın katları şeklinde olacaktır. Transfer1
rutininde $0750 (1872) byte transfer edilirken, transfer2 rutininde
256'nın katları şeklinde olduğu için 2048 byte transfer edilecektir. Eğer
hafıza düzenlemeniz biraz karışıksa fazladan transfer edilen 1 byte bile
programınızın bozulmasına neden olabilir. Bununda çaresi var aslında.
Önce $0750 byte'ın $0700 byte'ını transfer edersiniz, sonrada uygun $50 byte
için işlem yaparsınız. Bu ise fazladan 9 byte'lık bir code demektir.
İkinci dezavantaj ise, transfer2 rutinini bu şekliyle sadece bir kez
kullanılabilir. Çünkü kaynak ve hedef adreslerinin high byte'ları her
döngüde 1 arttırılmaktadır. Eğer rutini ikinci kez kullanmak istiyorsanız,
rutinin başında kaynak ve hedef adreslerinin high bytle'rını program
içindeki yerlerine yazmanız geerekir. Bu işlem ise 10 byte daha
kullanmak demektir. Böylece TRANSFER1=28 byte, TRANSFER2=33 byte yer
kaplamış olacak, ayrıca 1. dezavantaj yine devam edecektir.
ADRES
: $E8EA (59626)
GÖREVİ
: Ekranı bir satır yukarı kaydırma.
The anatomy of a COMMODORE 64 isimli kitapta SCROLL SCREEN olarak
isimlendirilen bu rutin ekranı bir satır yukarı kaydırır. Normalde ekranın
yukarı kayması için kursörün en alt satırda olması ve RETURN veya CURSOR DOWN
tuşuna basılmış olması gerekir. Bu adres ise kursörün pozisyonunu dikkate
almayıp ekranı olduğu gibi bir satır yukarı kaydırır. Peki bu adresle ne
yapılabilir? Mesela Basic'e ROLL komutu ekleyip, Basic ile hazırladığınız bir
açılış ekranını 1 satır yukarı kaydırıp, üstten kaybolan satırı en alt satırda
tekrar çıkartabilirsiniz. Tabii bunun için gerekli olan programı yazmanız lazım.
İsterseniz bu efekti ufak bir assembler rutiniyle yapmayı deneyelim.
*=$0801
.word nextline
.word 2004
; 2004
.byte $9e
; SYS
.text "2061"
; 2061
.byte 0
; komutu
nextline
.word 0
ldx
#$00
;Sayacı sıfırlayalım
loop0
lda
$0400,x
;Ekranın ilk satırındaki
sta
temp0,x
;bilgileri kopyalayalım
lda
$d800,x
;Aynı işi renk belleği
sta
temp1,x
;için de yapalım.
inx
;sayacı 1 arttır
cpx
#$28
;40 oldu mu?
bne
loop0
;olmadıysa tekrarla
jsr
$e8ea
;Olduysa ekranı 1 satır yukarı kaydır
ldx
#$00
;sayacı sıfırlayalım
loop1
lda
temp0,x
;kopyaladığımız değerleri ekranın
sta
$07c0,x
;en alt satırına yazalım.
lda
temp1,x
;Aynı işi renk belleği
sta
$dbc0,x
;için de yapalım.
inx
;sayacı 1 arttır
cpx
#$28
;40 oldu mu?
bne
loop1
;olmadıysa tekrarla
son
rts
;evet oldu. Öyleyse çıkalım.
temp0
=son+1
temp1
=temp0+40
.end
Eğer bu efekti $EA8A adresini kullanmadan yapsaydık oldukça uzun
bir program yazmak zorunda kalacaktık.
ADRES
: $FFF0 (65520)
GÖREVİ
: Kursör pozisyonunu ayarlama / okuma
Romda öyle rutinler vardır ki sizleri birçok işten kurtarır. Birazdan
anlatacağımız bu rutinde bunlardan biridir. Bir program yazmaya başladınız ve
ekranın 12. Satır 10. Sütun pozisyonundan başlayan 10 harflik bir yazı yazmanız
gerekiyor. Bu işlemi normalde iki şekilde yapabilirsiniz. Birinci olarak ekranın
ilgili pozisyonunun ekran belleği adresini öğrenip yazınızı ekran kodu olarak
yazdırırsınız. İkincisi kursörü önce en üst köşeye alırsınız. Daha sonra
“return” tuşunun kodunu kullanarak kursörü istediğiniz satıra getirirsiniz.
Yazacağınız yazıya biraz “boşluk” karakteri ekleyerek istediğiniz pozisyona
yazmış olusunuz. İkisinden birini tercih edin. Birinci seçenekte ekran
belleğinin adresleriyle uğraşırsınız. İkinci seçenekte ise fazladan byte
kullanarak programınızı uzatırsınız.
Aranızda “Başka bir alternatif yok mu ?” diye soranlar olabilir. Evet var.
KERNAL ROM’da, işletim sistemi rutinleri için sıçrama tablosu denilen ve Rom’un
son 128 byte’ında yer alan, direct ve indirect jump komutlarından oluşan bir
bölge vardır. Bu bölgenin $FFF0 adresi tam bize göredir. Ekranın istediğiniz
yerine bir yazı yazmak için yapmanız gereken işlemler şunlardır. Önce “carry”
bitini sıfırlayın. Sonra X registerine satır numarasını, Y registerine süttun
değerini yükleyin. En son olarak bir JSR komutuyla rutini çağırın. Böylece
kursörün pozisyonunu ayarlamış olduk. Daha sonra ise geçen sayıda tanıtmış
olduğumuz $AB1E adresini kullanarak yazıyı ekrana yazdırın. İsterseniz buraya
kadar yazdıklarımızla ilgili örnekler verelim.
Yazımız 10. Satır 5. Sütunda olsun.
İlk önce doğrudan ekran adresi vererek bu yazıyı yazdıralım. Bu arada ufak bir
not düşelim. Vereceğimiz örneklerde satır ve sütun numaraları “0” dan
başlamaktadır. Program yazarken buna dikkat edin.
POZİSYON = EKRAN BELLEĞİ BAŞLANGIÇ + SATIR * 40 + SÜTUN formülüne göre adresi
hesaplayalım.
EKRAN BELLEĞİ BAŞLANGIÇ ADRESİ = 1024
POZİSYON = 1024 + 10*40 + 5 = 1024 + 400 + 5 = 1429 ($0595)
Şimdi yazıyı yazdıralım.
ldx
#$00
loop0
lda
text,x
sta
$0595,x
inx
cpx
#$0b
bne
loop0
rts
text
.scrl “c64 turkiye”
İşin hesaplama kısmı olmasa her şey çok güzel olacak. Şimdi de ikinci şıkkı deneyelim. jsr $e544 ldx #$00 loop0 lda text,x jsr $ffd2 inx cpx #$1a bne loop0 rts text .byte $0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d,$0d .byte $20,$20,$20,$20,$20 .text “c64 turkiye” $0d sayısı return tuşunun, $20 sayısı ise “boşluk” karakterinin kodudur. Şimdi de $FFF0 adresini kullanarak yazıyı yazdıralım. clc ;”carry” bitini sıfırla ldx #$0a ;satır değeri ldy #$05 ;sütun değeri jsr $fff0 ;kursörü ayarla lda #<text ldy #>text jsr $ab1e rts text .text “c64 turkiye” .byte 0 Örnekleri karşılaştırarak hangisi daha kolayınıza geliyorsa onu kullanın. Şimdi de kursörün pozisyonunu okuyalım. sec ;”carry” bitini “1” yap jsr $fff0 ;rutini çağır. ... ... rts
Rutinden geri dönüşte kursörün satır değeri X registerinde, sütun değeri ise Y registerinde bulunur.
Bildiğiniz gibi C64’ün BASIC komutlarında kursörle ilgili bir komut yoktur. $FFF0 adresini kullanarak, kursörü istediğiniz pozisyona getirmek için “CURSOR” komutu ekleyebilirsiniz. CURSOR 10,10 : PRINT “C64 TURKIYE” vs. kullanmak ne güzel olurdu değil mi? (Bu yazıyı yazdıktan sonra “HADES’BASIC” bölümüne “CURSOR” komutunu ekledim.)