Z kapitoly 7:
Poznámka2: dokážete přijít na to, za jakých podmínek a zda vůbec NEbude vykreslovací rutina korektní?
Moje reseni: Emork ohot ez es ejurtesoen yndaz z ujarko ykvozarbo, kat ot etsej ezles v udohcerp nitert a ot zu ej aklev teslob, ezotorp yt ejarko es ijad tiser i mit ez es ilserkyv avon akvozarbo. Ela aretkolam arh am ukvozarbo nej rtinvu ynitert.
Jinak ten kod:
draw_sprite:
ld hl, SPRITE_ADR ; 3:10 adresa, od níž začíná maska spritu
push de ; 1:11
call draw_8_lines ; 3:17 vykreslit prvních 8 řádků spritu
pop de ; 1:10
add_e 32 ; 3:15 zvýšit E o hodnotu 32
push de ; 1:11
call draw_8_lines ; 3:17 vykreslit druhých 8 řádků spritu
pop de ; 1:10
add_e 32 ; 3:15 zvýšit E o hodnotu 32
call draw_8_lines ; 3:17 vykreslit třetích 8 řádků spritu
ret ; 1:10 návrat z podprogramu
;[23:143]
draw_8_lines:
ld b, 8 ; 2:7 počitadlo zapsaných řádků
loop:
ld a,(hl) ; 1:7 načtení jednoho bajtu z masky
ld (de),a ; 1:7 zápis hodnoty na adresu (DE)
inc hl ; 1:6 posun na další bajt masky
inc e ; 1:4
ld a,(hl) ; 1:7 načtení jednoho bajtu z masky
ld (de),a ; 1:7 zápis hodnoty na adresu (DE)
inc hl ; 1:6 posun na další bajt masky
inc e ; 1:4
ld a,(hl) ; 1:7 načtení jednoho bajtu z masky
ld (de),a ; 1:7 zápis hodnoty na adresu (DE)
inc hl ; 1:6 posun na další bajt masky
inc d ; 1:4 posun na definici dalšího obrazového řádku
dec e ; 1:4 korekce - posun zpět pod první osmici pixelů
dec e ; 1:4 dtto
djnz loop ; 2:13/8 vnitřní smyčka: blok s 3x osmi zápisy
ret ; 1:10 návrat z podprogramu
;[19:756=7+8*93-5+10]
By sel napsat rychleji a mensi:
draw_sprite:
...
;[23:143]
draw_8_lines:
ld bc, 8*(256+2) ; 3:10 počitadlo zapsaných řádků
loop:
ldi ; 2:16 [DE++] = [HL++]; BC--
ldi ; 2:16 [DE++] = [HL++]; BC--
ld a,(hl) ; 1:7 načtení jednoho bajtu z masky
ld (de),a ; 1:7 zápis hodnoty na adresu (DE)
inc hl ; 1:6 posun na další bajt masky
dec e ; 1:4 korekce
dec e ; 1:4 korekce
inc d ; 1:4 posun na definici dalšího obrazového řádku
djnz loop ; 2:13/8 vnitřní smyčka: blok s 3x osmi zápisy
ret ; 1:10 návrat z podprogramu
;[16:631=10+8*77-5+10]
A pokud by me restit i ten zasadni problem s korektnosti tak by sel udelat jeste mensi, pokud bude automaticky vracet spravne nastavene DE.
draw_sprite:
ld hl, SPRITE_ADR ; 3:10 adresa, od níž začíná maska spritu
call draw_8_lines ; 3:17 vykreslit prvních 8 řádků spritu
call draw_8_lines ; 3:17 vykreslit druhých 8 řádků spritu
call draw_8_lines ; 3:17 vykreslit třetích 8 řádků spritu
ret ; 1:10 návrat z podprogramu
;[13:71]
draw_8_lines:
ld bc, 8*(256+2) ; 3:10 počitadlo zapsaných řádků
loop:
ldi ; 2:16 [DE++] = [HL++]; BC--
ldi ; 2:16 [DE++] = [HL++]; BC--
ld a,(hl) ; 1:7 načtení jednoho bajtu z masky
ld (de),a ; 1:7 zápis hodnoty na adresu (DE)
inc hl ; 1:6 posun na další bajt masky
dec e ; 1:4 korekce
dec e ; 1:4 korekce
inc d ; 1:4 posun na definici dalšího obrazového řádku
djnz loop ; 2:13/8 vnitřní smyčka: blok s 3x osmi zápisy
ld a, e ; 1:4
add a, 32 ; 2:7
ld e, a ; 1:4
ret c ; 1:5/11
ld a, d ; 1:4
sub 8 ; 2:7
ld d, a ; 1:4
ret ; 1:10 návrat z podprogramu
;[25:647/666 =10+8*77-5+26/10+8*77-5+45]
A kdyz uz spamuji tak rovnou pridam muj skript nakompilaci asm zdrojaku a rovnou spusteni v emulatoru. S tim ze jde parametrem i menit adresa na jakou se to zkompiluje. Staci mit v kodu neco jako:
ifdef __ORG org __ORG else org 0x8000 endif
kde 0x8000 je default ale skript nastavuje __ORG kdyz mu ho zadate. Tim mu i reknete ze to ma spustit v emulatoru a nejen kompilovat binarku.
Neni ani potreba definovat nejaky entry point. Protoze se to zkompiluje jako binarka a pres zmakebas to vytvari z basic loaderu tapku. Loader je nastaven na testovani rychlosti programu.
No ja pri tom narazil na to ze inc/dec reg_8bit nastavuje vlajku p/v! Myslel jsem, ze podteceni nemam jak pomoci inc/dec zjistit a ono to jde... (preteceni je jasne, to se nastavi zero)
A to ani pokud je to v A. Takze jsem celou dobu delal SUB 0x01 misto DEC A... lol. Musim vyzkouset.
Jinak jsem ten kod jeste vylepsil kdyz jsem se na nej ted kouknul. Protoze to pricitani 32 se da udelat pres registr C kdyz je volny.
draw_8_lines:
ld bc, 8*(256+3)+32-3 ; 3:10 počitadlo zapsaných řádků
ld a, e ; 1:4 save E
loop:
ldi ; 2:16 [DE++] = [HL++]; BC--
ldi ; 2:16 [DE++] = [HL++]; BC--
ld a,(hl) ; 1:7 načtení jednoho bajtu z masky
ld (de),a ; 1:7 zápis hodnoty na adresu (DE)
inc hl ; 1:6 posun na další bajt masky
dec e ; 1:4 korekce
dec e ; 1:4 korekce
inc d ; 1:4 posun na definici dalšího obrazového řádku
djnz loop ; 2:13/8 vnitřní smyčka: blok s 3x osmi zápisy
ld a, e ; 1:4
add a, c ; 1:4
ld e, a ; 1:4
ret c ; 1:5/11
ld a, d ; 1:4
sub 8 ; 2:7
ld d, a ; 1:4
ret ; 1:10 návrat z podprogramu
;[24:644/663 =10+8*77-5+26/10+8*77-5+45]
...a pak vyzkousel 3x ldi a vysla uplne nejlepsi rutina jenze... mela drobnou chybku na krase...
Ale i pres opravu te chybky je to nejlepsi reseni. A pokud mas ramecek okolo obrazovky tak muzes ten fix zrusit.
draw_sprite:
ld hl, SPRITE_ADR ; 3:10 adresa, od níž začíná maska spritu
call draw_8_lines ; 3:17 vykreslit prvních 8 řádků spritu
call draw_8_lines ; 3:17 vykreslit druhých 8 řádků spritu
call draw_8_lines ; 3:17 vykreslit třetích 8 řádků spritu
ret ; 1:10 návrat z podprogramu
;[13:71]
draw_8_lines:
ld bc, 8*(256+3)+32-2 ; 3:10 počitadlo zapsaných řádků
ld a, e ; 1:4 save E
loop:
ld e, a ; 1:4 load E
ldi ; 2:16 [DE++] = [HL++]; BC--
ldi ; 2:16 [DE++] = [HL++]; BC--
ldi ; 2:16 [DE++] = [HL++]; BC--
dec de ; 1:6 fix fail pri tisku posledniho znaku v tretine! ldi zvedne D pro kazdy radek...
inc d ; 1:4 posun na definici dalšího obrazového řádku
djnz loop ; 2:13/8 vnitřní smyčka: blok s 3x osmi zápisy
ld a, e ; 1:4
add a, c ; 1:4
ld e, a ; 1:4
ret c ; 1:5/11
ld a, d ; 1:4
sub 8 ; 2:7
ld d, a ; 1:4
ret ; 1:10 návrat z podprogramu
;[24:632/651 =10+8*75-5+26/10+8*75-5+45]
...ale ldi je ti stejne k nicemu pokud budes delat nejake xor .)))
26. 7. 2023, 00:47 editováno autorem komentáře
Vsechno jinak! .) Tak z "detects overflow" z https://clrhome.org/table/ se v originalnim manualu k Z80 vyklubalo ze pokud pred odectenim obsahuje registr hodnotu 0x80, tak se ten priznak nastavi, v ostatnich 255 pripadech se vynuluje.
Takze to dela neco jineho... ale zase existuje dalsi zpusob jak rychle testovat hodnoty 0x80 (dec) nebo 0x7F (inc).
Pridava dalsi slozitost pro hledani optimalnich reseni...
Existuje testovani bitu... 2:8 pokud nas zajima jen 7. bit
Rotace 2:8 pokud nas zajima 0. nebo 7. bit
"sla reg" by u 0x80 nastavila ZERO a CARRY, ale to nejde testovat najednou takze bez pouziti A snad:
rlc reg 2:8
dec reg 1:4
nastavi ZERO jen pri puvodni hodnote 0x80
ld A,reg 1:4
xor 0x80 2:7 nastavi ZERO
atd. atd.
S tim predpripravenim spritu shiftnutych o 0-7 bitu - on by se dal udelat kompromis. Mit 3 vykreslovaci rutiny - jednu ktera by vykreslovala primo ten sprite, druha shiftnuty o 1 doleva, treti by vykreslovala sprite shiftnuty o 1 doprava. Pak by stacilo pripravit jenom 3 predpocitane sprity - shift o 0, 3 a 6 a kombinaci verze spritu a rutiny by se dokazal vykreslit jakkoliv shiftnuty sprite. Shift o jeden bod ten program az tak moc nezpomali, byl by to kompromis mezi rychlosti a mnozstvim zabrane pameti.
Jinak diky za serii clanku, musim opet zamacknout slzu - zx spectrum byl muj prvni computer a hex kody instrukci Z80 znam dodnes zpameti (dnes uz jenom nektere...)
Tak o ZX Spectre som tak mohol snívať. V detstve sme si zaobstarali Didaktik M, čo bol kompatibilný počítač so spectrom. V assembleri som to dotiahol do jednoduchým animácií.
Veľa si toho už ale nepamätám. No marí sa mi, že sa na obrazovke vykresľovala postupne striedavo každá ôsma čiara. 48 KB bolo spolu s 8 KB ROM a ďalej časť patrila obrazovke.
O mnohých detailoch čo sa uvádzajú v článku človek vôbec netušil. Lebo to nemal odkiaľ vedieť. Literatúry bolo minimum, poradiť nemal kto.
Robiť v tom bolo nesmierne náročné. Najmenšia chyba zmrazila počítač a vy ste ho museli resetnúť a znova načítať. Čo mohlo travať možno 5-10 minút.
Vyzkousel jsem jeste rutinu co zabira pro kazdy sprite dvojnasobek pameti, protoze ma pribalenou jeste masku pro mazani sveho okoli.
Kazdy bajt je ulozen jako 16 bitova hodnota. Spodnich 8 bitu je ten sprite a hornich 8 bitu je maska. Nacita se to pres nastaveni SP na adresu spritu.
Na zacatku vykresluji jeste pozadi, aby bylo videt co to dela.
SCREEN_ADR equ $4000
ENTRY_POINT equ $8000
org ENTRY_POINT
start:
ld a, %01010101
ld de, 0x0020
ld hl, 0x4000
ld c, 24
chessboard_pattern:
ld b, 8
ld (hl), a
add hl, de
djnz $-2
cpl
dec c
jr nz, chessboard_pattern
push hl ; 0x5800
finish:
pop hl
ld de, -0x0020
add hl, de
bit 6, h
jr nz, $+5
ld hl, 0x57E0
push hl
ld d, h
ld e, l
inc e
ld a,(hl)
rrca
ld (hl), a
ld bc, 31
ldir ; nakresli jeden pixelovy radek sachoveho pozadi
ld b, 15 ; x-ová souřadnice
ld c, 3 ; y-ová souřadnice
call calc_sprite_address ; výpočet adresy spritu
call draw_sprite
ld b, 29 ; x-ová souřadnice
ld c, 21 ; y-ová souřadnice
call calc_sprite_address ; výpočet adresy
call draw_sprite
jr finish ; žádný návrat do systému
calc_sprite_address:
; parametry:
; B - x-ová souřadnice (ve znacích, ne pixelech)
; C - y-ová souřadnice (ve znacích, ne pixelech)
;
; návratové hodnoty:
; DE - adresa pro zápis bloku
;
; vzor adresy:
; 0 1 0 Y4 Y3 0 0 0 | Y2 Y1 Y0 X4 X3 X2 X1 X0
ld a, c
and %00000111 ; pouze spodní tři bity y-ové souřadnice (řádky 0..7)
rrca
rrca
rrca ; nyní jsou čísla řádků v horních třech bitech
or b ; připočítat x-ovou souřadnici
ld e, a ; máme spodní bajt adresy
; Y2 Y1 Y0 X4 X3 X2 X1 X0
ld a, c ; y-ová souřadnice
and %00011000 ; dva bity s indexem "bloku" 0..3 (dolní tři bity už máme zpracovány)
or %01000000 ; "posun" do obrazové paměti (na 0x4000)
ld d, a ; máme horní bajt adresy
; 0 1 0 Y5 Y4 0 0 0
ret ; návrat z podprogramu
draw_sprite:
ld hl, SPRITE_ADR ; 3:10
ld c, 3 ; 2:7 výška spritu v řádcích
draw_sprite_1:
di ; 1:4
ld (draw_sprite_e+1), sp ; 4:20
ld sp, hl ; 1:6 adresa, od níž začíná maska spritu
ex de, hl ; 1:4
;[12:51]
draw_sprite_2:
ld b, 8 ; 2:7 počitadlo zapsaných řádků
draw_sprite_3:
pop de ; 1:10 ; první sloupec
ld a, (hl) ; 1:7
and d ; 1:4
xor e ; 1:4
ld (hl), a ; 1:7
inc l ; 1:4
pop de ; 1:10 ; druhý sloupec
ld a, (hl) ; 1:7
and d ; 1:4
xor e ; 1:4
ld (hl), a ; 1:7
inc l ; 1:4
pop de ; 1:10 ; třetí sloupec
ld a, (hl) ; 1:7
and d ; 1:4
xor e ; 1:4
ld (hl), a ; 1:7
dec l ; 1:4
dec l ; 1:4
inc h ; 1:4 posun na definici dalšího obrazového řádku
djnz draw_sprite_3 ; 2:13/8 vnitřní smyčka: blok s 3x osmi zápisy
;[22:1027=8*129-5]
dec c ; 1:4
jr z, draw_sprite_e ; 2:7/12
ld a, l ; 1:4
add a, 0x20 ; 2:7
ld l, a ; 1:4
jr c, draw_sprite_2 ; 2:7/12
ld a, h ; 1:4
sub 0x08 ; 2:7
ld h, a ; 1:4
jr draw_sprite_2 ; 2:12
draw_sprite_e:
ld sp, 0x0000 ; 3:10
ei ; 1:4
ret ; 1:10 návrat z podprogramu
SPRITE_ADR
db %00000000, %11111111, %00000000, %11111111, %00000000, %11111111 ; 1
db %00000000, %11111110, %00000000, %00001111, %00000000, %11101111
db %00000001, %11111100, %11110000, %00000111, %00010000, %11000111
db %00000011, %11111000, %00111000, %00000000, %00010000, %11000111
db %00000101, %11110000, %11010111, %00000000, %00010000, %00000111
db %00000101, %11110000, %11001100, %00000000, %00010000, %11000111
db %00000101, %11110000, %00110000, %00000001, %00010000, %11000111
db %00000100, %11110000, %11001000, %00000001, %00010000, %11000111
db %00000111, %11110000, %00110110, %00000000, %00010000, %11000111 ; 2
db %00001100, %11100000, %11111110, %00000000, %00111000, %00000011
db %00011111, %11000000, %11111000, %00000000, %00000000, %00000111
db %00000000, %11100000, %00000000, %00000000, %00110000, %00000111
db %00000011, %11111000, %11111111, %00000000, %10110000, %00000111
db %00000101, %11110000, %11111110, %00000000, %11100000, %00001111
db %00001110, %11100000, %11111101, %00000000, %11000000, %00011111
db %00011000, %11000000, %11111100, %00000000, %00000000, %00111111
db %00011000, %11000000, %00000000, %00000011, %00000000, %11111111 ; 3
db %00000001, %11100100, %11111000, %00000011, %00000000, %11111111
db %00000011, %11111000, %11111100, %00000001, %00000000, %11111111
db %00000001, %11111100, %10110000, %00000011, %00000000, %11111111
db %00000010, %11111000, %00001100, %00000001, %00000000, %11111111
db %00000111, %11100000, %00001110, %01100000, %00000000, %01111111
db %00011110, %11000000, %00000111, %11110000, %10000000, %00111111
db %00000000, %11100001, %00000000, %11111000, %00000000, %01111111
end ENTRY_POINT
Jde to vlastne i rovnou pomoci DE
draw_sprite:
ld hl, SPRITE_ADR ; 3:10
ld c, 3 ; 2:7 výška spritu v řádcích
draw_sprite_1:
di ; 1:4
ld (draw_sprite_e+1), sp ; 4:20
ld sp, hl ; 1:6 adresa, od níž začíná maska spritu
;[11:47]
draw_sprite_2:
ld b, 8 ; 2:7 počitadlo zapsaných řádků
draw_sprite_3:
pop hl ; 1:10 ; první sloupec
ld a, (de) ; 1:7
and h ; 1:4
xor l ; 1:4
ld (de), a ; 1:7
inc e ; 1:4
pop hl ; 1:10 ; druhý sloupec
ld a, (de) ; 1:7
and h ; 1:4
xor l ; 1:4
ld (de), a ; 1:7
inc e ; 1:4
pop hl ; 1:10 ; třetí sloupec
ld a, (de) ; 1:7
and h ; 1:4
xor l ; 1:4
ld (de), a ; 1:7
dec e ; 1:4
dec e ; 1:4
inc d ; 1:4 posun na definici dalšího obrazového řádku
djnz draw_sprite_3 ; 2:13/8 vnitřní smyčka: blok s 3x osmi zápisy
;[22:1027=8*129-5]
dec c ; 1:4
jr z, draw_sprite_e ; 2:7/12
ld a, e ; 1:4
add a, 0x20 ; 2:7
ld e, a ; 1:4
jr c, draw_sprite_2 ; 2:7/12
ld a, d ; 1:4
sub 0x08 ; 2:7
ld d, a ; 1:4
jr draw_sprite_2 ; 2:12
draw_sprite_e:
ld sp, 0x0000 ; 3:10
ei ; 1:4
ret ; 1:10 návrat z podprogramu26. 7. 2023, 21:55 editováno autorem komentáře