ÇİZGİ KURSÖR

NEREDEN : İSTANBUL NİCK / GRUP(LAR) : HADES / HI3S WEB SİTE : WWW.HI3S.ORG HTTP://HADES6510.SITEMYNET.COM

Eğer C64’ün yanıp sönen kare şeklindeki kursöründen sıkıldıysanız aşağıdaki kısa programla (sadece 96 byte uzunluğundadır) kursörünüz artık PC’lerin DOS zamanındaki kursörü şeklinde olacaktır. Peki bu değişiklik nasıl oluyor? Yeni kursörümüz aslında bir sprite’dır ve interrupt tekniği kullanılmıştır. Normal kursörün satır ve sütun değerleri okunarak programda sprite’ın X ve Y koordinat değerlerine dönüştürülmektedir.

*=$0801 
.word nextline 
.word 2004  
; 2004 
.byte $9e 
; SYS 
.text "2061" 
; 2061 
.byte 0 
; komutu 
nextline 
.word 0 
sei 
;interruptları durdur 
lda 
#<cursor 
;programın low byte’ını 
sta 
$0134  
;interrupt vektörünün low byte’ına yaz  
lda 
#>cursor 
;programın high byte’ını 
sta 
$0315  
;interrupt vektörünün high byte’ına yaz 
ldx 
#$00  
;X registerini sıfırla 
txa 
;Akü’ye X registerinin değerini yükle 
loop0  
sta 
$03c0,x 
;Sprite data adresine 0 yaz 
inx 
;sayacı 1 arttır 
cpx 
#$40  
;#$40 (64) oldumu ? 
bne 
loop0  
;olmadıysa tekrarla 
lda 
#$ff  
;çizgi şekli olması için $ff sayısını 
sta 
$03c0+21 
;sprite’ın uygun data adresine yaz 
lda 
#$03c0/64 
;sprite data başlangıcını  
sta 
$07f8  
;1. sprite pointerine yaz 
lda 
#$01  
;1. Sprite’ı 
sta 
$d015  
;görünür yap 
cli 
;interruptları başlat 
rts 
;programı bitir 
cursor 
lda  $d3 
;normal kursörün sütun pozisyonunu oku 
cmp  #$1d  
;$1d (19) ile karşılaştır 
bcc  no_extra 
;$1d’den küçükse git 
ldx 
#$01  
;sprite’ın extra x koordinatı var 
.byte $2c 
;bilgisayarı kandırma sayısı 
no_extra 
ldx 
#$00  
;sprite’ın extra x koordinatı yok 
stx 
$d010  
;spritelar için extra x koordinat adresi

asl ;sütun değerini 2 ile çarp asl ;sonucu 2 ile çarp asl ;önceki sonucu 2 ile çarp clc ;”carry” bitini sıfırla adc #$18 ;$18 (24) ile topla sta $d000 ;1. sprite’ın X koordinat adresine yaz. Burada biraz bilgi verelim. Yukarıda 3 defa asl komutunu kullandık. Peki neden böyle bir işlem yaptık? Normalde kursörün sütun değerini olduğu gibi sprite’ın x koordinatına veremeyiz. Eğer verirsek sprite’ımız sadece 1 pixel ilerlemiş olur. Bir karakter normalde 8 pixel genişliğindedir. Kursör dediğimiz şekil aslında bir karakterdir ve reverse space karakterinden başka bir şey değildir. Kursörün bir sonraki sütuna gitmesi demek sprite’ımızında 8 pixel ilerlemesi demektir. Kursörün sütun değeri*8 sayısı bize sprite’ın X koordinatını verecektir. Assemblerde bir sayıyı 8 ile çarpmak, o sayıyı 3 defa sola kaydırmak yani 3 defa ASL komutu kullanmak demektir. Buraya kadar tamam. Peki $18 (24) sayısı nereden geliyor. Bir sprite’ın ekranda tamamen görünür halde olması için X koordinatı $18 olmalıdır. Bu sayıyı 3 ASL komutu sonunda elde ettiğimiz sayıyla toplarsak işimiz tamam olacaktır. lda $d6 ;kursörün satır değerini oku asl ; 2 ile çarp asl ; bir daha 2 ile çarp asl ; son kez 2 ile çarp clc ;”carry” bitini sıfırla adc #$32 ;$32 (50) ile topla sta $d001 ;1. sprite’ın Y koordinat adresine yaz. Yukarıdaki açıklamanın bir benzerini satır değeri için yapıp sonucu sprite’ın Y koordinat adresine yazdığımızda kursörün o anki pozisyonunda birde sprite göstermiş oluruz. inc $d027 ;1. sprite’ın rengini değiştir. jsr $ffea ;zamanı ilerlet ve stop tuşunu kontrol et. jmp $ea61 ;Romdaki interrupt rutinine geri dön. .end Geldik son açıklamaya. Kendi yazdığımız bir interrupt rutininin çalışması bitince son komutun normalde JMP $EA31 veya $EA81 olması gerekir. $EA81 deki komutlar $EA31’den başlayan komutların devamıdır. Peki aradaki $50 (80) byte’ta neler olmaktadır? İlk önce Stop tuşu kontrolü ve zaman ilerletme yapılıyor. Sonra kursörün yakılıp söndürülmesi ve kursörle ilgili karakter ve renk işlemleri yapılıyor. Daha sonra ise teyp tuşlarına basılıp basılmadığı ve teyp motor on / off işlemleri yapılıyor. En son olarak ise klavye kontrolü yapılmakta ve $EA81 adresine gelinmektedir. $EA81’den itibaren ise sırayla Y, X ve A registerleri yığından geri alınıp interrupt rutini bitirilmektedir. Bizim rutinimizde ise önce JSR $FFEA ile bir işlem yapılmakta ve JMP $EA61 ile çıkış yapılmaktadır. Eğer JMP $EA31 kullansak kursör işlemleri yapılacak, JMP $EA81 kullansak tuşlar çalışmaz hale gelecek. Bu nedenle önce JSR $FFEA ile stop tuşunun kontrol edilmesini sağlıyoruz, sonrada kursör işlemlerine hiç uğramadan geri kalan işler için JMP $EA61 komutuyla işimizi bitiriyoruz.

C64 İÇİN BAŞ AŞAĞI KARAKTER SETİ PROGRAMI 
HAZIRLAYAN       : İSMAİL ŞAHİN 
İLETİŞİM         : HADES@HI3S.ORG 
HADES6510@YAHOO.COM 
NEREDEN          : İSTANBUL 
NİCK / GRUP(LAR) : HADES / HI3S 
WEB SİTE         : WWW.HI3S.ORG 
HTTP://HADES6510.SITEMYNET.COM 
*=$0801 
.word nextline 
.word 2004  
; 2004 
.byte $9e 
; SYS 
.text "2061" 
; 2061 
.byte 0 
; komutu 
nextline 
.word 0 
sei 
;İnterruptları engelle 
lda 
$01 
;Karakter ROM'u 
and 
#$fb  
;artık CPU tarafından  
sta 
$01   
;okunabilir 
lda 
#$d0  
;ROM adresi = $D000 
ldx 
#$30  
;RAM adresi = $3000 
ldy 
#$00  
;olacak şekilde ayarla. 
sty 
$fb 
;$FB ve $FC adreslerinde 
sta 
$fc 
;ROM adresi tutuluyor. 
sty 
$fd 
;$FD ve $FE adreslerinde 
stx 
$fe 
;RAM adresi tutuluyor. 
ldx 
#$10  
;Blok sayacı = $10 (16) 
transfer 
lda 
($fb),y 
;ROM'dan o anki adresi 
sta 
($fd),y 
;oku ve RAM'e kopyala 
iny 
;byte sayacını 1 arttır 
bne 
transfer 
;"0" değilse geri dön 
inc 
$fc 
;ROM HIGH adresi 1 arttır 
inc 
$fe 
;RAM HIGH adresi 1 arttır 
dex 
;Blok sayacını 1 azalt 
bne 
transfer 
;"0" olmadıysa geri dön. 
lda 
$01 
;I/O bölgesi eski haline 
ora 
#$04  
;getiriliyor. CPU artık 
sta 
$01 
;karakter roma erişemez 
cli 
;interruptlara izin ver 
lda 
#$1c  
;VIC'e yeni karakter 
sta 
$d018  
;setinin yerini bildir. 
new_fonts 
lda 
#$30  
;Karakter seti başlangıç 
ldy 
#$00  
;adresi $3000 olarak 
sty 
$fb 
;$FB ve $FC adreslerine 
sta 
$fc 
;kaydediliyor 
loop2  
ldy 
#$00  
;Y registeri byte sayacı=0 
loop0  
lda 
($fb),y 
;O anki adresten bir byte oku 
pha 
;okunan değeri yığına at 
iny 
;sayacı 1 arttır 
cpy 
#$08  
;8 oldumu ? 
bne 
loop0  
;olmadıysa bir byte daha oku  
ldy 
#$00  
;Y registeri byte sayacı=0 
loop1  
pla 
;yığındaki değeri al 
sta 
($fb),y 
;O anki adrese yaz 
iny 
;sayacı 1 arttır 
cpy 
#$08  
;8 oldumu ? 
bne 
loop1  
;olmadıysa yeni değeri al.

Yukarıdaki komutlarla bir karakteri baş aşağı çeviriyoruz. Burada asıl can alıcı nokta "YIĞIN" dediğimiz bölgenin kullanılmasıdır Yığın "LIFO" -Last In First Out- mantığıyla çalışır. Yani yığına atılan en son sayı ilk önce geri alınır. Bizim komutlar ilk çalışmaya başladığında önce $3000'den itibaren ilk 8 byte'ı okuyup yığına atmaktadır. Böylece yığına en son $3007 adresindeki değer atılmış olmaktadır. Yığından geri alma işlemi sırasında ise ilk önce $3007 adresinin değeri alınmaktadır. Bu işlemi 8 defa tekrarladığımızda ise bir karakterin datalarını kendi içinde tersten yerleştirmiş oluyoruz. Aşağıdaki tablo daha açıklayıcı olacaktır.

$3000 --> yığın --> $3007 
$3001 --> yığın --> $3006 
$3002 --> yığın --> $3005 
$3003 --> yığın --> $3004 
$3004 --> yığın --> $3003 
$3005 --> yığın --> $3002 
$3006 --> yığın --> $3001 
$3007 --> yığın --> $3000 
lda 
$fb 
;Karakter setinin LO adresini al 
clc 
;Elde bitini sfırla 
adc 
#$08  
;8 ile topla 
sta 
$fb 
;LO adrese geri yaz. 
bcc 
next_char 
;Toplama sonucu "elde" biti "0" ise git 
inc 
$fc 
;Karakter setinin HI adresini 1 arttır 
next_char 
lda 
$fc 
;HI adresi al 
cmp 
#$40  
;#$40 oldumu? Olmadıysa bir sonraki 
bne 
loop2  
;karakter için işlemleri tekrarla 
rts 
;Olduysa programı bitir. 
.end 
Gördüğünüz gibi kısacık bir programla $3000-$4000 arasındaki karakter 
setimizi baş aşağı çevirmiş olduk. Programın listesini “program dökümleri” 
sayfasında bulabilirsiniz. Ekran görüntülerimiz ise aşağıdadır.

Normal karakter setli ekran görüntüsü Ters karakter setli ekran görüntüsü. Bir başka karakter setinde görüşmek dileğiyle.