Anket

Anlatım tarzını ve detay düzeyini nasıl buluyorsunuz?

Bana ne? Ben okumuyorum ki bunları, durumum yok.
0 (0%)
Gereksiz detaya giriyorsun, uyuyoruz. Azıcık "high-level" geç.
0 (0%)
Daha da detay ver, anlamıyoruz. Belki de sen anlatamıyorsundur?
0 (0%)
Anlatım daha ilgi çekici olabilir. Nasıl mı? Bana sorma.
0 (0%)
İlgiyle takip ediyorum, böyle iyi. Bring it on!
10 (100%)

Toplam Oy Verenler: 10

Gönderen Konu: codewarrior'ın Amiga Assembler Güncesi  (Okunma sayısı 2789 defa)

0 Üye ve 1 Ziyaretçi konuyu incelemekte.

Çevrimdışı codewarrior

  • RAAT
  • Retroman
  • *
  • İleti: 30
codewarrior'ın Amiga Assembler Güncesi
« : 15 Şubat 2020, 22:24:48 »
Merhaba arkadaşlar,

Amiga assembler üzerindeki içsel yolculuğum devam ediyor. Bana entresan gelen noktaları, düşüncelerimi, bir takım code snippetlerini, çabalarımdan örnek videoları vs, izin verirseniz bu başlık altında paylaşmak istiyorum. Hem benim için geri dönüp bakabileceğim bir günce, hem de ilgi duyan ve yeni başlayan arkadaşlar için ufak tefek fikirler ve saç baş yolduran problemlere çabuk çözümler bulabilecekleri bir yer haline gelebilir (gelemeyebilir de). Burada paylaşacaklarımın internet üzerinde kolay bir arama ile direk bulunamayacak ve kendi çabalarımla bir sonuca eriştirdiğim şeyler olması konusuna dikkat edeceğim. Tabii bana harika gelen bazı çözümler, konunun uzmanı arkadaşlarımıza bir şaka gibi gelebilir. Onların yorumları bence hepimiz için ayrıca değerli olacaktır.



Müsaadenizle başlayayım:

Bir süredir Scoopex'den Photon'un Amiga Hardware Programming adlı video tutorial'ını takip ediyorum. Daha önceki başka bir başlıkta söylediklerimi tekrar edeyim: Photon'un epey psychedelic bir anlatım tarzı var. 20 dakika boş konuşup sonra 10 saniyede okyanusun dibine götürüyor getiriyor sizi. Ağır kuzey ülkeleri aksanlı bir İngilizce de beni benden alıyor. Açıkcası geri ala ala seyredilmesi taraftarıyım. Dalgınlıkla minik bir kısmı kaçırıp 'yav bu abi ne diyor?' noktasına çok hızlı gelebiliyorsunuz. Yine de bitmiş bir tutorial olduğu, protracker, deluxe paint, IFF Converter, Player61 gibi toolları da detaylı anlattığı için çok tavsiye ediyorum.

Bahsettiğim bu tutorialın başlangıç kısımlarında bir rasterline'ı, copper kullanmadan ekranın tepesinden aşağıya doğru kaydırma diye nispeten kolay bir kısmı anlatığı birkaç video var. Burada tepeden başlayıp ortayı biraz geçen ve ekranın en altına inmeden geri döndürdüğü bir örnek kod yazdırıyor ve konuyu geçiyor. Ben de büyük bir hevesle durumdan vazife çıkarıp rasterline'ı en alt satıra kadar indirip öyle çıkartmak gibi bir homework edindim kendime. Yaptım da hiç sorun olmadı. 1 pixel kalınlığında bir line en tepeden en aşağı kadar kayıyor, çarpıp geri dönüyor ve mouse'un sol tuşu ile de çıkabiliyorsunuz. Dikkat: Copper aktif ediliyor ama hiç kullanılmıyor burada. Aşağıdaki video'da görebilirsiniz:

Not a valid vimeo URL
Bu noktada source kodum şu şekilde: Link.


Tutorial ilerlemeye devam etti ve bu rasterline'ı hem copper kullanarak yapacağız ve hem de aynı anda kalınlaştıracağız şimdi. Yani üstteki örnek 1 pixel kalınlığında iken mesela 10 pixele çıkartacağız. Ne kadar kolay değil mi? Değilmiş... Photon, rasterline'ı alt tarafa kadar indirmediği için hemen kalınlaştırmayı yapıp geçti gitti ama aynı şevkle girişen ben aşağıdaki video'daki durum ile karşılaştım. Aşağıya yakın bir yerlerle rasterline'ın nasıl bozulduğuna dikkat edin lütfen.

Not a valid vimeo URL
Bu noktada source kodum şu şekilde: Link.


Tabi tutorial kalınlığı renklendirerek devam etti. Ben hala problemimin sebebini tam anlayamadığım için aynı şekilde bug'lı olarak ilerledim. Renklendirilmiş halde sorun daha da bariz görünüyor:

Not a valid vimeo URL
Bu noktada source kodum şu şekilde: Link.



Sorunu sizler de gördüğünüze göre gelelim bunun sebebine ve çözümüne.

Raster için ekran en üst satır $02c ve en alt satır $12c ile ifade ediliyor. Dikkat ederseniz en alt satır numarasının büyüklüğü yüzünden bu değeri bir word içinde saklamamız ve kontrol etmemiz lazım. Eğer olur da bir byte içerisinde tutmak hatasına düşersek ekran line numarası $02c ile başlayıp birer birer artarak önce $02d, sonra $02e... vs şekilde $12c olana kadar artarak giderken $0ff'den geçecek ve byte ile tuttuğumuzdan $00'dan sonra başa dönerek ölümcül bir hata yapmış olacağız. O yüzden çizeceğimiz rasterline'ın numarasını (veya kalınlığa göre bir numara aralığını) word olarak tutmak zorundayız. Aslında karşılaştığım sorunun ana sebebi de bu. Ama ben word yerine byte kullanmak gibi bir hata yapmadım. İlginç ama Copper bu iş için byte kullanacak şekilde dizayn edilmiş ve word kullanamıyor!!.

Bu işi bilenler çoktan anladılar durumu ama benim gibi newbie'ler için biraz daha açıklamaya çalışayım. Copper kullanırken siyah arka ve beyaz rasterline'ı yukarıdan aşağıya kaydırmak için basitçe şu aşağıdaki işlemleri yapıyorsunuz.  İyice karışmasın diye geri dönüş kısmını eklemedim buraya ama eminim tahmin edebilirsiniz nasıl olacağını..

  • raster için en üst ekran pozisyonuna ($02c) kadar bekleme koy
  • background rengini siyaha değiştir
  • y = $02c
  • çizime başlamak için raster'a başlangıç ekran pozisyonuna (y dedik buna) kadar bekleme koy
  • background rengini beyaza değiştir
  • rasterline için bitiş ekran pozisyonuna (y+kalınlık diyelim) kadar bekleme koy
  • background rengini siyaha değiştir
  • y++ ve go to 4

Copper'ın emirleri bir longword (yani double-word) şeklinde bir listeye yazılıyor ve adına geleneksel şekilde CopperList deniyor. Aşağıda iki satırlık bir copperlist var, açık olsun diye her longword satırını iki word şeklinde yazdım ve tüm byte'ları açık açık gösterdim:

Kod: [Seç]
dc.w $2c07,$fffe
dc.w $0180,$0000
dc.w $ffff,$fffe

Son satır copperlist için 'end' komutu. İlk satırdaki $fffe bir önceki word'de tanımlanan satır ve kolon'a kadar raster beklemesi ayarlar. İkinci satırda $180 background rengini ikinci word'deki değere ($0RGB) set ediyor yani siyah. Bizi ilgilendiren birinci satırdaki ilk word. Dikkat ederseniz satır (2c) ve kolon (07) byte değerler şeklinde verilmiş. Copper sadece bu şekilde çalışıyor yani sorunumuzdaki $ff numaralı satırı geçerken $00'a döneceğiz ve aslında $100'de olmamız gerekirken raster bekleme noktamızda problem yaratacak. Copper dizaynının buna çözümü şöyle:

Kod: [Seç]
dc.w $2c07,$fffe
dc.w $180,0
dc.w $ffdf,$fffe
dc.w $1007,$fffe
dc.w $180,$fff
dc.w $1107,$fffe
dc.w $180,0
dc.w $ffff,$fffe

Yani, $ff numaralı satırı geçeceksek bunu copper'a bir uyarı ile belirtmemiz gerekiyor. 3.satır bu uyarı için (dc.w $ffdf,$fffe). Yani $ff nolu satırın $df nolu kolonu için bir bekleme set ediyoruz. Bundan sonra gelecek $ff'den daha düşük her satır numarasını copper $100 sayısının üstüne ekleyerek işleme alacaktır. Sorun çözüldü, değil mi? Değil ne yazık ki..

Statik bir rasterline yapacaksak, yani ekranda kaymayacak ve sadece duracaksa sorun çözüldü. Veya 1-pixel bir line kaydıracaksak yine sorunu çözdük. Ama kalın bir line kaydıracaksak $ff nolu satır için dinamik rutinler kullanmaktan başka bir şansımız kalmıyor. Yani copperlist'i programımız run ederken on-the-fly değiştirmeliyiz. Öyle ki kalın line'ımız $ff nolu satıra yaklaşırken, içinden geçerken, ve sonrasında olmak üzere bu durumları ayrı ayrı ele almak zorundayız. Ya, bu kadar basit bir örnek için nedir bu çektiğimiz, yapılır mı bu arkadaş dediğinizi duyar gibiyim: Amiga yazılımcılığına hoşgeldiniz! :)

Final çözümüm şu şekilde:

Tek renk kalın line için copperlistimizi şu hale getiriyoruz:
Kod: [Seç]
copper:
dc CPRFETCHMODE,0         ; slow fetch node, AGA compatibility
dc.w CPRBITPLANECNTL,$0200 ; disable bitplanes

dc.w CPRRASTERLINECLR,$222
dc.l $2f07fffe
dc.w CPRRASTERLINECLR,$000

start:
dcb.l 8
end:
dcb.l 8

dc.l $2b07fffe
dc.w CPRRASTERLINECLR,$222
dc.l $fffffffe


Start ve End etiketlerinin hemen sonralarına dikkat edin lütfen. Bomboş bir alan var orada, toplam 16 longword'lük. Orayı dinamik dolduracağız ve her bir programın ana döngüsünde copperlistin o kısmını tekrar yazacağız. Bu dinamik yazılımı yapan tek renk için kod şu şekilde:

Kod: [Seç]
.b:
moveq #8-1,d1
move.l #start,a0
move.l #end,a1
.b1:
move #$01fe,(a0)+
move #$0000,(a0)+
move #$01fe,(a1)+
move #$0000,(a1)+
DBF d1,.b1

move d7,d1
add #BARTHICKNESS,d1
cmp #$ff,d1
blo .c
bhi .d
.c: ; 1st section
move.l #start,a0
move.b d7,(a0)+
move.b #$07,(a0)+
move #$fffe,(a0)+ ; end 1st word
move #CPRRASTERLINECLR,(a0)+
move #$0fff,(a0)+ ; end 2nd word

move.l #end,a0
add #BARTHICKNESS,d7
move.b d7,(a0)+
sub #BARTHICKNESS,d7
move.b #$07,(a0)+
move #$fffe,(a0)+ ; end 1st word
move #CPRRASTERLINECLR,(a0)+
move #$0000,(a0)+ ; end 2nd word
move #$ffdf,(a0)+
move #$fffe,(a0)+ ; end 3rd word
jmp .f

.d:
cmp #$ff,d7
bhi .e ; 2nd section
beq .d1

move.l #start,a0
move.b d7,(a0)+
move.b #$07,(a0)+
move #$fffe,(a0)+ ; end 1st word
move #CPRRASTERLINECLR,(a0)+
move #$0fff,(a0)+ ; end 2nd word
move #$ffdf,(a0)+
move #$fffe,(a0)+ ; end 3rd word

move.l #end,a0
add #BARTHICKNESS,d7
move.b d7,(a0)+
sub #BARTHICKNESS,d7
move.b #$07,(a0)+
move #$fffe,(a0)+ ; end 1st word
move #CPRRASTERLINECLR,(a0)+
move #$0000,(a0)+ ; end 2nd word
jmp .f

.d1:
move.l #start,a0
move.b d7,(a0)+
move.b #$07,(a0)+
move #$fffe,(a0)+ ; end 1st word
move #CPRRASTERLINECLR,(a0)+
move #$0fff,(a0)+ ; end 2nd word
move #$ffdf,(a0)+
move #$fffe,(a0)+ ; end 3rd word

move.l #end,a0
add #BARTHICKNESS,d7
move.b d7,(a0)+
sub #BARTHICKNESS,d7
move.b #$07,(a0)+
move #$fffe,(a0)+ ; end 1st word
move #CPRRASTERLINECLR,(a0)+
move #$0000,(a0)+ ; end 2nd word
jmp .f

.e: ; 3rd section
move.l #start,a0
move #$ffdf,(a0)+
move #$fffe,(a0)+ ; end 1st word
move.b d7,(a0)+
move.b #$07,(a0)+
move #$fffe,(a0)+ ; end 2nd word
move #CPRRASTERLINECLR,(a0)+
move #$0fff,(a0)+ ; end 3rd word

move.l #end,a0
add #BARTHICKNESS,d7
move.b d7,(a0)+
sub #BARTHICKNESS,d7
move.b #$07,(a0)+
move #$fffe,(a0)+ ; end 1st word
move #CPRRASTERLINECLR,(a0)+
move #$0000,(a0)+ ; end 2nd word



Programımız kalın veya ince için artık düzgün çalışıyor:

Not a valid vimeo URL
Bu noktada source kodum şu şekilde: Link.



Alacalı rasterline için gereken değişiklikleri yapmak kolay bundan sonra. Asıl göstermek istediğim kısmı geçtiğimiz için artık detaya girmeme gerek yok ama sizin için son kodu aşağıya ekiyorum.

Not a valid vimeo URL
Bu noktada source kodum şu şekilde: Link.


Umarım açıklayıcı olabilmişimdir. Buralara kadar okuduysanız teşekkür ederim. Selamlar sevgiler.


Çevrimdışı 68k

  • Tedavideki Retromanik
  • ****
  • İleti: 269
Ynt: codewarrior'ın Amiga Assembler Güncesi
« Yanıtla #1 : 16 Şubat 2020, 00:21:55 »
süper, teşekkürler.

Çevrimdışı Alco

  • Yönetici
  • Özgür Retrocu
  • *
  • İleti: 2227
  • "Kahraman olmak, dürüst olmaktan kolaydır" Luigi P
    • Sizin Amstrad
Ynt: codewarrior'ın Amiga Assembler Güncesi
« Yanıtla #2 : 16 Şubat 2020, 13:08:19 »
@codewarrior Harika bir fikir olmuş bu günce işi. Ellerine sağlık! Yazdıkların da detaylı ama daha da detaylı ve hatta temel bilgileri de içermesinde hiçbir sıkıntı yok bence. Seni yormayacak ve yazmaktan bezdirmeyecek kadar detaya girmen güzel olur. Bugün biz okuruz yarın başkası. Ama sonuçta herkesin seviyesi ve beklentisi farklı :)

Ben hoşgörüne sığınarak hemen bir talep dile getireyim. Nasıl bir altyapı kullanıyorsun? Setup'ın nasıl? Crossdev mi yoksa gerçek donanım mı ya da her ikisi birden mi? Peki ya editör/ass olarak ne kullanıyorsun? Bu konulardaki tercihlerini gerekçeleriyle duymak isterim.

Belki "Amiga Assembler 101" beklemek sana getireceği zahmet açısından haksızlık olur ama biz çaktırmadan seni ona yönlendirmiş olalım. Bu vaka analizi metoduyla da ortaya enfes bir çalışma çıkacağını düşünüyorum.  :)

Bu arada, farketmedik sanma sakın. Ortama sessizce girdin ve çaktırmadan fırtına gibi esiyorsun. Harikasın!

Çevrimdışı codewarrior

  • RAAT
  • Retroman
  • *
  • İleti: 30
Ynt: codewarrior'ın Amiga Assembler Güncesi
« Yanıtla #3 : 17 Şubat 2020, 16:54:24 »
Harikasın!

Asıl sizler harikasınız @Alcofribas .

Nazik sözlerin için çok teşekkür ederim. Detaya da gireriz, hiç yormaz valla. Sevilen bir konuya harcanan emek hiç yorucu olmuyor. Önce hemen setup'ımı ve nasıl kurulabileceğini yazayım. İlerleyen zamanlarda ve daha sonraki girdilerde örnek üzerinden satır satır da geçer, asm komutlarına, hw registerlarına, copper, blitter, sprite komutlarına vs de bakarız. Tabii ki bu nadide toplulukta bunları benden kat kat iyi bilenler vardır mutlaka. Onların katkısı çok daha değerli, ama ben de siz istediğiniz sürece ve zaman bulabildiğim sürece yazarım tabii. Tekrar etmeliyim, başta bahsettiğim Photon'un tutorial'ının sonlarına doğru geliyorum artık. Eğer bu güncede o tutorial'dan sıkıştırılmış bir bilgi toparlağı çıkarabilirsem sevineceğim. Çünkü epey dağınık anlatıyor. Bu günce hiçbir işe yaramazsa en azından bu işe yarar belki -- yine de bu işe ilgisi olan arkadaşlara gözü kapalı tavsiye ediyorum Photon'un tutorial'ını.





Amiga assembler'a hızlı girebilmek ve verdiğim örnekleri derleyip çalıştırmak için en 'basic' setup'ım aşağıdaki gibi.
 
Not: Mac OS kullanıyorum, Windows'ta çok farklı değildir diye ümitliyim. 'Neden WinUAE değil?' diyen arkadaşlar, Mac'de WinUAE yok - keşke olsaydı ama adı üstünde WINuae :(.

  • FS-UAE (FS-UAE Launcher.app & FS-UAE Arcade.app) indirelim: Link
  • Kickstart v1.3 indirelim: <Burada bunu veremem biliyorsunuz. Ama eminim bu sizi durduramaz.>
  • FS-UAE Launcher'ı kuruyoruz. Paketin içinden FS-UAE Arcade de çıkıyor, bunu kurmaya gerek yok.
  • FS-UAE Launcher'ı çalıştırıyoruz. Sol üstteki menü ikonundan 'Import Kickstart'ı seçiyoruz ve download ettiğimiz Kickstart dosyasının içinde bulunduğu folder'ı gösteriyoruz. Bu aşamada birden fazla Kickstart'ı aynı dizin içine koyup tek seferde import edebiliriz.

  • Üst orta kısımdan 4.ikonu seçiyoruz (Hard Drives). Orada ilk kutunun sağındaki ilk ikonu tıklayıp bir dizini hard disk olarak gösteriyoruz. Bu dizinin içine tüm sourcelarımızı ve toollarımızı direk koyacağız. Size örnek olsun diye 'work' dizinimi zipleyerek ekliyorum bu girdiye, direk onu kullanabilirsiniz. İçinde AsmTwo ve önceki örneklerin source'ları var. Aslında bir yerden sonra dizinleri düzenlemeye başlıyorsunuz, yeni hard disk dizinleri ekliyorsunuz ama hızlı başlamak için bir dizin yeterli.

  • Configs and Games yazan kısmın altındaki kutucuğa konfigurasyonunuz için bir isim yazın ve sağındaki buton ile kaydedin.

  • Emulator kurulumu bu kadar. Start'a basın ve başlayın. CLI'de 'work:asmtwo' yazarsanız derleyiciniz çalışacak. Dikkat buradaki 'work', PC'deki dizininizin ismi. AsmTwo uygulaması da bu dizinin içinde olacak zaten.

  • AsmTwo çalıştıktan sonra ilk soruya 'c' (yani chipmem), ikinciye de 200 (yani 200KB lik bir alanda çalışsın AsmTwo) diyoruz.

  • 'Ready' ve cursor'u gördükten sonra 'r' (yani bir source dosyası yükle) diyeceğiz ve bir hata mesajı alacağız 'Req.Library not found !!!'. Bunu önemsemeyin. 'FILENAME>' sorusuna source'unuzun ismi neyse onu giriyorsunuz, mesela 'rasterline.S'. Dizini girmenize gerek yok zaten AsmTwo 'work' içinde çalışıyor ve source da orada. Source dosyasının byte olarak uzunluğunu söyleyecek size. Tekrar gelen cursorda 'a' diyoruz (yani assemble). İki pass atacak, hata yoksa gelen cursorda 'j' diyelim (yani jump) ve çalıştıralım.

  • Çalıştı sanırım, umarım..
  • 'rasterline.S' örneğini kullandıysanız, sol mouse tuşu ile kodunuzu durdurup assembler'a dönebilirsiniz. Döndükten sonra (veya en başta isterseniz) ESC'ye basarak source'unuzu editleyebilirsiniz ve tekrar ESC ile cursor'a dönebilirsiniz. Ama Amiga üzerinde source-editing bir işkence tabii. Hard diskinizden bir dizini gösterdiniz ve source dosyanız da orada, unutmayın. Sourcelarınızı direk en sevdiğiniz editor neyse onunla kullandığınız işletim sistemi üzerinden editleyin ve mutlu olun.

Bu kadar..
Kolay, değil mi?


AsmTwo aslında yine Photon tarafından AsmOne'dan forklanmış bir version. Bence varolan diğer AsmOne ve AsmPro versiyonlarının hepsinden çok daha iyi çalışıyor. Tabi orjinal AsmOne'ın kullanım klavuzu var sadece: Link. Vaktiniz olursa mutlaka okumanızı tavsiye ederim. Çok çabuk okunuyor zaten.

Benim hali-hazırda kullandığım ortam burada anlattığıma çok yakın. Bence böyle epey rahat çalışılıyor. Açıkcası tam anlattığım minimalistlikte başladım. Sonrasında sayısız save-state ve ClassicWB'nin System.HDF'i ile devam ettim. Zaten ilerledikçe siz de buna benzer şekilde değişeceksiniz ama başlamak için yukardaki basit adımları izlemek gayet yeterli.

Bir deneyin, seveceksiniz ;) .

Sevgiler, selamlar.

Çevrimdışı Ref

  • Yönetici
  • Özgür Retrocu
  • *
  • İleti: 2958
  • Advanced User Simulator
    • ae unutmadan
Ynt: codewarrior'ın Amiga Assembler Güncesi
« Yanıtla #4 : 18 Şubat 2020, 10:52:21 »
@codewarrior , işin doğrusu bu başlığa böyle kısacık bir yorum yapıp bırakmıyım diye günlerdir bir mesaj kürate ediyorum :D Yaz sil, oku yorumla falan derken en sonunda böyle olmayacak, codewarrior deneyimi yaşamalıyım diye senin ayak izlerini takip etmeye karar verdim fakat hayatın akışı engel olup duruyor bu uzunlukta bir çalışmaya ve yarım kalıyor.

Bu mesajda sadece heyacanla takip ettiğimi ve bu mesajın forumdaki en dolu içeriklerden biri olduğunu söylemek istedim. İleride daha kapsamlı bir mesaj gelmesini ümit ediyorum :D

Çevrimdışı doMiNO

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 210
Ynt: codewarrior'ın Amiga Assembler Güncesi
« Yanıtla #5 : 18 Şubat 2020, 19:02:04 »
@codewarrior , başlattığın günce Amiga assembler'a başlamak isteyenler için yol gösterici olacak, harika bir kaynak niteliğinde. Ben de zevkle takip ediyorum.

Çevrimdışı codewarrior

  • RAAT
  • Retroman
  • *
  • İleti: 30
Ynt: codewarrior'ın Amiga Assembler Güncesi
« Yanıtla #6 : 18 Şubat 2020, 23:30:01 »
Merhaba,

@Ref teşekkür ederim. Her ne kadar kendim bir öğrenci olsam da, en azından öğrendiğim kadarını anlatabilirim diye ümit ediyorum. Olabildiğince basitleştirerek anlatmaya çalışacağım. Bir kısmı iyice anlamadan ilerlememeye çalışıyorum ki dönüp baktığımda çabucak unutmuş olmayayım. O yüzden bazı yerlerde epey takılabiliyorum. Yukarıda bir örneğini gördünüz zaten. Ama bence böylesi güzel, sindire sindire gitmek yani. Acelemiz yok zaten, değil mi?

@doMiNO belki de hepimizden uzun süre Amiga kullanmaya devam etmiş senin gibi değerli bir kişilikten bunu duymak harika. Teşekkür ederim, devam etmem için bana güç verdin. Sağol. Daha önce de söylediğim gibi aslında anlattığım kısımlardan epey ilerdeyim, dolayısı ile başlarda çabuk çabuk yazabilirim (tabii hayat ne kadar izin verirse), ama sonlara geldikçe işler epey zorlaşıyor ve yavaşlayacağım kesin. Neyse o zamana kadar daha vakit var ;)



O zaman hazırsak ve madem daha fazla detay da istiyorsak, güncenin bugünkü kısmında biraz geri sararak başlıyorum. Konumuz Amiga Assembler komutlarına ve register'lara ufaktan bir giriş. Bence en kolayı bir örnek üzerinde ilerleyerek öğrenmek. Hadi, ilk mesajımda gösterdiğim tek piksellik kayan rasterline'ı, kaynak kodu satır satır inceleyerek beraber yapalım. Bu hızlı ama anlaşılır bir giriş olacak diye düşünüyorum.

Amacımız siyah ekrana beyaz bir çizgi çekmek. Dikkat, çizgimiz bu örnekte hareket etmeyecek. Başlangıç kodumuz aşağıdaki gibi. Commentleri alışkanlıkla İngilizce yazdım ama eğer anlaşılmıyor derseniz Türkçeleştiririm tabii. Kod ekte.
Alıntı
start:
   CIAAPRA=   $bfe001                  Input/Output for pin 6 (port 1 & 2 fire buttons) http://amiga-dev.wikidot.com/information:hardware#toc3
   VHPOSR=      $dff006                  Read raster XY position   http://amiga-dev.wikidot.com/hardware:vhposr
   COLOR00=   $dff180                  Palette color 0 http://amiga-dev.wikidot.com/hardware:colorx
   RASTERSTART=$ff                   $02c is the top of the screen
init:
   move #RASTERSTART,d7               d7 initialized to $0ff
mainloop:
   btst #0,VHPOSR-1                  test if raster high byte is 0
   bne mainloop                      if not loop again to wait
   cmp.b #$2c,VHPOSR                   test if raster low byte is $2c (raster at top?)
   bne mainloop                     if not loop again to wait
   move.w #$000,COLOR00               move color black to COLOR00(background palette)

waitraster1:
   cmp.b VHPOSR,d7                     raster on our desired position?
   bne waitraster1                     if not loop again to wait
   move.w #$fff,COLOR00               move color white to COLOR00(background palette) we are drawing the line
waitraster2:
   cmp.b VHPOSR,d7                     raster on our desired position? this second check ensures we are at the edge of just leaving our beloved position
   beq waitraster2                     if not loop again to wait
   move.w #$000,COLOR00               move color black to COLOR00(background palette) we are done drawing

   btst #6,CIAAPRA                     is left mouse button clicked?
   bne  mainloop                     if not start over running the main loop
exit:
   rts                            return to AmigaOS (did we forget something? I think so)


Satır satır inceleyelim bu kodu.

İlk satırda 'start:' var. İki nokta üst üste ile biten ve sola yanaşık herhangi bir string'i derleyici bir 'label (etiket)' olarak kabul eder. Hatta iki nokta üst üste koymasanız bile sola tam yanaştırırsanız aynı anlamda kabul edilir. Uygulama assemble edildiğinde yani çalıştırılmak üzere makina koduna çevrildiğinde, bu label'dan sonra ilk gelecek byte'ın adresi bu label'a atanır. Yani bu kodu AsmTwo içinde cursor'da 'a' yazıp assemble ettikten sonra, yine cursor'da '=S' derseniz label'lar ve karşılık gelen adresleri görebilirsiniz. 'start'ın karşısında yazan değer 0 olacaktır çünkü bu minik program 'relocatable' ve başlangıç adresi assembler tarafından otomatik belirlenecek ve o adres değeri artı sıfır 'start' etiketinin gösterdiği yer olacaktır. Bunu daha iyi görebilmek için cursor'da bir hex dump alabilirsiniz: h.l start yazın. Uygulamalar relocatable veya absolute olarak derlenebilir ve bu kod içinden ayarlanabilir. Bu konuda hiçbirşey söylemediğimiz için asmtwo otomatik olarak relocatable kod üretti ve bir yerlere yerleştirdi. Bu konuya önümüzdeki günlerde tekrar döneceğiz.

Şükür ikinci satırdayız: 'CIAAPRA=$bfe001' diyor. Burada bir register adresini bir constant'a atama yapıyoruz. Bahsettiğimiz adres '$bfe001' ve her iki joystick portunun fire butonunu (pin 6) kontrol eden register bu. Bunu kendi seçtiğimiz bir sabite (CIAAPRA) atıyoruz ki bu anlamsız numarayı hatırlamak zorunda kalmayalım. Uygulamamızda bunu sol mouse tuşunun basılıp basılmadığını anlamak için kullanacağız. Bu arada asmtwo kendisi için anlamlı olan bir statement'ı parse ettikten sonra bir boşluk bırakıp yazdığınız herşeyi comment kabul ediyor. Yani noktalı virgül vs yazmanıza gerek yok. Harika değil mi?

Üçüncü satır: 'VHPOSR=$dff006'. Başka bir register adresi ama mantık ikinci satırla aynı. Bu sefer raster'ın ekranda o andaki X ve Y pozisyonlarını okumak için kullanacağız bu adresi (daha doğrusu atadığımız constant'ı).

Dördüncü satır: 'COLOR00=$dff180'. Başka bir register adresi daha. Arkaplan rengini ayarlamak için kullanılan register bu. Sabitimizi atadık geçtik.

Beşinci satır:  'RASTERSTART=$ff'. Bu resmen kendimize ait bir sabit ataması. Ekranın nedense en üst satırı $02c, en alt satırı da $12c ile gösteriliyor. Bunları birbirinden çıkartırsanız $100 yani 256 piksel sayısını bulursunuz. Biz istiyoruz ki 1 piksellik beyaz çizgimiz tam olarak şu sorunlu $0ff satırında çıksın. $02c'yi bundan çıkartarak kaçıncı satırdan bahsettiğimizi bulabilirsiniz. Açıkcası hiç merak etmedim :)

Altıncı satır: 'init:'. Başka bir label. Artık biliyoruz bunları di mi?

Yedinci satır: 'move #RASTERSTART,d7'. İşte ilk gerçek assembler komutumuz: 'move'. Burada biraz durmamız gerekecek. Bu komut soldaki değeri, sağdaki değişken içine atar. Solda, burada olduğu gibi sabit bir değer veya bir register veya bir hafıza bölgesi olabilir. Eğer buradaki gibi bir sabit değer (RASTERSTART $0ff değerini taşıyan bir sabitten başka birşey değil) kullanacaksak o zaman başına bunun bir sabit değer olduğunu belirtmek için '#' koymak zorundayız. İnanmayacaksınız belki ama burada bunu koymazsak, bu program hala assemble oluyor ama tabii ki direk crash ediyor. Bir düşünün acaba neden olabilir?... Neyse şimdiden sıkmayayım sizi, eğer '#' koymazsak asmtwo RASTERSTART'ın içindeki değeri bir adres olarak kullanıp o adresteki değeri sağdaki registere atacak ve çıtonk :). Bu arada sağdaki değişken bir register (d7). Amiga'nın 7. data registeri. Toplamda 8 data registeri var ve bunların her biri longword (double word)lük registerlar. Dolayısı ile 'move' kullanırken dikkatli olmamız gerekiyor. 'move' komutunu 'move.b' şeklinde yazarsak soldaki değerin en düşük byte'ını sağdaki değişkenin en düşük byte'ına taşır. 'move.w' en düşük word'ü aynı şekilde taşır. 'move.l' ise bire bir kopyalar. Aman dikkat soldaki değer longword değilse ve longword taşıma yaparsanız Allah bilir ne taşıyacak. Aynı şey word taşıma için de geçerli. Anladınız sanırım durumu - Welcome to 32-bit computing :P. Peki birader, o kadar şey söyledin ama sen 'move' yazmışın direk, ne '.b' var, ne '.l' ne bişey diyeceksiniz. 'move' = 'move.w' oluyor. Süper kolaylık, değil mi? Aslında değil. Neyse buna da geliriz.

Sekizinci satır: 'mainloop:'. Başka bir label. Sıkıcı mı artık?

Dokuzuncu satır: 'btst #0,VHPOSR-1'. Hatırlarsanız VHPOSR raster pozisyonu idi. Bunun üst byte'ının 0. bitini 0 mı diye test ediyoruz. 'btst' bit-by-bit karşılaştırma yapar. Soldaki değer karşılaştırılacak bit numarası ki burada sabit 0 verilmiş yani 0.bit. Sağdaki ise karşılaştırmanın yapılacağı byte'ın adresi. Bu komut her zaman ilgili bitin 0 olup olmadığına bakar. Yani 'btst #6,VHPOSR-1' yazsaydık, 6. bitin 0 olup olmadığını test ediyor olacaktık. Bu testin sonucu sonraki satırda kontrol edilir.

Onuncu satır: 'bne mainloop'. 'bne' yani kısaca 'Branch if not Equal'. Neye eşit olup olmadığı peki? Sıfıra tabii ki. Yani bir önceki test sıfıra eşit çıkmadıysa ilgili label'a atla diyor.

Onbirinci satır: 'cmp.b #$2c,VHPOSR'. Buraya geldik demek ki bir önceki satır çalışmadı yani bit 0 çıktı. O zaman hadi bir de raster pozisyonunun alt byte'ını '$2c' ile karşılaştıralım. Dikkat 'cmp' yani 'Compare' adı üstünde karşılaştırma yapar ama bit bazında değil. Komutun sonunda '.b' var, demek ki ne bu? Evet bildiğiniz byte'ı olduğu gibi karşılaştıracak. Bir önceki 0. bit karşılaştırması ve bu tüm byte karşılaştırmasını bireştirirsek ne yaptık burada? Raster pozisyonu $02c mi diye baktık ve $02c olana kadar bekledik. Yani raster ekranın en başına çıkmadan uygulamamızda birşey yapmak istemiyoruz ve bekledik. Oraya çıktı. Sonraki satırda bunu kontrol ettik ve 13.satıra geçtik.

Onikinci satır: 'bne mainloop'. Bir yerlerde görmüştük sanki bunu.

Onüçüncü satır: 'move.w #$000,COLOR00'. Artık biliyoruz bunları. Word taşıyan bir komut, nereye COLOR00 diye bir sabitin gösterdiği bir adrese. COLOR00 background rengini tutan registerin adresini taşıyor. '#$000' yani siyah değerini gönderiyoruz. Peki ama bunu '#0' diye yazamaz mıydık? Yazardık tabii, burada sadece bunun '#$RGB' olduğunu vurgulamak istediğim için böyle yazdım. Burayı istediğiniz gibi değiştirip istediğiniz background rengini RGB olarak ayarlayabilirsiniz. Buradan itibaren raster aşağıya doğru indikçe biz müdahale etmediğimiz sürece her satırı siyaha boyayacak.

Bir boş satır geçtik. Onbeşinci satır: 'waitraster1:'. Hmmm, evet.

Onaltıncı satır: 'cmp.b VHPOSR,d7'. Raster'ın pozisyonu d7 registerindeki değerde mi (yani bizim istediğimiz yerde yani $ff'de mi) diye kontrol ediyoruz. Hani d7 register'ına $ff koymuştuk ya, hatırladınız mı? Sadece alt byte'ı kontrol etmemiz yeterli. Line'ı bu örnekte aşağı kaydırıyor olmayacağız ama kaydırsaydık üst byte'ı kontrol etmememiz bir problem yaratır mıydı? Bunu bir düşünebilirsiniz...

Onyedinci satır: 'bne waitraster1'. Henüz $ff'e gelmedi galiba. Bir çay içip gelelim.

On sekizinci satır: 'move.w #$fff,COLOR00'. Bir üst satır çalışmadı. Demek ki muhitimize geldik. Çizgimizi çizmeye başlayalım. Beyaz rengi arkaplan rengine atıyoruz.

Ondokuzuncu satır: 'waitraster2:'. Bir label daha.

Yirminci satır: 'cmp.b VHPOSR,d7'. Bu ilginç. Tamamen aynı kontrolü birkez daha yapıyoruz. Eğer bu karşılaştırma eşitlik döndürürse muhitten çıkmak üzereyiz anlamına geliyor. Yani siyahla boyayacağımız tüm 1 piksellik satır boyanmış olacak.

Yirmibirinci satır: 'bne waitraster2'. Boyacı çalışıyor hala. Bir tur atıp gelelim.

Yirmiikinci satır: 'move.w #$000,COLOR00'. Bir üst satır çalışmadı. Demek ki istediğimiz satırın boyanması bitti. Tekrar arkaplanı siyaha alıyoruz. Bunu yapmazsak beyaza boyamaya devam eder diğer satırları da.

Yirmiüçüncü satır: 'btst #6,CIAAPRA'. CIAAPRA ismini verdiğimiz registerin 6.bitinin sıfır olup olmadığına bakıyoruz. Eğer olduysa kullanıcı mouse'un sol tuşunu kliklemiş demektir. Sıkıldı herhalde, çıkmamızı istiyor. Tabii bildiğiniz gibi asıl kontrolü sonraki satırda yapacağız.

Yirmidördüncü satır: 'bne  mainloop'. Mouse'un sol tuşuna basmadıysa tüm uygulama loop'unu birkez daha çalıştıralım.

Yirmibeşinci satır: 'exit:'. Demek ki bastı. Çıkıyoruz, haydi hayırlısı.

Son satır: 'rts'. Return to Subroutine. Yani bizi kim çağırdıysa ona dönüyoruz. Bizim durumumuzda AmigaOS'a kontrolü devrediyoruz. Sanki birşeyleri unuttuk ama bu sonranın konusu. Belki tahmin edersiniz, size güveniyorum ;)


Yükleyip çalıştırınca aşağıdaki sonuç çıkmalı. Pek beklediğiniz gibi olmamış olabilir. Çünkü birçok yapmamız gereken şeyi yapmadık (acaba neleri yapmadık da böyle oldu?).

'O kadar kastık, bu mu çıktı yani?' diyorsanız, valla haklısınız ama şanlı Amiga coding işi böyle. Yavaş yavaş ve acı dolu. :)

Not a valid vimeo URL
Devam edeceğiz...
İyi geceler, sevgiler.


Çevrimdışı Ref

  • Yönetici
  • Özgür Retrocu
  • *
  • İleti: 2958
  • Advanced User Simulator
    • ae unutmadan
Ynt: codewarrior'ın Amiga Assembler Güncesi
« Yanıtla #8 : 20 Şubat 2020, 09:34:54 »
Bu harika başlığa biraz daha gaz verelim o zaman  :)

https://medium.com/accelerated-intelligence/explanation-effect-why-you-should-always-teach-what-you-learn-9800983a0ea1


Bu süper doğru. Bir konuda ders vermeye başladıktan sonra o konudaki bilgim 50 kat falan artıyor. En önemlisi, tamamen cepte zannettiğiniz, kesin doğrular olarak kabul ettiğiniz bilgilerin aslında gerçek bir dayanağı olmadığını, bazen deneyimden edinilmiş bir tahmin, bazen ise salt yanlış bilgiler üzerine inşa edilmiş fikirler olduğunu farkediyor olmanız. Çok iyi bildiğimi düşündüğüm (ve her kesin benim çok iyi bildiğimi düşündüğü) tüm konuların, o konuda ders vermeye hazırlandığım/başladığım anda, siyah-beyaz'dan gri bir yelpazeye dönüştüğüne her seferinde şahit oldum.

Neyse, konuya dönersek, şimdi bu basit kod örneğinde dahi, İlker ve Emir'in Autistic tasarımında yaptıkları tasarım kararlarının benzerlerini okuma fırsatı bulmuş oldum. Elbette ikisi de bu işin kitabını yazmış adamlar olduğu için "ben giderken onlar dönüyordu" ama olsun, donanım seviyesinde kodlama yapmak bana o bilgisayarın temel kullanım amacını tekrar hatırlattı. @codewarrior 'un dediği gibi, amiga üzerinde artık birşey üretmek bize aşırı zor geliyor. Çok basit bir metin düzenleme işi büyük bir eziyete dönüşüyor. UAE ile düşük çözünürlük belasını aşsanız bile, bu sefer font sorunu devreye giriyor. Ya da kullanılan programın uae grafik kartını desteklememesi ortaya çıkıyor vb. Mecburen crossdev yapmak şart oluyor. Günümüz PC konforunda kodlama yapmak ama sonuçları limitli donanımda gözlemek istiyoruz. Autistic bunu başardığında üzerinde çalışması amiga'dan çok daha keyifli bir hobi aracı olacaktır.

Bu rehberi takiben Asmtwo ile denemelerim hızla sürmektedir.

Çevrimdışı codewarrior

  • RAAT
  • Retroman
  • *
  • İleti: 30
Ynt: codewarrior'ın Amiga Assembler Güncesi
« Yanıtla #9 : 20 Şubat 2020, 10:56:52 »
Bu harika başlığa biraz daha gaz verelim o zaman  :)

https://medium.com/accelerated-intelligence/explanation-effect-why-you-should-always-teach-what-you-learn-9800983a0ea1

@Alcofribas, 'Teaching is knowledge’s oxygen' -- ne kadar doğru bir cümle. Bütün bilgi açık, ortada ve free olmalı bence. Ve olabildiğince paylaşılması teşvik edilmeli. Yüzde yüz katılıyorum yazdıklarına. Sonlara doğru 'bir facebook grubu kurdum bugün, gelin katılın' demeseymiş daha iyi olurmuş, ama ilk kısım o kadar doğru ki birşey demeyelim hadi.

Bu süper doğru. Bir konuda ders vermeye başladıktan sonra o konudaki bilgim 50 kat falan artıyor. En önemlisi, tamamen cepte zannettiğiniz, kesin doğrular olarak kabul ettiğiniz bilgilerin aslında gerçek bir dayanağı olmadığını, bazen deneyimden edinilmiş bir tahmin, bazen ise salt yanlış bilgiler üzerine inşa edilmiş fikirler olduğunu farkediyor olmanız. Çok iyi bildiğimi düşündüğüm (ve her kesin benim çok iyi bildiğimi düşündüğü) tüm konuların, o konuda ders vermeye hazırlandığım/başladığım anda, siyah-beyaz'dan gri bir yelpazeye dönüştüğüne her seferinde şahit oldum.

@Ref, O kadar doğru birşey yazmışsın ki.. Alkışlıyorum.




Biraz vakit bulmuşken devam edelim isterseniz. En azından bu 'basit' örneğimizi tamamlamaya çalışalım. Hatırlarsanız amacımız, siyah ekrana 1 piksellik bir çizgi çekip onu ekranın en başından en sonuna kadar kaydırmak. Tepeye ve dibe vurduğunda 'bounce' edip geri dönecek. Son bıraktığımız yerde ekrana çizgiyi çekebilmiştik ama nedense mouse'u oynattıkça ve hatta oynatmasak da aralarda ekranda 'flickering (tam doğru terim değil ama anladığınız ne demek istediğimi)' oluyor ve görüntü assembler uygulamasının arayüzü ile karışıyordu. Bunu deneyip üzerinde düşünecek vaktiniz oldu mu, bilemiyorum ama size sorunun sebebini söyleyeyim: Interruptları kapatmadık. Sistem bizim 'kıymetlimissss' CPU zamanımızı ve ekranımızı bizden çalıyor ve sistemin ekran işleri bizim ufak uygulamamızla karışıyor. Dikkat: Bu örnekte Copper hiç kullanımıyordu. Hatta init bile etmemiştik.Yani saf CPU kullanıyoruz ekrana basmak için. CPU, Copper'ın yaptığı herşeyi yapabilir ama maliyeti çok yüksektir. Ekrana bir çizgi çekmek için kimse CPU kullanmaz. Biz bu örnekte en basitten başladığımız için CPU ile çizim yaptık. Bu örneği bitirdiğimizde bile Copper'ı ufaktan init etmiş ama hala tam kullanmıyor olacağız.

Photon'un kendini kaptırıp arada söylediği gibi: 'Enough talk, let's fight!'.

Sorunumuzu çözmek için sistem interruptlarını 'init:' kısmımızda kapatmamız ve 'exit:' sonrası uygulamadan çıkarken de tekrar açmamız gerekiyor. Eğer açmazsak sistem hiçbir device'ı artık kontrol edemeyeceği için amiga kilitlenecektir. Bu arada bir önceki girdide 'birşeyler unutuyoruz belki de' dediğim şey bu değil. Hala düşünebilecek vaktiniz var bunun üzerine. Ne unutuyoruz acaba? :)

'start:' ve 'init:' arasını şu şekilde değiştiriyoruz -- bold olan kısmı ekledik:
Alıntı
start:
   CIAAPRA=   $bfe001                  Input/Output for pin 6 (port 1 & 2 fire buttons) http://amiga-dev.wikidot.com/information:hardware#toc3
   VHPOSR=      $dff006                  Read raster XY position   http://amiga-dev.wikidot.com/hardware:vhposr
   COLOR00=   $dff180                  Palette color 0 http://amiga-dev.wikidot.com/hardware:colorx
   INTENAR=   $dff01c                  Interrupt enable bits read
   INTENAW=   $dff09a                  Interrupt enable bits (clear/set bits) http://amiga-dev.wikidot.com/hardware:intenar
   RASTERSTART=$ff                   $02c is the top of the screen
init:
.
.

INTENAR=$dff01c: Yeni birşey değil bizim için. Bir adresi bir sabite atadık. Bu adresi her yerde yazacağımıza, bu sabiti kullanacağız. Atadığımız adres sistem interrupt'larını etkinleştirme bitlerini okuma register'ının adresi.

INTENAW=$dff09a: Bir okuma registeri varsa bir de yazma registeri olmalı. Bu adres de sistem interrupt'larını etkinleştirme bitlerini yazma register'ının adresi. Bana neden okuma için ayrı yazma için ayrı bir register var diye sormayın. Amiga'nın dizaynının tuhaf noktalarından biri daha. Muhtemelen performans kaygıları yüzünden ayırdıklarını düşünüyorum. Ama bu konuda araştırma yapmadım. Eğer siz araştırırsanız bir gün, hepimizi de aydınlatabilirsiniz.

Adreslerin muhteviyatını bu link'te bulabilirsiniz. Bunların ne olduğunu öğrendiğimize göre yapacağımız şey kolay aslında:
  • Okuma register'ını kullanark 'init:' kısmında interrupt enable bitlerinin ('word' cinsinde bir değer bu) şu anki durumunu okuyacağız. Yani araba bize nasıl teslim edildiyse öyle geri vereceğiz ya sahibine, sağını solunu çizdirmeyeceğiz.
  • Okuduğumuz şu anki durumu uygulamamızda daha önce kullanılmamış, boş bir data register'a koyacağız - d1 olsun mesela
  • Yazma registerini kullanarak interrupt enable bitlerini $7fff değerine set edeceğiz. Dikkat ederseniz bu word değerde 15.bit (leftmost bit) sıfır. Yukardaki link'teki tabloya baktıysanız, bunun CLEAR operasyonu olduğunu görürsünüz. Geriye kalan FFF ise 14-0 arası tüm bitleri seçtiğimizi gösteriyor. Yani tüm interrupt etkinleştirme bitlerini sıfıra çekiyoruz. Diğer bir deyişle tüm sistem interruplarını kapatmış olacağız.
  • 'exit:' kısmına gelene kadar güllük gülistanlık uygulamamız at koşturuyor ortamda. Ama artık çıkacağız ve AmigaOS'a döneceğiz. Yani emanet arabayı vuruksuz şekilde sahibine teslim etmemiz gerekiyor :). Dikkat: bu arada d1 data register'ına hiç dokunmadık uygulamamız süresince. Dolayısı ile içinde hala interrupt enable bitlerinin uygulamamız başlarkenki durumları bir word halinde duruyor olmalı. Ne söylediğinizi duyar gibiyim, tabii ki böyle bir iş için tüm uygulama boyunca bir data registeri meşgul edilmez. Zaten topu topu 8 tane var birine zaten sistem el koymuş, stack pointer olarak kullanıyor (buna da geleceğiz merak etmeyin), birine de biz çöktük tüm uygulama boyunca. Normalde bu tür save işlemleri için memory alanları veya stack pointer kullanılıyor ama örneğin basit olması için burada bir data register kullandık.
  • d1 registerinin içindeki word değeri $c000 ile OR'luyoruz. Yani kısaca 15'inci ve 14'üncü bitleri set ediyoruz. Bu da, bu save edilmiş değerleri SET edeceğiz ama unutmadan Master Interrupt'ı (14.bit) da mutlaka set edelim demek (to be on the safe side).
  • d1 registerinin içindeki word değeri yazma registerini kullanarak yazıyoruz
  • Bu kadar.

Şimdi kodumuzu yukardaki şekle uygun bir halde düzenleyelim. 'init:' sonrası şunu ekliyoruz:
Alıntı
.
.
init:
   move #RASTERSTART,d7               d7 initialized to $0ff
   move INTENAR,d1                     read the Interrupt enable bits into d1
   move #$7fff,INTENAW                  disable all Interrupts

mainloop:
.
.

move INTENAR,d1: Okuma register adresinin gösterdiği memory noktasındaki değeri d1 data registerinin içine taşıyoruz. Dikkat: 'move' kullandık, bu 'move.w' demek biliyorsunuz. Interrupt etkinleştirme bitleri bir word değer olduğu için doğru bir taşıma yaptık. d1 registerinin (bu bir longword register aslında tabii) düşük word'ünde bizim interrupt etkinleştirme bitleri değerimiz var artık. Bu satırı şu şekilde de yazsaydık fark etmezdi: move.w $dff01c,d1 . INTENAR'ın veya $dff01c'ın önünde '#' kullanmadığımız için asmtwo bunu bir sabit sayı değil de bir adres olarak alıp o adresteki memory noktası içinde bulunan değeri getirecektir, unutmayın.

move #$7fff,INTENAW: Direk $7fff sabit sayısını INTENAW'ın gösterdiği adresteki yerin içine koyuyoruz. Yani daha önce anlattığım gibi, kısacası tüm sistem interruptlarını kapattık gitti. Bunu şöyle de yazabilirdik biliyorsunuz artık: move.w #$7fff,$dff09a . '#' işaretinin nerede kullanılıp nerede kullanılmadığına dikkat edin lütfen.

'exit:' sonrası şunu ekliyoruz:
Alıntı
.
.
exit:
   or #$c000,d1                      re-enabling all Interrupts
   move d1,INTENAW                      writing the Interrupt enable bits

   rts

or #$c000,d1: Yeni bir komut görüyoruz: OR. Bu komut soldaki ile sağdaki değerleri bitwise (bit-by-bit) OR'layıp sağdaki adresin gösterdiği yerin içine koyar. 'or' yazıldığına göre bu 'or.w' demek. d1 içinde save ettiğimiz interrupt enable bitleri vardı. Yukarda nedenini anlattığım şekilde 15. ve 14. bitleri set ettik (OR'ladık). ve d1 register'inin içine koyduk.

move d1,INTENAW: d1'in low word'ü içindeki değeri götürdük çaaaat diye interrupt etkinleştirme bitleri yazma register'ına word olarak yazdık. Bu noktada tüm sistem interruptları geri geldi. Beklersek ekranımız titreyecek vs vs. Ama 'rts' ile kaçtık gittik biz, çoktan AmigaOS'a döndük. Sanki birşey unutuyoruz ama? :).

Bir bakalım ne oldu:
Not a valid vimeo URL
Kod ekte.

Evet, titreme yok oldu. Artık mouse da oynamıyor tabii. Interruptların hepsini kapatınca başka ne olacaktı ki. Yanlız bir gariplik var. Ekran temiz değil sanki. Neyse ona sonra bakarız, önce çizgimizi kaydıralım artık, bir şanımız olsun.

--- devam edecek...

Sevgiler, selamlar.

Çevrimdışı codewarrior

  • RAAT
  • Retroman
  • *
  • İleti: 30
Ynt: codewarrior'ın Amiga Assembler Güncesi
« Yanıtla #10 : 22 Şubat 2020, 19:52:45 »
Yeni bir gün, yeni bir girdi. Bugün basit örneğimizi tamamlayacağız ve Copper'a da hafif bir giriş yapacağız. Hadi başlayalım...

Çizgimizi aşağı yukarı kaydırabilmek için, raster'ı beklediğimiz yeri dinamik olarak değiştirmemiz gerekiyor.  Yani algoritmamız şu şekilde olmalı:
  • Raster bekleme yerimizi ekranın en üst noktasına set edelim ($02c).
  • Ana döngünün her dönüşünde raster bekleme noktamızı bir arttıralım.
  • Eğer dibe ($12b) ulaşırsak bir arttırmak yerine bir azaltmaya başlayalım.
  • Eğer tepeye ($02c) ulaşırsak bir azaltmak yerine bir arttırmaya başlayalım.

Dikkat ederseniz dip noktayı $12c yerine $12b aldık. Çünkü eğer $12c alırsak çizgimiz ekranın altından üstüne taşma yapıyor. Bu sorunla karşılaşmamak için bu tür bir önlem alıyoruz. Sizler $12c ile deneyip ne demek istediğimi görebilirsiniz.

Yukarıdaki algoritmamızı uygulamaya başlayalım. Öncelikle 'init:'in hemen öncesine şunları ekliyoruz:
Alıntı
.
.
   RASTERSTART=$02c                  $02c is the top of the screen
   RASTEREND=   $12b                  $12c is the bottom of the screen
   INCREMENT=   1                     speed of the rasterline movement
init:
.
.
Gördüğünüz gibi ekran başlangıç ve bitiş satırlarını tanımladık. Satır değiştirme miktarımızı da 1 birim olarak belirledik. 'init:'in altına aşağıdaki bold olarak işaretli satırı ekliyoruz. Satır değiştirme miktarımızı d6 data register'ine koyduk -- Bir register daha harcadık, bu iş böyle olmaz :)
Alıntı
.
.
init:
   move #RASTERSTART,d7               d7 initialized to $0ff
   move #INCREMENT,d6                  d6 initialized to 1
.
.

Şimdi, çizgiyi çizdiğimiz noktada, çizmeden hemen önce, çizginin bulunduğu yere göre arttırım veya eksiltme işlemini yapacağız. Arka plan rengini siyaha çektiğimiz yerin hemen altına aşağıdaki bold olarak işaretlenmiş kodu ekliyoruz:
Alıntı
.
.
   move.w #$000,COLOR00               move color black to COLOR00(background palette)

   add d6,d7                        add the INCREMENT to raster position
   cmp.w #RASTEREND,d7                  raster at the bottom?
   blo .a                           not yet so jump over next line
   neg d6                           passing the screen bottom, need to return,
*                                 so negate the INCREMENT
.a:
   cmp.w #RASTERSTART,d7               raster at top?
   bhi .b                           not yet so jump over next line
   neg d6                            passing the screen top, need to return,
*                                 so negate the INCREMENT
.b:

waitraster1:
.
.
Eklediğimiz kısmı incelersek, bizim için yeni birkaç komut göreceğiz. O yüzden bu kısmı yine satır satır açıklayalım:

add d6,d7: Adı üstünde toplama işlemi bu. Soldaki yerdeki değeri sağdaki yere ekliyor ve sonuç yine sağdaki değerin içinde kalıyor. Burada birşey belirtmediğimiz için word işlemi yapılıyor. Zaten d6'yı ve d7'yi initialize ederken de INCREMENT ve RASTERSTART değerlerimizi değerimizi word olarak atamıştık. Dolayısı ile burada word toplama yapmak doğru olacak.

cmp.w #RASTEREND,d7: Bu komutu biliyoruz. d7'nin içinde $12b değeri mi var diye kontrol ediyoruz. Yani d7'yi arttıra arttıra gidiyoruz, ekranın dibine vardık mı acaba?

blo .a: 'blo', 'Branch if Lower' demek. Yeni bir komut ama gayet anlaşılır ne yaptığı. Bir önceki karşılaştırmamızda sağdaki değer soldaki değerden küçükse verilen label'a dallanır. Burada dikkat ederseniz label'imizin solunda bir '.' var. Bu nokta, bu label'in bir lokal label olduğunu gösteriyor. Eğer bu nokta yoksa o label 'global' bir label'dır. Aradaki fark basitçe şu: Lokal label'lar iki global label arasında tanınır. Yani bir lokal label'ı tanımladığınız ismi, arasında kaldığı iki global label dışında tekrar kullanabilirsiniz. Kodlamayı kolaylaştırmak için getirilmiş muhteşem yöntemlerden biri.

neg d6: Buraya geldiyse üstteki dallanma çalışmadı demektir. Yani karşılaştırma sonrası d7, ekranın dip noktasına eşit (ya da büyük) çıktı. Bir arttırma yerine bir azaltma yapmaya başlamamız lazım. 'neg' komutu tam olarak bunu yapıyor. d6 içindeki sayı herneyse onu -1 ile çarpar yani 'negate' eder. Artık d6 içinde -INCREMENT var yani -1.

.a: Bir lokal label. Öğrendik biz bunu.

cmp.w #RASTERSTART,d7: d7'yi bir de ekranın tepe noktası ile karşılaştıralım. Tamam dipten çıkmadık ama belkide tepeden uçmak üzereyiz.

bhi .b: 'bhi', 'Branch if Higher' demek. Yani bir önceki karşılaştırmamızda sağdaki değer soldaki değerden büyükse verilen label'a dallanır. 'blo' gibi çalışıyor, çok farklı değil.

neg d6: Buraya geldiysek d6 içinde eksi değer var ve bizde tepeye vurduk. Bir 'negate' çekelim de tekrar yola girelim. Artık d6 içinde -(-INCREMENT) var yani 1.

.b: Hmmm.

Bir çalıştıralım bakalım, ne olacak:
Not a valid vimeo URL
E, gayet güzel kayıyor işte. Başardık!. Yanlız ekranda bir pislik, arkada kalan görüntüler var vs. Ekranı silsek, tertemiz olsa daha güzel olacak. Hadi bunu da Copper kullarak yapalım, böylece copper'a da yumuşak bir giriş yapmış oluruz.

Copper nedir, ne değildir? Şuradan (link) okuyabilirsiniz. Aslında basitçe CPU üzerinden yük almak için tasarlanmış, custom bir yan-prosesördür. Değerli CPU zamanı yerine, görece değersiz olan copper zamanını kullanarak CPU'da daha önemli işlerimizi paralelde yaptırabiliriz. Copper, her biri 4-byte yani 2-word yani bir longword uzunluğunda olan komutları sırayla okuyup çalıştırır. Geleneksel olarak bu komut listesine 'CopperList' denir. Copperlist, Amiga'nın Chip memory'si içerisinde ve assembler tarafından data olarak tanımlanan bir section'a yerleştirilmek zorundadır. Burada section'dan kasıt bir memory aralığından başka birşey değil.

'Birşeyi örnekle öğrenmek en iyi yöntemdir' düstürümüzden hareketle, ekranı temizleme işini copper'a yaptıracağız. Ama öncelikle ne yapmamız gerekiyor? Amiga coding'in özünü unutmayın: Hiçbir şey kolay değil, hiçbir şey acı çekmeden olmaz. Önce acımızı çekmemiz lazım. Epeyce bir hazırlık, tanımlama vs yapmamız gerekiyor copper'ı ayağa kaldırmak için.

Copperlist'i yerleştireceğimiz data section'umuzu tanımlamamız lazım ama Assembler'a data bölümünü belirtmek için önce kod bölümünü belirtmek gerekiyor. Data section biraz daha beklemek zorunda. Kodumuzun en üstüne şu satırı ekliyoruz:
Alıntı
   SECTION rasterline_code,CODE_C
.
.
Assembler'a diyoruz ki:Bir SECTION daha görene kadar bundan sonraki tüm kodu CODE section'unun içine yerleştir. Hatta bu section mutlaka Chip memory içinde bir yerlerde olsun. Bunu CODE_C'nin sonundaki C ile belirtiyoruz. C yerine F de yazabilir veya hiçbirşey yazmayabilirdik. F, Fast memory'i ifade eder. Eğer sadece CODE dersek, Amiga kafasına göre bir yerlere (Public Memory) yerleştirecek demektir.

Kodumuzun en alt kısmına şu satırı ekliyoruz:
Alıntı
.
.
rts

gfxname:
   dc.b "graphics.library",0            name of the library to open

Burada bir tanımlama yaptık. 'dc.b' yani 'declare bytes' komutunu kullanarak 'graphics.library' string'ini bir memory alanına yerleştirdik. Sonuna da bir NULL karakter koyduk (,0). Yani toplamda 17 bytelık bir yer ayırdık, içine 'graphics.library\0' yazdık. Bunun ilk byte'ının adresini de 'gfxname:' label'ı gösterecek şekilde ayarladık. Yani kodumuz içinde bir yerde 'gfxname'in gösterdiği adrese atıfta bulunursak, 'g' karakterini içeren bir byte'a atıfta bulunuyor olacağız. 'gfxname+1'in gösterdiği yere atıfta bulunursak, 'r' karakterini içeren bir byte'a atıfta bulunacağız. Bu şekilde...

Şimdi bu yeni değişkenimizi kullanalım. 'init:' satırının hemen sonrasına aşağıdaki parçayı ekleyelim:
Alıntı
.
.
init:
   move.l 4.w,a6                     execbase
   move.l #gfxname,a1                  filling in the paramter for
   jsr -408(a6)                     calling oldopenlibrary*()
   move.l d0,a1                     getting return value
   move.l 38(a1),d4                  getting the original copper ptr
   jsr -414(a6)                     calling closelibrary()


   move #RASTERSTART,d7               d7 initialized to $0ff
.
.

'Yavaş codewarrior, serin gel' dediğinizi duyar gibiyim. Merak etmeyin açıklayabilirim, bir fırsat verin, vurmayın..

Yukarda bir yerlerde demiştik ya, copper copperlist'i işler durur diye. İşte normalde AmigaOS'un işlettiği bir copperlist'i işliyordu bu ana kadar. Biz araya girip, copper'a da çöküp AmigaOS'un elinden alıp kendi emellerimize alet edeğiz. Yanlız arabayı çizdirmeden sahibine geri vermek gibi ulvi bir amacımız var unutmayın. Photon'un deyimi ile 'kötü çocuklar değiliz biz'. Sağlam vereceksek de orjinal copperlist adresini bir yerlere saklamamız lazım ki, çıkarken geri yerine koyabilelim. İşte bu adres ulaşabilmek için 'graphics.library'i açıp içinden bir fonksiyonu çalıştırıp, onun döndürdüğü değerler arasından copperlist pointer'ı alıp saklayacağız. Sonra da tabii 'graphics.library'i kapatsak fena olmaz. Boşuna memory harcamasına gerek yok. İşte bu kod parçacığı tam olarak bu işi yapıyor. Bir adresi almak için ne eziyetler, ne eziyetler.

Gene satır satır gidelim:

move.l 4.w,a6: AmigaOS içerisindeki çalıştırılabilir rutinlerin bir tablosunu a6 isimli adres registerına yüklüyoruz. Adres registerları, data registerları gibi çalışırlar. Onlar gibi longword bir değer tutarlar ve yazıp-okuyabilirsiniz. Ama tuttukları değerler data yerine adres değerleridir. Adresleme işlemlerinde kullanılmak üzere bazı güzel ek özellikler barındırırlar. Bir tanesini sonraki satırlarda göreceğiz. Buradaki komut, entresan bir şekilde 4. memory bölgesi ile işlem yapıyor. Dikkat ederseniz 4'ün başında bir # yok. Dolayısı ile bu bir adres değeri ve resmen Amiga'daki hafızanın 4.noktasına direk bir atıf yapıyor. Bu nokta OS içindeki çalıştırılabilir rutinlerin tablosunun adresini içeriyor aslında. Burada word olarak bu adresi a6 içine alıyoruz.

move.l #gfxname,a1: Hatırlarsanız 'gfxname' bir label ve bir string'e işaret ediyor. Daha önce anlattığım gibi eğer biz 'gfxname'e direk atıfta bulunursak bu string'e ulaşıyoruz. Eğer '#gfxname' şeklinde yazarsak etiketin numarasına yani tahmin edebileceğiniz gibi 'adres'ine ulaşıyoruz. Bu satırla 'gfxname' label'inin gösterdiği string'in başlangıç adresini a1 adres register'ına alıyoruz.

jsr -408(a6): 'jsr', 'Jump to Subroutine' demek. Burada, a6 adres registerinin gösterdiği byte'ın 408 byte gerisinden başlayan bir subroutine'e yani fonksiyona atlıyoruz. Bu noktada uygulamamız o adresteki o fonksiyonu çağırıyor ve dönene kadar o fonksiyon çalışıyor. Bu fonksiyon 'oldopenlibrary' fonksiyonu. Bir kütüphane açmamızı ve içindeki rutinlere ulaşmamızı sağlıyor. Peki hangi kütüphane? Hangisi olduğunu a1'in içine koyduğumuz adres ile söyledik ya: 'graphic.library'. 'oldopenlibrary' fonksiyonunun detayı için şuraya bakabilirsiniz: Link. Burada adres registerlarının güzel bir özelliğini görüyoruz: -408(a6). Bir adres register'ını parantez içine alıp öncesine sayısal bir değer verirsek, adres registerının gösterdiği noktayı geçici olarak (bu satır için sadece) o sayısal değer kadar değiştirebiliriz.

move.l d0,a1: Fonksiyon çalıştı ve döndü. Sonucu 'd0' içine bıraktı. Dikkat ederseniz 'oldopenlibrary' fonksiyonu parametresini a1 içinden aldı, sonucunun (ki epey büyük bir data) başlangıç adresini d0'a bıraktı. Bu her fonksiyon için farklıdır. Bu satır ile d0 içindeki adresi olduğu gibi a1 içine aldık.

move.l 38(a1),d4: AmigaOS'un kullandığı orjinal copperlist pointer a1 registerinin gösterdiği değerin 38 byte ilerisinde. Bu noktadan bir longword okuyup d4 registeri içine yazıyoruz. Şükürler olsun, orjinal copperlist adresini elde ettik.

jsr -414(a6): a6'nın içinde hala AmigaOS içerisindeki çalıştırılabilir rutinlerin tablosu duruyordu. Başka bir fonksiyon çağırıyoruz: CloseLibrary, detaylar burada: Link. Hangi library'i kapatacağını parametre olarak aldığı a1 içisindeki aldığımız dataya bakarak anlıyor. Yani bu fonksiyon 'gfxname' ile gösterilen ismi kullanmıyor. Zaten dikkat ettiyseniz, a1'in içinde o ismin adresi yok artık. Böylece 'graphics.library'i kapattık gitti.

Orjinal copperlist adresi var artık elimizde ve d4'ün içinde. Uygulama sonuna kadar d4'e de dokunamayacağız artık. Kötü programlama nedir, nasıl yapılır? Örneklerle gösteriyorum burada. :) İleride düzelteceğiz bunları hep, merak etmeyin.

Artık sıra geldi copperlistimizi yazmaya. Öncelikle copper ne yapabilir, fonksiyonelitesi nedir, onu bir anlamaya çalışalım. Copper, özetle sadece üç çeşit işlem yapabilir: MOVE, WAIT ve SKIP.

MOVE:: $reg,$değ: Bir Amiga donanim registerine ($reg) bir word değer ($değ) yükler. Genel olarak copper'ın erişebildiği tüm registerlerin adresleri $dffxxx şeklindedir. Tüm bu adresler $dff ile başladıkları için copperlistte bu kısmı yazmaya gerek yoktur ve son 3 basamak bir word şeklinde yazılır: $xxx.

WAIT:: $SATIRSUTUN,$fffe: Raster'ın belli bir pozisyona gelmesi beklemek için kullanılır. Soldaki word değerin ilk byte'ı raster'ın satır pozisyonunu, ikinci byte'ı sütun pozisyonunu gösterir. İkinci word değer ise birinci word'deki bitlerin hangilerinin karşılaştırmaya katılıp katılmayacağını gösterir. Normalde 'tüm bitler' anlamına gelen $fffe kullanılır. Diyelim ki siz sadece satır kontrolü yapmak istiyorsunuz. O zaman $ff00 yeterli olacaktır. Bu durumda birinci word'deki ikinci byte (SUTUN) hesaba katılmayacaktır. WAIT  komutu olduğunu belirtmek için ikinci word'ün birinci biti daima 0'dır.

SKIP: $SATIRSUTUN,$ffff: Raster'ın belli bir pozisyona gelene kadar sonraki copperlist komut satırı atlanır. Çalışma mantığı WAIT ile birebir aynıdır. Sadece SKIP komutu olduğunu belirtmek için ikinci word'ün birinci biti daima 1'dir.

Copperlist her zaman $ffff,$fffe komutu ile biter. Gördüğünüz gibi bu aslında, 255.satır 243.sütunu bekle komutudur. Böyle bir satır-sütun olmadığı için bu hiç gerçekleşmeyecek bir komuttur ve copperlist sonu anlamına gelir. Copperlist komutları genelde tek satıra iki word şeklinde tanımlanır ama isterseniz 4 byte veya tek bir longword şeklinde de tanımlayabilirsiniz.

Bu örnekteki copperlistimizi yazmak için uygulamamızın en altına şu satırları ekliyoruz:
Alıntı
.
.
gfxname:
   dc.b "graphics.library",0            name of the library to open

   SECTION rasterline_data,DATA_C
Copper:
   dc.w $100,$0200                     disable all bitplanes
   dc.w $ffff,$fffe                  end of the copperlist

.
.


Satır satır gidelim gene.

SECTION rasterline_data,DATA_C: Copperlist mutlaka Chip memory içinde ve bir data section'unda yer almalı. Dolayısı ile 'rasterline_data' isminde böyle bir section tanımladık.

Copper: Copperlist'imizin başlangıç adresini gösteren label.

dc.w $100,$0200: 'declare words' komutunu kullanarak 2 word tanımlıyoruz. Bu bir MOVE işlemi. $dff100 adresine $0200 word değerini atıyor. Bu 'Bit Plane Kontrol Register 0'ın adresi. Buraya $0200 değerini yükleyerek tüm 'bit plane'leri kapatıyoruz. Bunun detayına daha sonra geleceğiz ama bu noktada şunu bilmeniz yeterli. Tüm bitplane'leri kapatmak ekranda halihazırda var olan görüntüleri silecektir. Yani ekranı temizliyoruz bu şekilde.

dc.w $ffff,$fffe: Bunu biliyoruz. Copperlist bitiş komutu.

Artık bir copperlistimiz olduğuna göre bunu orjinal copperlistin yerine koyabilir ve bunun çalışmasını sağlayabiliriz. Bunun için aşağıdaki kodu start'ın altına ekliyoruz ki copperlist'imizi yazacağımız register adresini aklımızda tutmak zorunda kalmayalım:
Alıntı
.
.
   INTENAW=   $dff09a                  Interrupt enable bits (clear/set bits)
   COPPERADDR=   $dff080                  Copperlist address
   RASTERSTART=$02c                  $02c is the top of the screen
.
.
Ve copperlistimizin adresini copper registerine yazıyoruz. 'init:' içine şunu ekleyelim:

Alıntı
.
.
   move #$7fff,INTENAW                  disable all Interrupts

   move.l #copper,COPPERADDR            putting our copperlist in
mainloop:
.
.

Çilemiz henüz bitmedi. Arabayı sahibine teslim edeceğiz unutmayalım. Tahmin edeceğiniz üzere çıkmadan hemen önce orjinal copperlist'i yerine koymalıyız ki AmigaOS bir şok geçirmesin. d4'ü hiç kullanmadık bu arada, yani orjinal copperlist adresi hala orada olmalı. Aşağıdaki kodu 'exit:'in hemen sonrasına ekliyoruz:
Alıntı
.
.
exit:
   move.l d4,COPPERADDR               put the original copperlist back
.
.

Evet, tamamız galiba. Bir deneyelim bakalım, nasıl oldu?:

Not a valid vimeo URL

Soğuk bir birayı hakkettik bence. ;)
Selamlar, sevgiler.


Not: Sonraki episode'da CPU üzerindeki yükü Copper'a taşıyoruz ve rasterline'ın kalınlığını arttırıyoruz. Öğrendiklerimizle bunu yapmanın ne kadar kolay olacağına şaşıracaksınız.

Çevrimdışı codewarrior

  • RAAT
  • Retroman
  • *
  • İleti: 30
Ynt: codewarrior'ın Amiga Assembler Güncesi
« Yanıtla #11 : 25 Şubat 2020, 11:47:20 »
Tekrar hoşgeldiniz. Bugünkü amacımız CPU üzerindeki yükü Copper'a aktarmak ve kayan çizgimizi kalınlaştırmak. Nispeten basitçe halledeceğiz diye düşünerek başlıyoruz. Muhtemelen yine bir çukurun dibine yuvarlanacağız :)

Öncelikle ufak tefek düzenlemeler yapalım kodumuzda. 'mainloop:'un hemen altını şu şekilde değiştiriyoruz arkaplan rengini siyaha set ettiğimiz son satırı siliyoruz. Çünkü bu işi zaten copper yapacak:
Alıntı
.
.
mainloop:
.w1:
   btst #0,VHPOSR-1                  test if raster high byte is 0
   bne .w1                      if not loop again to wait
   cmp.b #$2b,VHPOSR                   test if raster low byte is $2c (raster at top?)
   bne .w1                        if not loop again to wait
.w2:
   cmp.b #$2b,VHPOSR                   test if raster low byte is $2c (raster at top?)
   bne .w2                        if not loop again to wait


   move.w #$000,COLOR00                  move color black to COLOR00(background palette)
.
.
İkinci bir loop (.w2) eklediğimizi gördünüz ve açıkcası ilk loop'un son kısmının bir tekrarı olarak görünüyor. Evet aynen öyle. Bu ikinci küçük loop'u raster'ı bir tur daha beklemek için kullanıyoruz. Amacımız biraz delay sağlamak, o kadar. Aklınızda olsun programlarınızda bekleme yaratmanın en kolay yollarından biri raster'ın belli bir pozisyona gelmesini beklemektir. Eğer sizin için bu çok hızlı oluyorsa, bir loop içerisinde birden fazla kereler bekleyebilirsiniz aynı noktayı.

Kodumuzdan alttaki kısmı tamamen siliyoruz. Bu kısmı da copper halledecek:
Alıntı
.
.
waitraster1:
   cmp.b VHPOSR,d7                     raster on our desired position?
   bne waitraster1                     if not loop again to wait
   move.w #$fff,COLOR00                  move color white to COLOR00(background palette) we are drawing the line
waitraster2:
   cmp.b VHPOSR,d7                     raster on our desired position?
   beq waitraster2                     if not loop again to wait
   move.w #$000,COLOR00                  move color black to COLOR00(background palette) we are done drawing
.
.

Temizliğimizi yaptığımıza göre copperlist'imizi yazabiliriz. Önceki copperlist'i aşağıdaki şekilde değiştiriyoruz:
Alıntı
.
.
Copper:
   dc.w $1fc,0                     slow fetch node, AGA compatibility http://amiga-dev.wikidot.com/hardware:fmode
   dc.w $100,$0200                     disable all bitplanes
   dc.w $2c07,$fffe                  wait for the top
   dc.w $180,$000                     change background color to black
startdraw:
   dc.w $0007,$fffe                  wait for the start of current line
   dc.w $180,$fff                     change background color to white
enddraw:
   dc.w $00ff,$fffe                  wait for the end of current line
   dc.w $180,$000                     change background color to black
   dc.w $ffff,$fffe                  end of the copperlist
.
.

Satır satır inceleyelim ki iyi anlayalım di mi?:)

dc.w $1fc,0: Bu AGA Write Fetch mod registeri ($dff1fc). Sıfır atayarak OCS compatible modu seçiyoruz. Amacımız tüm Amiga'lar ile uyumlu çalışması copperlistimizin. Hatırlarsanız copper, donanım registerlerine ulaşırken adresin $dff kısmını default olarak var kabul ediyordu. Buradan anlıyoruz ki ancak $dff ile başlayan registerlara ulaşabilecek şekilde tasarlanmış.

dc.w $100,$0200: Tüm bitplane'leri kapattık. Ekran silindi.

dc.w $2c07,$fffe: Raster'ın en üst satır ve 7.kolona gelmesini bekledik. 7.kolonu bekleme sebebimiz çizginin tam olarak ekranda görünür ilk noktadan başlaması için. Bunu da hatırlamamız gereken konular içerisine not aldık.

dc.w $180,$000: $dff180 register'ine (arkaplan rengi), siyah ataması yapıyoruz.

dc.w $0007,$fffe: Bu satıra kodumuz içerisinden 'startdraw:' etiketi yardımı ile ulaşarak dinamik olarak ilk byte'ı (satır no) değiştireceğiz. Amacımız çizgimizin başlangıcı için dinamik şekilde raster pozisyonu beklemesi sağlamak.

dc.w $180,$fff: Bu satır çalıştığına göre istediğimiz yere geldi raster. Beyaza set ediyoruz arkaplan rengini ve boyamaya başlıyoruz.

dc.w $00ff,$fffe: Bu satıra kodumuz içerisinden 'enddraw:' etiketi yardımı ile ulaşarak dinamik olarak ilk byte'ı (satır no) değiştireceğiz. Amacımız çizgimizin bitişi için dinamik şekilde raster pozisyonu beklemesi sağlamak.

dc.w $180,$000: Bu satır çalıştığına göre istediğimiz yere geldi raster. Siyaha set ediyoruz arkaplan rengini. Çizimimiz bitti.

dc.w $ffff,$fffe: Copperlist'i bitiriyoruz.


Çalıştıralım bakalım. Bu noktadaki kodu 'rasterline_basic3.S' olarak ekliyorum:
Not a valid vimeo URL
Allahın belası $ff posizyonu tüm keyfimizi kaçırdı gene. Ya arkadaş bu nasıl bir dizayndır. Bu çözünürlükte ekranda 256 satır yok mu? En tepeye $00 de en alt $ff olmuyor mu? Böyle yap, bir sorun olmasın. Ama olmaz, ilk satır $02c olacak, son satır da $12c olacak, copper komutlarında satır byte olarak alınacak ki aradaki $0ff-$100 geçişini anlamak bir eziyete dönsün.

Neyse sinir krizi için çok erken arkadaşlar. Daha ilerde neler var bilseniz :). Şu an gördüğümüz problemi nispeten basit bir yöntem ile çözebiliriz. İlerde tekrar başımıza bela olacak ve daha zor ama kesin bir çözüm geliştireceğiz. Yine de bu örneği olabildiğince basit tutabilmek adına, çok güzel olmayan palyatif bir çözüm ile ilerlemeye çalışalım. Eğer kendiniz 'bu çözüm nasıl olmalı?' diye düşünmek isterseniz, açıkcası bildiğiniz şeyler burada göstereceğim çözüme ulaşmanıza imkan veriyor. Düşünmek isterseniz bu noktada okumayı bırakın ve hazır olduğunuzda geri gelin. Bekliyorum :)

Düşündünüz mü? Umarım yapabilmişsinizdir. Devam ediyoruz:

'dc.w $ffdf,$fffe' komutunu kullanarak 'geçiş çizgisinin sonunda mıyız, acaba?' testini yapabilir ve raster'ı bu noktaya kadar bekletebiliriz. Bu satırdan sonraki copperlist satırlarında bekleyeceğimiz her satır no, aslında $100+satır olacaktır. Bu geçişin çizgimizin pozisyonuna göre nerede olması gerektiğini düşünürsek aslında 3 ihtimal olduğunu görebiliriz: $ff geçişi, çizgimizden sonra, önce veya (kalınlığına göre) çizgimizin içinde olabilir. Dolayısı ile çizgimizi kaydırırken bu geçişi de dinamik yerleştirmemiz gerekiyor. Quick-n-dirty bir çözüm olarak çizgimizin başlangıç noktasının öncesine, bitiş noktasının sonrasına ve tam ikisinin arasına da birer 'border' koyuyoruz. Border'ları çizgimizin o anki pozisonuna göre dinaik değiştireceğiz ama copperlist'i yazarken default değerlerini yazıyoruz. Copperlist'imizi aşağıdaki şekilde değiştiriyoruz:
Alıntı
.
.
border1:
   dc.w $2cdf,$fffe
startdraw:
   dc.w $0007,$fffe                  wait for the start of current line
   dc.w $180,$fff                     change background color to white
bordermid:
   dc.w $ffdf,$fffe
enddraw:
   dc.w $00ff,$fffe                  wait for the end of current line
   dc.w $180,$000                     change background color to black
border2:
   dc.w $2bdf,$fffe

.
.
'b:' etiketi sonrasına aşağıdaki kodu eklememiz gerekiyor ki borderları runtime'da dinamik olarak düzenleyebilelim:
Alıntı
.
.
.b:
   cmp.w #$0ff,d7                  is d7 higher than $0ff?
   beq .d                        equal, so no problem
   bhi .c                        our line in lower screen, borders should switch

   move.b #$2d,border1               our line in higher screen, border1=screentop
   move.b #$ff,border2               border2=$ff
   move.b d7,bordermid               bordermid can be our line position
   jmp .d

.c:
   move.b #$ff,border1               our line in lower screen, border1=$ff
   move.b #$2b,border2               border2=screenbottom
   move.b d7,bordermid               bordermid can be our line position
.d:

   move.b d7,startdraw               put our line start position in copperlist
   move.b d7,enddraw               put our line end position in copperlist
.
.
Bu kısmın anlaşılır olduğunu düşünüyorum ama yine de kısaca özetlemem gerekirse:

Şu anki çizgi satırımızı $ff değeri ile karşılaştırıyoruz. Eğer büyükse '.c:' etiketine, eşitse '.d:' etiketine atlıyoruz. Eğer küçükse hiçbir yere atlamadan aşağıya doğru devam ediyoruz. Eğer eşitse birşey yapmamıza gerek yok, copperlist'e girdiğimiz default hali zaten bu durum için hazırlanmış. Küçük olduğu durumda çizgimiz ekranın üst kısmında bir yerlerde demektir. Yani border1'i ekranın en üst noktasına, border2'yi de sorunlu noktaya ($ff) set edersek, çizgimiz zaten arada bir yerde olacak demektir. Bordermid'i de çizgimize güvenle set edebiliriz. Büyük olduğu durumda da tersi geçerli: Border1'i $ff değerine, border2'yi ekranın altına ve bordermid'i de çizgimize set edersek çizgimizin yerini doğru konumlandırmış olacağız.

Bir bakalım oldu mu acaba?:
Not a valid vimeo URL
Mükemmel!. İlerde başımız ağrıyacak ama şu an mutluyuz :).

Bugünü kapatmadan önce bir de kalınlaştıralım çizgimizi, ne dersiniz? Bakın bu kolay işte. Kodumuzda 'init:' öncesine bir tanım ekleyelim:
Alıntı
.
.
   INCREMENT=   1                     speed of the rasterline movement
   LINETHICKN=   10                     thickness for our line
init:
.
.
Sonrasında '.d:' kısmını aşağıdaki şekilde değiştirelim:
Alıntı
.
.
.d:
   move.b d7,startdraw               put our line start position in copperlist
   add #LINETHICKN,d7               increase d7 to push end pos further
   move.b d7,enddraw               put our line end position in copperlist
   sub #LINETHICKN,d7               decrease d7 to get the original d7 value
.
.
Dikkat ederseniz burada çizgimizin başlangıç satır numarasını copperliste yazdıktan hemen sonra d7'yi kalınlık değeri kadar arttırıp bitiş noktasını copperliste yazıyoruz. Ne kadar kalınlık tanımladıysak başlangıç ve bitiş satırları arası o kadar artacak. Bu da bize kalın bir beyaz çizgi verecek. Eski d7 değerine dönmek için kalınlığı tekrar çıkartmamız yeterli oluyor bu arada.

Nasıl görünecek, bir bakalım:
Not a valid vimeo URL
Hmm, kalınlık güzel olmuş ama bir kedi gördüm sanki. Bir göz kırpma mı var ne? Şaka bir yana, bu noktada size bu güncenin ilk girdisinde anlattığım problemle karşılaşıyoruz. Çizgimizin kalınlığı 1 pikselin üzerine çıkınca, sorunlu $ff noktasından geçerken kırılmalar oluyor. Bunun çözümü biraz daha sofistike ve aslında bunu ilk girdide anlatıım. Oraya atıf yaparak devam edeceğiz.

Ama önce bir mola.
Sevgiler, selamlar...


Çevrimdışı Alco

  • Yönetici
  • Özgür Retrocu
  • *
  • İleti: 2227
  • "Kahraman olmak, dürüst olmaktan kolaydır" Luigi P
    • Sizin Amstrad
Ynt: codewarrior'ın Amiga Assembler Güncesi
« Yanıtla #12 : 26 Şubat 2020, 15:11:37 »
Anketi yeni farkettim. Bence yazım dilin harika ve genel olarak süper gidiyor. Böyle mesajlarla araya girip bölmek istemiyorum ama belirteyim dedim.

Çevrimdışı Alpyre

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 106
Ynt: codewarrior'ın Amiga Assembler Güncesi
« Yanıtla #13 : 26 Şubat 2020, 15:52:24 »
Bu konuya (senin kadar açık ve detaylı anlatılmamış olsa da) Amiga Hardware Reference Manual'de değinilmiştir (bkz. Copper WAIT instruction).
Bir de benzer şekilde masking sorunsalı vardır ki, bir sonraki güncede de onun detaylarını bekleriz artık. :) Keyifle okudum, bilgi tazeledim, eline sağlık.

Çevrimdışı Ref

  • Yönetici
  • Özgür Retrocu
  • *
  • İleti: 2958
  • Advanced User Simulator
    • ae unutmadan
Ynt: codewarrior'ın Amiga Assembler Güncesi
« Yanıtla #14 : 27 Şubat 2020, 23:45:25 »
Şu anda ben de takipteyim, itiraf edeyim çok eğlenceli. Bir başka itiraf, şu "boşlukta" duran commentler bana gerginlik yaratıyor. Alışmamışım öyle ortaya yazmacaya! Önünde // ya da ' ya da ; falan olmalı :) Amigada ayak altına dolanmaması güzel bu arada. PC'de rahat okunuyor.

 


Neyse, bu rehberleri okurken yıllardır bulduğum her platformda kodladığım bir projem var, şimdi de copper ya da blitter'in çizgi çizdirme fonksiyonu ile yapacağım Snes mode 7 türü bir yol gitme efekti (lotus gibi). Copper yarı yolda renk değiştirebilse süper olurdu ama değiştiremese bile, color cycling için kullanılabilir gibi sanki.

Geç gelen edit:
Buralarda bazı registerler bulunuyor, ya da palet adresleri var. Örneğin INTENA(R) INTENA(W) gibi, ne oldukları şuradaki bağlantıda mevcut:
http://coppershade.org/articles/Code/Reference/Custom_Chip_Register_List/