Gönderen Konu: CPC'de Assembler ile imtihanım...  (Okunma sayısı 34341 defa)

0 Üye ve 1 Ziyaretçi konuyu incelemekte.

Çevrimdışı Fero

  • RAAT
  • Retroman
  • *
  • İleti: 34
  • guy.brush
    • Ferhat Tanman
Ynt: CPC'de Assembler ile imtihanım...
« Yanıtla #30 : 03 Ocak 2019, 13:22:05 »
Ayrıca, @fero,
ekteki grafikte raat#5 metni görüyorum ama partide bunu göstermedin. Yoksa ben mi kaçırdım?

CPC paletiyle ilk denememdi. Pek istediğim gibi olmadı. Arada kaynattım :)
"Never pay more than 20 bucks for a computer game."

Çevrimdışı matahari

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 209
    • The Blog of Mert Börü
Ynt: CPC'de Assembler ile imtihanım...
« Yanıtla #31 : 03 Ocak 2019, 13:27:08 »
Ödevi şöyle bırakayım :)

Harika, elinize sağlık Fero! Z80 kodlamanız giderek çok daha iyi oluyor. :)

Henüz yolun başındayken, kod yazma disiplininden taviz vermemeniz ve bu disiplini bir alışkanlık haline getirebilmeniz için, izninizle birkaç tavsiyem olacak.

Bu foruma post edilen herşey aslında 'arşiv' niteliğinde. Buraya yazdığımız kodların ileride 'referans' olarak kullanılabilmesi için, post edilenlerin mümkün olduğunca düzgün ve eksiksiz olmasında fayda var diye düşünüyorum.

Bu bağlamda;
  • Comment'lerin detaylı yazılmasında,
  • Code/Comment ilişkisinin doğru ve eksiksiz olarak uyum sağladığına emin olmakta,
  • Label isimlerinin 00, 01, xx yerine, 'ne iş yaptığı çok daha net anlaşılır' nitelikte yazılmasında,
  • Kodun kolaylıkla çalıştırılabilmesi için Copy/Paste edileceği düşünülerek, gerekli tüm Assembler direktiflerinin (include, org, vs.) koda eksiksiz olarak eklenmesinde (Bu konuda hades hocamın büyük bir titizlikle yazdığı Z80 kodlarını örnek alabilirsiniz. Arzu ederseniz birkaç post üstte yazdığım Invert character 'A' kodundaki formata da tekrar bakabilirsiniz),
  • Ve elbette, tıpkı sizin yaptığınız gibi, kodun çalışması için gereken tüm dosyaların mesaj ekinde sunulmasında,
biraz daha titiz davranabilirsek, bizden sonra bu sayfaları ziyaret edeceklere faydamız olabilir.

*NOT: RAAT#5'te sabaha karşı 04:00 sularında "İsterseniz bug'ı bulmanıza yardım edeyim!" diyerek gıcır gıcır bilgisayarınızın başına sinsice (!) oturmam, Z80 Assembler karşısında saatlerce sizi esir almam, üstüne de Skate'in önerdiği colour trick'i gözümden uyku akarak kodlamam hususunda gösterdiğiniz hoşgörü ve sabır için teşekkür ederim.

Çevrimdışı Fero

  • RAAT
  • Retroman
  • *
  • İleti: 34
  • guy.brush
    • Ferhat Tanman
Ynt: CPC'de Assembler ile imtihanım...
« Yanıtla #32 : 04 Ocak 2019, 12:05:24 »
Teşekkürler! Henüz tüm yapabildiğim çalıp çırptığım kodların nasıl çalıştığını anlamak ve değiştirmekten ibaret olduğundan, pek öyle kodluyormuş gibi hissetmiyorum. Yazım disiplini konusunda çok haklısınız. Daha dikkatli ve titiz olmaya gayret edeceğim.

*NOT: RAAT#5'te sabaha karşı 04:00 sularında "İsterseniz bug'ı bulmanıza yardım edeyim!" diyerek gıcır gıcır bilgisayarınızın başına sinsice (!) oturmam, Z80 Assembler karşısında saatlerce sizi esir almam, üstüne de Skate'in önerdiği colour trick'i gözümden uyku akarak kodlamam hususunda gösterdiğiniz hoşgörü ve sabır için teşekkür ederim.

Aksine bende bir anlığına "adamı resmen bağladım buraya, içinden bana küfrediyor olabilir" diye bir düşünceye kapılmıştım. Bilgisayarın başına geçmenizden de çok büyük mutluluk duydum. İşin üstatlarını problem çözerken canlı olarak izlemekten daha iyi ve keyifli bir öğrenme yöntemi düşünemiyorum. Ancak raat öncesinde de uykusuz bir gece geçirdiğimden, kodda olan biteni algılamakta ve doğru soruları sormakta biraz zorlandım. Yine de benim için muhteşem bir deneyimdi. Ben teşekkür ederim :)


"Never pay more than 20 bucks for a computer game."

Çevrimdışı Fero

  • RAAT
  • Retroman
  • *
  • İleti: 34
  • guy.brush
    • Ferhat Tanman
Ynt: CPC'de Assembler ile imtihanım...
« Yanıtla #33 : 06 Ocak 2019, 07:53:25 »
Geceleri uyku tutmayınca hemen CPC 'ye sarıyorum. Bugün bakalım iyice anlayabilmiş miyim diye biraz kendimi zorlamaya karar verdim. Ekranı sol üstten ve sağ alttan aynı anda silecek bir kod yazmak için kolları sıvadım. Zorlu birkaç saatin ardından ilk satırları güzelce temizleyebildim ancak 2. satırlara başladığında sağ altta işler epey karıştı. Koda yazdığım commentlerde detaylı şekilde aklımdan geçenleri anlatmaya çalıştım. Umarım becerebilmişimdir.

Son satırlardaki POP HL ve SBC HL,DE satırlarını açtığımda garip bir şekilde düzgün silinen üst taraf ta bozuluyor. Screen memory ile ilgili birşeyleri kaçırıyor olabilirim. Bir de interrupt'ı açıp kapatmanın bunun gibi basit birşeyi nasıl ve neden etkilediğini anlayamadım.

İlerleme kat edemiyorum, bari yazım şekline dikkat edeyim de üstatları kızdırmayayım dedim  ;)

Kod: [Seç]
;---------------------------------------------------------------------------------------;
; ;
;      CPC - CIFT YONLU DIKEY SILME DENEMESI - 1 ;
;       06.01.2019 / F3R0 ;
; ;
;---------------------------------------------------------------------------------------;

TOP_LINE equ &c000
BOT_LINE equ &ff80

org &8000

di ;Interrupt'lari kapatirsak ust taraf 1 satir = 8 dizi fazladan siliyor.

;-------------------------------- Ekrani dolduruyoruz ----------------------------------;

DrawImage:
ld    hl,&c000
        ld    de,&c000+1 ;Ekrani kirmizi renk ile
        ld    bc,16384 ;dolduruyoruz.
ld    (hl),255
ldir

;----------------------------------- On hazirliklar ------------------------------------;

ld hl,TOP_LINE ;Yukaridan silme baslangic adresi
exx
ld hl,BOT_LINE ;Asagidan silme baslangic adresi
exx
;Bunun sonucunda HL=&C000, HL'=&FF80
;olarak tanimlamis oluyoruz. Shadow
;registerlari degistirerek bir alttaki
;adresten, bir ustteki adressten silerek
;ilerleyecegim.

VerticalLines: ld a,12 ;Toplam silinecek satir sayisi /2
VerticalRows: ld c,8 ;Her satir arasinda 8 dizi var.

exx ;; Stack dan daha sonra istedigim sirada
push hl ;; cekebilmek icin 2 kere shadowlar ile
exx ;; degistirip push yaptim. Boylece
push hl ;; stack: 1.top_line 2.bot_line
;; seklinde siralandi.

RowLength: ld b,80 ;Bir dizideki toplam byte. 1 byte = 2 pixel
;silinecek alanin yatay uzunlugu.

;--------------------------------- Dizileri siliyoruz ----------------------------------;

ClearRows: ld (hl),0 ;;HL deki mevcut TOP_LINE (&c000) adresinin
inc hl ;;ilk byte'i siliniyor. Bir arttiktan sonra
exx ;;shadow register'lar ile degistiriliyor.
ld (hl),0 ;;Boylece HL deki mevcut adress BOT_LINE (ff80)
inc hl ;;oluyor. Ayni sekilde ilk byte 'i silinip
exx ;;bir arttirildiktan sonra dizideki toplam byte
ld d,100 ;;kadar tekrar ediyor.
Delay: dec d
jr nz,delay ;;Her tekrarda bir miktar bekletiyorum.
djnz ClearRows ;;80. tekrardan sonra devam.

NextRow: ld de,2048-80 ;;Mevcut adresi 80 byte sildik. Bir sonraki
add hl,de ;;dizinin basina ulasmak icin, 2048 ekleyip,
;;80 geri geliyorum.

exx ;;HL 'ye alttaki adresi aldim.

ld de,2048+80 ;;Alttan silinen dizide de ters yonde silerek
sbc hl,de ;;asagidan yukari ilerledigimiz icin tam
;;tersini yapiyorum.
exx
dec c
jr nz,RowLength

;--------------------------------- Satirlari siliyoruz ---------------------------------;

;;8 diziyide sildikten sonra bir sonraki satira
NextLine: ;;geciyoruz. Bunun icin HL 'deki mevcut adrese
pop hl ;;asagiya gitmek icin +80, yukari gitmek icin-80
ld de,80 ;;verecegim.
add hl,de
;pop hl ;;....
;sbc hl,de ;;...
dec a ;;..
jr nz,VerticalRows ;;.


halt

"Never pay more than 20 bucks for a computer game."

Çevrimdışı matahari

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 209
    • The Blog of Mert Börü
Ynt: CPC'de Assembler ile imtihanım...
« Yanıtla #34 : 06 Ocak 2019, 13:56:10 »
Son satırlardaki POP HL ve SBC HL,DE satırlarını açtığımda garip bir şekilde düzgün silinen üst taraf ta bozuluyor.

Çünkü sorun(lar) sözünü ettiğiniz son satırlarda.

NextLine etiketiyle başlayan bölümde;

-Bug#1: HL'yi POP edip, üstüne 80 ekleyerek bir sonraki satıra geçiyorsunuz, ama elde ettiğiniz bu değeri saklamayı (EXX ile shadow register setine switch etmeyi) unutuyorsunuz. Bir sonraki POP komutu, hesapladığınız mevcut değerin üzerine yazıyor.

-Bug#2: Aynı sorun ikinci POP işlemi için de geçerli, yine EXX yapmayı unutuyorsunuz.

-Bug#3: EXX komutu HL, DE, BC ve onların shadow'larını etkiler. LD DE,80 komutu ile yüklediğiniz değer EXX komutu ile birlikte shadow DE register'ına gidiyor, onun değeri de mevcut DE'ye geliyor. Yüklediğiniz 80, diğer DE register'ında kalıyor. Bu yüzden DE'yi tekrar 80'e eşitlemeniz gerekiyor.

Doğrusu şöyle olacak:

Kod: [Seç]
...

NextLine: pop hl
ld de,80
add hl,de
exx
pop hl
ld de,80
sbc hl,de
exx
dec a
jr nz,VerticalRows

...

Bir de interrupt'ı açıp kapatmanın bunun gibi basit birşeyi nasıl ve neden etkilediğini anlayamadım.

Hmmmm... Evet bu başlı başına bir sorun. Eğer interrupt'ları açık bırakırsanız, her interrupt ile birlikte arkaplanda bir sürü firmware CALL yapılır. Bu routine'ler, mevcut DL, DE ve BC register değerlerini bozmamak için shadow register'ları kullanır. Bu yüzden ilk firmware CALL sonrasında, sizin shadow register değerleriniz buhar oluyor. Eğer EXX komutunu kullanacaksanız, (ihtiyaca göre geçici ya da kalıcı olarak) interrupt'ları kapatmanız gerekir.

İlerleme kat edemiyorum, bari yazım şekline dikkat edeyim de üstatları kızdırmayayım dedim  ;)

:)

Yok canım, estağfurullah. Kızmak diye birşey söz konusu değil.

Bu kadar detaylı comment'ler yazmanız çok iyi olmuş. Açıkcası, neyi/nasıl yapmak istediğinizi tam olarak bilemediğim için, yukarıdaki bug'ları yazdığınız comment'leri takip ederek yakaladım diyebilirim. Elinize sağlık!

Çevrimdışı hades

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 179
Ynt: CPC'de Assembler ile imtihanım...
« Yanıtla #35 : 06 Ocak 2019, 14:40:30 »
Ferhat'a yardımcı olayım dedim ve yapmak istediği efekti kodladım. Açıklamalar yardımcı olur umarım.

Kod: [Seç]
org &8000

; di ;Interrupt'lari kapatirsak ust taraf 1 satir = 8 dizi fazladan siliyor.

;-------------------------------- Ekrani dolduruyoruz ----------------------------------;

DrawImage:
ld    hl,&c000
        ld    de,&c000+1 ;Ekrani kirmizi renk ile
        ld    bc,16383 ;dolduruyoruz.
ld    (hl),255
ldir
;----------------------------------- On hazirliklar ------------------------------------;

;***************************************************************************************
ld ix,&c000 ;ust
ld hl,&ff80 ;alt

ld a,12 ;ekran satir sayisi/2
clear_new_line push ix ;bir sonraki satir hesaplamasi
push hl ;icin yiginda sakliyoruz
ld c,8 ;bir karakter satirindaki pixel sayaci
new_pixel_line ld b,80 ;kolon sayaci
clear_a_pixel_line ld (hl),0 ;ust tarafi temizle
ld (ix+0),0 ;alt tarafi temizle
inc hl
inc ix
djnz clear_a_pixel_line
;---------------------------------------------------------------
; yeni pixel satirina gecmeden once bekleyelim
;---------------------------------------------------------------
ld de,&1000 ;gecikme sayaci
delay00 dec de
ld a,d
or e
jr nz,delay00
;---------------------------------------------------------------
; yeni pixel satirlari icin hesaplamalar
;---------------------------------------------------------------
ld de,2048-80 ;yeni ust satir icin fark (&07b0)
add ix,de ;ornek c050+07b0=c800
ld de,2048+80 ;yeni alt satir icin fark (&0850)
sbc hl,de ;ornek ffd0-0850=f780
dec c ;pixez satir sayacini 1 azalt
jr nz,new_pixel_line
;---------------------------------------------------------------
; yeni karakter satiri icin hesaplamalar
;---------------------------------------------------------------
pop hl ;alt adresi geri al
pop ix ;ust adresi geri al
ld de,80 ;adresler arasi fark
add ix,de ;yeni ust satir icin +80
sbc hl,de ;yeni alt satir icin -80
dec a
jr nz,clear_new_line
halt

Bu arada ufak bir ekleme yapayım.

ld hl,&c000
ld de,&c000+1
ld bc,16384
ld (hl),255
ldir

komutlarında BC=16383 olması daha iyidir. Cünkü 16384 döngü sonunda HL=FFFF iken DE=0000 olacak ve ldir komutu nedeniyle 0000 adresine 255 yüklenecektir. Dolayısıyla &0000'ki restart rutini &FF ile başlamış olacaktır.

Çevrimdışı Fero

  • RAAT
  • Retroman
  • *
  • İleti: 34
  • guy.brush
    • Ferhat Tanman
Ynt: CPC'de Assembler ile imtihanım...
« Yanıtla #36 : 06 Ocak 2019, 16:05:43 »
@matahari, bunu düşünemediğime inanamıyorum. Hemde debug'la da defalarca üzerinden geçmeme rağmen! Halbuki işin başında shadow registerları nasıl kullanacağıma epey bir kafa yormuştum. Neyse, en azından çalışan bir kod yazmaya çok yaklaşmışım. Bu da benim açımdan sevindirici oldu :)

@hades, harikasın! Aynı işi farklı bir yöntemle görünce şimdi bazı şeyler kafamda daha da iyi oturdu. Her nasılsa, IX register'ında add ix,de şeklinde bir kullanımın hatalı olduğu yanılgısına kapılıp, shadow register'lara başvurmaya karar vermiştim. Eğer sen bu kodu paylaşmasaydın muhtemelen bir yerlerde kullanımı dikkatimi çekene kadar durumun farkına varmayacaktım.

Çok teşekkürler ikinize de, sizin de ellerinize sağlık!
"Never pay more than 20 bucks for a computer game."

Çevrimdışı matahari

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 209
    • The Blog of Mert Börü
Ynt: CPC'de Assembler ile imtihanım...
« Yanıtla #37 : 06 Ocak 2019, 23:10:24 »
Süpeeeeer! hades'in kodu 3 byte daha kısa. Elinize sağlık hocam! :)

Bu aşamada elimizde, aynı işi farklı yöntemlerle yapabilen iki routine'imiz oldu. Yazım tekniği açısından, her ikisi için de 'size optimization' odaklı diyebiliriz. Peki, bu kodlar daha kısalır mı? Elbette. Gerek var mı? Bence yok, çünkü burada amaç ekran silme algoritmasının nasıl çalışacağını pseudo-code mantığı ile örneklemek.

Neden 'pseudo-code' terimini kullandım?

Çünkü bu routine'leri bir oyun/demo içerisinde kullanmaya kalkarsak;
  • Silme işleminin yavaş olması,
  • Performans odaklı bir işlem için, Z80'in en ağır çalışan register'ları olan IX/IY'nin kullanılması,
  • Neredeyse tüm Z80 register'larının kullanılması sebebiyle diğer routine'ler için PUSH/POP kullanımı dışında seçenek bırakılmaması,
  • Shadow register kullanımı sebebiyle tüm interrupt'ların kapatılması,
  • Interrupt'ların kapatılması nedeniyle, interrupt tabanlı hiçbir işin yapılamaması,
  • Her frame'de ekran temizleme işlemi için kullanılan bekleme süresinin dummy loop ile geciktirilmesi sebebiyle CPU'nun o sırada başka iş yapamaması,
ve benzeri sebeplerle, bu tarz kodlamanın başımıza çok iş açacağını şimdiden öngörebiliriz.

Bu bağlamda, yukarıda saydığım sorunların nasıl giderileceğine yönelik örnek bir kod yazdım. İşlevsel olarak, hades ve Fero'nun yazdığı kodlarla birebir aynı işi yapıyor.

Bonus olarak,
  • Interrupt'ları kapatmıyor. (Ekran silinirken arka planda interrupt tabanlı raster effect çizmek veya müzik çalmak mümkün.)
  • Interrupt'lar ile çakışacak shadow register setini ve hantal IX/IY register'larını kesinlikle kullanmıyor. (Sadece HL, DE, BC, AF ve AF' register'larını kullanıyor.)
  • Ekran silme yöntemi olarak, Z80 üzerinde bilinen en hızlı yöntemi uyguluyor. Ekran hafızasını 'stack' olarak kullandığı için, bir PUSH komutu ile toplam 11 t-state içerisinde hem 2 byte siliyor, hem de destination adresini eksiltiyor. (bkz: Robocop)
  • Ekran silme işlemi dışında kesinlikle PUSH/POP kullanmıyor.
  • Hiçbir CPU cycle boşa harcanmıyor, ekran bekleme tamamen VSYNC ile yapılıyor. Ekran silmeden artakalan tüm zaman dilediğinizce kullanılabiliyor. - (Böylece RAAT#5 sırasında Skate'in sorduğu "Amstrad üzerinde vertical blanking nasıl yakalanıyor?" sorusunu örnekleyerek yanıtlamış oldum.)
  • Uygulanan yöntem/teknikler, Z80 işlemcili tüm 8-bit retro bilgisayarlarda kullanılabiliyor. - (Evet Ref, ZX Spectrum'da da kullanılabilir. ;))
Eğer gerçek anlamda bir oyun/demo kodlaması yapılacaksa, bu tür bir teknik kullanılmasında fayda var. Zira, bu minimalist kod tamamen 'hız odaklı'. Gerekmedikçe hiçbirşeyi kapatmıyor/kullanmıyor.

Daha kısası/hızlısı yazılabilir mi? Elbette mümkün, o konuda bir iddiam yok.

Amacım, gerçek hayatta bu tür bir kodun nasıl yazıldığına dair bir 'şablon' sunabilmek. Umarım size yeni bir pencere açabilmişimdir.

Kod: [Seç]
LET ADDR_CodeExec = &4000
LET ADDR_ScrFirstLine = &c000
LET ADDR_ScrLastLine = &ff80

;----------------------------------------------------------------------
; Fast bidirectional screen cleaning routine v1.2
; for Amstrad 464/664/6128 computers
;
; (c) matahari - (Jan 06, 2019)
;----------------------------------------------------------------------

run CodeExec
org ADDR_CodeExec

CodeExec: ;------ Generate a dummy interrupt handler ----------------------------

di ; Disable interrupts
im 1 ; Interrupt mode = 1
ld hl,&c9fb ; Interrupt handler = EI,RET
ld (&0038),hl ; Overwrite interrupt vector

;------ Fill whole screen with red pixels -----------------------------

ld hl,ADDR_ScrFirstLine ; Screen addr to fill
ld de,ADDR_ScrFirstLine + 1
ld bc,16383 ; Number of bytes to fill
ld (hl),255 ; Colour = Red
ldir ; Memory fill using LDIR

;------ Press any key to continue -------------------------------------

call &bb18 ; Wait for a key!

;**********************************************************************
; MAIN LOOP - INITIALIZE!
;**********************************************************************

push bc ; Due to LDIR, BC=0. Save it!
pop af ; Load &0000 (16-bit) to AF
ex af,af' ; Save clean AF to AF'
ld hl,ADDR_ScrFirstLine + 80 ; Set addr of first upper line
ld de,ADDR_ScrLastLine  + 80 ; Set addr of last lower line
ld c,13 ; Number of char loop

;**********************************************************************
; MAIN LOOP - BEGIN
;**********************************************************************

LoopFillChars: ld b,8 ; Number of pixels in a char

LoopFillLines: ld a,b
ld (Buffer8bit),a ; Save B
ei ; Enable interrupts, and give
; some time to interrupt
; driven routines to breathe!

;------ Check for vertical blanking -----------------------------------

ld b,&f5 ; PPI port B
WaitVBlanking: in a,(c) ; Read current value from port
rra ; bit 0 -> carry
jr nc,WaitVBlanking ; If bit 0=1 then VSYNC is OK,
; else try again...

halt ; You may replace these two
halt ; instructions with your
; favourite music player ;-)

di ; Disable interrupts, again!
ld a,(Buffer8bit)
ld b,a ; Restore B

;------ Fill upper line -----------------------------------------------

ex af,af' ; Get clean AF from AF'
ld sp,hl ; Stack = UPPER LINE ADDRESS

REPEAT 40 ; Paste 'PUSH AF' for 40 times
push af ; Poke clean AF to screen
REND ; End paste

;------ Fill lower line -----------------------------------------------

ex de,hl ; Swap HL and DE values
ld sp,hl ; Stack = LOWER LINE ADDRESS

REPEAT 40 ; Paste 'PUSH AF' for 40 times
push af ; Poke clean AF to screen
REND ; End paste

ex af,af' ; Save clean AF to AF'

;------ Calculate next line addresses ---------------------------------

ld sp,2048-1
sbc hl,sp ; Lower line
ex de,hl ; Swap HL and DE values
inc sp
add hl,sp ; Upper line

djnz LoopFillLines ; Decrease B, and loop
; for all pixels in a char

;------ Calculate next char addresses ---------------------------------

ld sp,2048*8-81
sbc hl,sp ; Upper line
ex de,hl ; Swap HL and DE values
inc sp
add hl,sp ; Lower line
ex de,hl ; Swap HL and DE values

dec c ; Decrease C,
jr nz,LoopFillChars ; and loop for all chars

;**********************************************************************
; MAIN LOOP - END
;**********************************************************************

LoopForever: jr LoopForever

Buffer8bit: db 0


Release Notes:

v1.0
  • Orijinal sürüm
v1.1
  • Buffer okuma/yazma işlemi 16-bit'ten 8-bit'e indirildi. Böylece, hem kod 1 byte kısaldı, hem de 2 raster line (upper + lower) için toplam 40 t-state süren buffer okuma/yazma işlemi 34 t-state'e indi. Aslında I register'ını geçici bir değişken olarak kullanıp 8 t-state daha kazanmamız mümkün, ama hantal IX/IY register setini "performans gerektirmeyen" interrupt tabanlı başka bir iş için kullanma ihtimalimizi düşünerek, bu aşamada aşırı kontrollü davranıyorum. - (*NOT: Normal koşullarda, aslında böyle bir buffer kullanmamıza hiç gerek yok. Çok daha hızlı bir yöntem olan PUSH/POP yapmamız yeterli. Ancak, temizleme işlemini çok hızlı yapabilmek amacıyla ekran hafızasını Stack olarak kullandığımız için, tüm silme işlemi sırasında hiç PUSH/POP yapmamamız gerekiyor. Silme işlemi bittikten sonra, isteğe bağlı olarak normal SP kullanımına geri dönülebilir.)
v1.2
  • Başlamak için herhangi bir tuşa basmanızı bekleyen firmware call eklendi. WinApe sorunlu bir emülator, bazen refresh etmekte gecikebiliyor. Ekranı fill ettikten sonra refresh için biraz zaman tanımamız, sanırım WinApe açısından daha iyi oldu.

Çevrimdışı hades

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 179
Ynt: CPC'de Assembler ile imtihanım...
« Yanıtla #38 : 07 Ocak 2019, 00:04:43 »
Bir efekt için 3 farklı rutin. Çok güzel kodlar bunlar. cpc donanımına henüz tam olarak hakim olmadığım için yolun başındayım diyebilirim, ancak Fero'daki öğrenme ve bir şeyler üretmeye olan hevesi, gayreti beni de gaza getiriyor.

Bu arada naçizane bir öneri olarak;

push   bc            ; Due to LDIR, BC=&00. Save it!
pop   af

komutları yerine XOR A yazarak hem A'yı sıfırlamış oluruz, hem de kod 1 byte daha kısalmış olur. Ayrıca PUSH-POP ikilisinin harcadığı zamandan kurtulmuş oluruz.

Çevrimdışı matahari

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 209
    • The Blog of Mert Börü
Ynt: CPC'de Assembler ile imtihanım...
« Yanıtla #39 : 07 Ocak 2019, 00:16:20 »
Bir efekt için 3 farklı rutin. Çok güzel kodlar bunlar. Fero'daki öğrenme ve bir şeyler üretmeye olan hevesi, gayreti beni de gaza getiriyor.

Bunu duyduğuma çok sevindim. Yeni kodlarınızı heyecanla bekliyoruz. 8)

Bu arada naçizane bir öneri olarak;

push   bc            ; Due to LDIR, BC=&00. Save it!
pop   af

komutları yerine XOR A yazarak hem A'yı sıfırlamış oluruz, hem de kod 1 byte daha kısalmış olur. Ayrıca PUSH-POP ikilisinin harcadığı zamandan kurtulmuş oluruz.

Tavsiyeniz için çok teşekkür ederim. Sıkça kullandığım bir yöntemdir, ve fakat burada maalesef bir işe yaramıyor. Amacım sadece A'yı sıfırlamak değil, hem A hem de F'yi sıfırlamak. 16-bit'lik AF register'ının tamamı sıfır olacak ki, tek PUSH AF komutu ile 2 byte birden silebileyim. ;)

Bildiğim kadarıyla, Z80 mimarisinde F register'ına LD komutu ile erişmek mümkün değil. F'ye 8-bit bir değer yüklemenin tek yolu, yüklenecek değeri POP etmek.

Çevrimdışı Fero

  • RAAT
  • Retroman
  • *
  • İleti: 34
  • guy.brush
    • Ferhat Tanman
Ynt: CPC'de Assembler ile imtihanım...
« Yanıtla #40 : 07 Ocak 2019, 02:18:45 »
Şahanesiniz. Matahari'nin son paylaştığı kodu anlayabilmem için z80 heaven 'da biraz zaman geçirmem gerekecek. :)
"Never pay more than 20 bucks for a computer game."

Çevrimdışı matahari

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 209
    • The Blog of Mert Börü
Ynt: CPC'de Assembler ile imtihanım...
« Yanıtla #41 : 07 Ocak 2019, 17:00:05 »
Matahari'nin son paylaştığı kodu anlayabilmem için z80 heaven 'da biraz zaman geçirmem gerekecek. :)

Aynı tekniği kullanan basit bir örnek, konuyu daha hızlı kavramanıza yardımcı olabilir. ;)

Kod: [Seç]
LET ADDR_CodeExec = &4000
LET ADDR_ScrFirstPixel = &c000
LET ADDR_ScrMemoryEnd = &ffff + 1

LET CONST_InitialColour = &ff
LET CONST_ClearColour = &0000

;----------------------------------------------------------------------
; Fast screen clear/fill routine v1.0
; for Amstrad 464/664/6128 computers
;
; (c) matahari - (Jan 07, 2019)
;----------------------------------------------------------------------

run CodeExec
org ADDR_CodeExec

CodeExec: ;------ Generate a dummy interrupt handler ----------------------------

di ; Disable interrupts
im 1 ; Interrupt mode = 1
ld hl,&c9fb ; Interrupt handler = EI,RET
ld (&0038),hl ; Overwrite interrupt vector

;------ Fill whole screen with a single colour (for test purpose) -----

ld hl,ADDR_ScrFirstPixel ; Screen addr to fill
ld de,ADDR_ScrFirstPixel + 1
ld bc,16383 ; Number of bytes to fill
ld (hl),CONST_InitialColour ; Fill using this colour
ldir ; Memory fill using LDIR

;------ Press any key to continue -------------------------------------

call &bb18 ; Wait for a key!

;**********************************************************************
; MAIN LOOP - INITIALIZE! - (Only SP,DE,B registers are used!)
;**********************************************************************

ld (OldSP),sp ; Save current SP value
ld sp,ADDR_ScrMemoryEnd ; SP = screen end addr
ld de,CONST_ClearColour ; Clear using this colour
ld b,128 ; Number of times to loop

;**********************************************************************
; MAIN LOOP - BEGIN
;**********************************************************************

LoopClear: REPEAT 64 ; Paste 'PUSH DE' for 64 times
push de ; Poke clear colour using DE
REND ; End paste

djnz LoopClear ; Decrease B, Loop B times

; 1 PUSH pokes 2 bytes on scr
; 2 bytes * 64 PUSH * 128 times
; => 16384 bytes

;**********************************************************************
; MAIN LOOP - END - (Back to normal life)
;**********************************************************************

ld sp,(OldSP) ; Restore previous SP value
ei ; Enable interrupts

LoopForever: jr LoopForever

OldSP: dw 0


Çevrimdışı hades

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 179
Ynt: CPC'de Assembler ile imtihanım...
« Yanıtla #42 : 07 Ocak 2019, 22:42:38 »
Kodlamalara devam.

Kod: [Seç]
;---------------------------------------------------------------;
; CPC RUTINI #06 - EKRAN EFEKTI #03 ;
; PIXEL PIXEL YATAY EKRAN KOPYALAMA ;
; (C) 06-01-2019 / HADES ;
;---------------------------------------------------------------;
; Bu rutin hafizadaki ekran goruntusunu pixel satirlari
; seklinde ekran belleginin pixel satirlarina kopyalar
;===============================================================;
run start
org &8000
;===============================================================;
; ekran modunu ayarla ve renkleri duzenle
;===============================================================;
start call &bc14 ;firmware cls
di
setmode ld bc,&7f00
ld a,%10001100
out (c),a
ld de,PaletteArray
pcolor out (c),c
ld a,(de)
inc de
out (c),a
inc c
bit 4,c
jr z,pcolor
ld bc,&7f10 ;select border
out (c),c
ld bc,&7f54 ;set border colour to black
out (c),c
;===============================================================;
call effect_03
halt
;===============================================================;
PaletteArray db &54,&4b,&43,&44,&4e,&4c,&5c,&5b
       ;blk;wht;yel;dbl;org;brd;red;lcy
db &57,&55,&45,&46,&40,&58,&4b,&54
       ;lbl;blu;pur;cya;gry;mgn;bmg;blk

;---------------------------------------------------------------;
; EFEKT RUTINI BURADAN BASLIYOR
;---------------------------------------------------------------;
effect_03 ld ix,&4000 ;hafizada saklanan ekran
ld iy,&c000 ;default ekran bellegi
ld h,25 ;ekrandaki karakter satiri sayaci
next_line push ix ;ix registerini yigina sakla
push iy ;iy registerini yigina sakla
;===============================================================;
; hafizadan o anki pixel satirini kopyala
;===============================================================;
ld c,8 ;kopyalanacak pixel satir sayaci
next_pixel ld b,80 ;bir pixel satirindaki byte sayisi
next_byte ld a,(ix+0) ;hafizadaki ekrandan bir byte oku
ld (iy+0),a ;default ekrana bellegine yaz
inc ix ;hafizadaki ekran adresini 1 arttir
inc iy ;default ekran adresini 1 arttir
djnz next_byte ;80 byte kopyalanincaya kadar tekrarla
;===============================================================;
; biraz bekleyelim
;===============================================================;
ld de,&0400
bekle dec de
ld a,d
or e
jr nz,bekle
;===============================================================;
; bir alttaki pixel satiri icin hesapla
;===============================================================;
ld de,2048-80 ;bir sonraki pixel satiri icin adres farki
add ix,de ;yeni pixel satirinin adresini hesapla
add iy,de ;yeni pixel satirinin adresini hesapla
dec c ;pixel satir sayacini 1 azalt
jr nz,next_pixel ;0 oluncaya kadar islemleri tekrarla
;===============================================================;
; bir sonraki karakter satiri icin islem yap
;===============================================================;
pop iy ;iy registerini yigindan geri al
pop ix ;ix registerini yigindan geri al
ld de,80 ;bir sonraki karakter satiri icin adres farki
add ix,de ;yeni karakter satirinin adresini hesapla
add iy,de ;yeni karakter satirinin adresini
dec h ;karakter satiri sayacini 1 azalt
jr nz,next_line ;0 oluncaya kadar islemleri tekrarla
ret
;===============================================================;
org &4000

screen incbin "BatR2.scr"
;===============================================================;