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 podprogramu
26. 7. 2023, 21:55 editováno autorem komentáře