Vlákno názorů k článku Vývoj her a dem pro ZX Spectrum: vlastní vykreslovací subrutiny od _dw - Jeste jsem to nedocetl do konce. Budu uplne ignorovat...

  • Článek je starý, nové názory již nelze přidávat.
  • 2. 3. 2023 2:10

    _dw

    Jeste jsem to nedocetl do konce.

    Budu uplne ignorovat pouzivani djnz pro pripady, kdy se to na nahradit jr, protoze se to pouzije 256x a uvnitr smycky je nejaky registr menen tak, ze nastavi zero flag prave a jedine ve stejnou dobu co by se ukoncila smycka.

    Ale dovolil jsem si upravit tu rutinu pro 14. kapitolu. Z puvodnich 53 bajtu na 38 bajtu.
    Jedna z podminek je bud pouzit nejaka makra a nebo slevit z prehlednosti a nepouzivat nejake globalni konstanty jako je adresa tech fontu. Protoze puvodni rutina uplne ignoruje ze je polozena v pameti na adresu delitelnou 256...
    Pak jsem upravil tu funkci pro vypsani znaku tak, aby vracela v DE adresu nasledujiciho znaku (vcetne prelezeni pres tretiny obrazovky), prijde me to jako pouzitelnejsi navrh, nez muset po kazdem vypsanem znaku hledat kde je nasledujici adresa.
    Puvodni:

    SCREEN_ADR      equ $4000
    CHAR_ADR        equ $3c00
    ENTRY_POINT     equ $8000
    
            org ENTRY_POINT
    
    start:
            ld de, SCREEN_ADR        ; 3:10   adresa pro zápis
            ld a, 'A'                ; 2:7    kód vykreslovaného znaku
            call draw_char           ; 3:17   zavolat subrutinu pro vykreslení znaku
    
            ld de, SCREEN_ADR+1      ; 3:10   adresa pro zápis
            ld a, 'B'                ; 2:7    kód vykreslovaného znaku
            call draw_char           ; 3:17   zavolat subrutinu pro vykreslení znaku
    
            ld de, SCREEN_ADR+128+31 ; 3:10   adresa pro zápis
            ld a, '?'                ; 2:7    kód vykreslovaného znaku
            call draw_char           ; 3:17   zavolat subrutinu pro vykreslení znaku
    
    finish:
            ret                      ; 1:10   ukončit program
    
    draw_char:
            ld hl, CHAR_ADR          ; 3:10   adresa, od níž začínají masky znaků
            ld b, 0                  ; 2:7
            ld c, a                  ; 1:4    kód znaku je nyní ve dvojici BC
            sla c                    ; 2:8
            rl b                     ; 2:8    2*bc
            sla c                    ; 2:8
            rl b                     ; 2:8    4*bc
            sla c                    ; 2:8
            rl b                     ; 2:8    vynásobení BC osmi
            add hl, bc               ; 1:11   přičíst adresu k offsetu masky znaku
    
            ld b, 8                  ; 2:7    počitadlo zapsaných bajtů
    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 d                    ; 1:4    posun na definici dalšího obrazového řádku
            djnz loop                ; 2:8/13 vnitřní smyčka: blok s osmi zápisy
            ret                      ; 1:10
    
    end ENTRY_POINT

    Nove:

    SCREEN_ADR      equ $4000
    CHAR_ADR        equ $3c00
    ENTRY_POINT     equ $8000
    
        org ENTRY_POINT
    
    start:
        ld   DE, SCREEN_ADR ; 3:10   adresa pro zápis
        ld    A, 'A'        ; 2:7    kód vykreslovaného znaku
        call draw_char      ; 3:17   zavolat subrutinu pro vykreslení znaku
    
        ld    A, 'B'        ; 2:7    kód vykreslovaného znaku
        call draw_char      ; 3:17   zavolat subrutinu pro vykreslení znaku
    
        ld    E, SCREEN_ADR+4*32+31 ; 2:7   adresa pro zápis (jsme stale v prvni tretine obrazovky)
        ld    A, '?'        ; 2:7    kód vykreslovaného znaku
    ;    call draw_char      ; 3:17   zavolat subrutinu pro vykreslení znaku
    
    finish:
    ;    ret                 ; 1:10   ukončit program
    
    ;    Input: DE = adresa znaku pro zapis, A = znak
    ;   Output: DE = adresa nasledujiciho znaku (muze pretect do atributu)
    ; Pollutes: B = 0, C = hi(old_DE),HL
    draw_char:
        ld   BC, 0x3C00     ; 3:10   adresa, od níž začínají masky znaků
        ld    H, C          ; 1:4
        ld    L, A          ; 1:4    kód znaku je nyní ve dvojici HL
        add  HL, HL         ; 1:11   2x
        add  HL, HL         ; 1:11   4x
        add  HL, HL         ; 1:11   8x
        add  HL, BC         ; 1:11
    
        ld    B, 0x08       ; 2:7    počitadlo zapsaných bajtů
        ld    C, D          ; 1:4
    loop:
        ld    A,(HL)        ; 1:7    načtení jednoho bajtu z masky
        ld  (DE),A          ; 1:7    zápis hodnoty na adresu (DE)
        inc   L             ; 1:4    posun na další bajt masky
        inc   D             ; 1:4    posun na definici dalšího obrazového řádku
        djnz loop           ; 2:8/13 vnitřní smyčka: blok s osmi zápisy
        ld    D, C          ; 1:4
        inc  DE             ; 1:6
        ret                 ; 1:10
    
    end ENTRY_POINT

    PS: Jinak me uplne dostal ten vypis u jr/djnz, kdy jsem si myslel ze 0 ukazuje pred tu instrukci a ona ukazuje za ni. Uplne jsem si to pletl s $, ktera ukazuje prave pred (na prave provadenou/za­pisovanou) instrukci. Takze $ je neco jako 0xFE.

  • 2. 3. 2023 8:22

    Pavel Tišnovský
    Zlatý podporovatel

    Super, díky za doplnění. Můžu tu verzi s add HL, HL hodit do repa pro ostatní? Že bych na tom postavil příklad pro příště?

  • 3. 3. 2023 3:28

    _dw

    Muzes pouzit cokoliv. Pisi to sem, protoze si myslim ze to jde udelat lepe, ne abych trolil. Jsou to jen kousky kodu, ktere uz urcite napsalo spoustu lidi prede mnou a netoci se tu zadne velke penize, takze o nic nejde. Z80 nikoho v podstate uz nezajima asi jako historicky serm. .)

    A nektery kod je na prvni pohled podezrely, to citis hned, ze to pujde napsat lepe, na to by prisel kazdy. Staci aby tam byla nejaka instrukce, jako jsou dvoubajtove s osmi takty a hned to pouta pozornost.

    U nekterych veci citim, ze je to spatne, ale nejde to dokazat. Jako napr.

    ; B - x-ová souřadnice (ve znacích, ne pixelech)
    ; C - y-ová souřadnice (ve znacích, ne pixelech)

    By melo byt prohozene, X v C a Y v B.
    Ted to vypada ze na tom nezalezi, ze je to jen skryta vada. Pokud by si chtel napsat rutinu, kde by vstup mohl mit X vic jak 31 a povazovalo by se to za X = X mod 32, Y = (Y + X /32) mod 24. Tak uz by to bylo poznat.

    Je to stejna chyba (navrhu) jako ze DJNZ ma pocitadlo v B a ne v C. Tam to ale jde dokazat hned, ze je to spatne mit bity s mensi vahou ve vyssim registru.

    PS: Pak jsem si nevsiml, ze bys/nekdo diskutoval nad tim, jakou strategii zvolit pro obsazeni registru, a ktere se budou ve funkcich uchovavat, zda vsechny a nebo jen nektere. Podle me je to dulezita vec mit jednotne pravidla, pokud pises neco co neni na par bajtu.

    Ja jsem prvne ukladal vse na zasobnik a vstupy a vystupy mel v registrech jak se to zrovna hodilo... Variant je ale vic, jestli napriklad chces uchovavat i vstup, protoze se ta fce vola opakovane s nepatrne odlisnym vstupem.

    Forth me ale naucil, ze to jde i uplne jinak, dokonce tak, ze proste i vis nejen co musis uchovat a co je volne, ale i kde mas parametry, bez ohledu na pocet a nemusis to pro kazdou fci hledat.

    Na druhou stranu pokud pouzivas zasobnik "ciste" pro data, tak si komplikujes volani fci a ukladani pocitadel smycek.
    Kdyz to michas tak, mas taky problemy a kdyz mas data na pevnych adresach tak taky.

    Tohle uz nekdo musel pro Z80 resit. Nekdo musel prijit na to, ze:

    - 1 bitovy vystup je nejlepsi mit v carry protoze... setris registr a muzes vysledek pouzit pro skoky, scitani s prenosem atd.?

    - 8 bitovy vystup je nejlepsi mit v A protoze... je velka sance ze uz byl akumulator pro vypocet pouzit a nemusis ho teda uz nastavovat a ani ho nemusis uchovavat kdyz byl menen ale je to vystup?

    - 16 bitovy vystup v HL protoze... viz 8 bitovy vstup.

    Nebo je to nejak uplne jinak a ta funkce neni "nezavisla", ale se pouziva jen jako pomocna fce nejake jine a ta uz ma registry nastavene takhle a takhle takze...

    Mozna staci jakakoliv pravidla, ale hlavne aby byla? I spatna jsou lepsi nez zadna?

    Mozna by sla pouzit nejaka statistika verejnych zdrojaku? Urcite na to existuji nejake strategie. Jen maly navrh na tema clanku.

  • 3. 3. 2023 9:34

    Pavel Tišnovský
    Zlatý podporovatel

    diky. pro jistotu se ptam, aby nebyl problem. Jinak jasne - spoustu tech veci zkusime optimalizovat, ale snazim se aspon prvni verzi udelat trosku citelne a snad i prehledne. Co jsem se dival na kod z nekterych her (i na 6502), tak to uz jsou nekdy brutalne optimalizovane veci, kde se bez popisu proc a jak se to dela, neni moc sance to pochopit.

    (btw budu muset dohledat triky, okolo FP, tam toho bylo hodne a byly dost silene :)