Názor k článku Vývoj her a dem pro ZX Spectrum: vlastní vykreslovací subrutiny podruhé od _dw - Ted jsem si teprve uvedomil, ze v te...

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

    _dw

    Ted jsem si teprve uvedomil, ze v te rutine draw_char je skryta vada. Protoze adresa fontu je zapsana pres promennou CHAR_ADR, aby tam nebyla magic cisla... .)

    Pak tam nemuzeme natvrdo prirazovat do registru H registr C s tim, ze je tam nula. Protoze to tak uz nemusi byt. Kdybych potreboval zmenit fonty a videl na zacatku ze staci zmenit CHAR_ADR a je hotovo, tak bych mozna ani neprochazel kod a nehledal vyskyty, protoze kdyz to vytknu tak to mohu menit.

    Spravne by to melo bys nejak takto:

    ;draw_char_save_bc
    draw_char:
        push hl                  ; uschovat HL na zásobník
      ifdef draw_char_save_bc
        push bc                  ; uschovat BC na zásobník
      endif
        ld    bc, CHAR_ADR       ; adresa, od níž začínají masky znaků
      if CHAR_ADR & 255
          .warning Pouzivas adresu fontu nezarovnanou na segment, to neni nejlepsi napad.
        ld    h, 0x00            ; C je nulové, protože CHAR_ADR=0x3c00
      else
        ld    h, c               ; C je nulové, protože CHAR_ADR=0x..00
      endif
        ld    l, a               ; kód znaku je nyní ve dvojici HL

    K Atarist, muzes to mit ve stinovych registrech, ale taky to neco bude stat. Nejhorsi na tomhle je, ze dopredu nevis co vsechno budes jeste potrebovat. Muzes to delat i tak, ze to budes neustale prepisovat v prubehu jak se budou pozadavky menit a dokud te to bude bavit. (nastesti retroprogramovani je jen hobby programovani).

    Kdyz se kouknes co to dela ted, a jestli je to uzitecne... tak to zatim neni lepsi nez pouzit ROM rutinu pro me. Tam budes mit jen problem s poslednim radkem (predposledni se da osetrit zmenou jedne ROM promenne).

    Tiskneme font v matici 8x8 a nemenime atributy, takze je jasne kam by se to vyvijelo dal. A pokud chceme tisknout atributy, ma smysl to na zacatku pozicovat jako XY? Neni to lepsi pozicovat rovnou jako adresu atributu?

    Pak potrebuji jinou rutinu calc_char_address. To uz nekdo musel resit... .)

    0x5800..0x5AFF
    -->
    0x4000..0x57FF

    00 01 00 11 11 00 Y5 Y4 Y3 Y2 Y1 X5 X4 X3 X2 X1
    -->
    00 01 00 Y5 Y4 00 00 00 Y3 Y2 Y1 X5 X4 X3 X2 X1

    Vypada to, ze to staci segment vynasobit osmi a invertovat 7.bit/vynulovat 7. bit/pricist 0x80.

                   ;[7:27]
    ld    A, ?     ; 1:4
    add   A, A     ; 1:4    2x
    add   A, A     ; 1:4    4x
    add   A, A     ; 1:4    8x
    xor  0x80      ; 2:7
    ld    ?, A     ; 1:4
    
    Varianta pokud neni volne A
                   ;[8:32]
    sla   D        ; 2:8    2x
    sla   D        ; 2:8    4x
    sla   D        ; 2:8    8x
    res   7, D     ; 2:8

    Kod upraveny tak, aby dekodoval v retezci nektere specialni znaky "\n", AT, ink, paper, flash, bright.

    SCREEN_ADR      equ $4000
    CHAR_ADR        equ $3c00
    ENTRY_POINT     equ $8000
    ATTR_T          equ $5C8F
    
    ZX_EOL          equ 0x0D     ; zx_constant   end of line
    
    ZX_INK          equ 0x10     ; zx_constant   colour
    ZX_PAPER        equ 0x11     ; zx_constant   colour
    ZX_FLASH        equ 0x12     ; zx_constant   0 or 1
    ZX_BRIGHT       equ 0x13     ; zx_constant   0 or 1
    ZX_AT           equ 0x16     ; zx_constant   Y,X
    
    ZX_BLUE              EQU %001     ; zx_constant
    ZX_YELLOW            EQU %110     ; zx_constant
    
    
             org ENTRY_POINT
    
    ; Input: x = 0..31
    ;        y = 0..23
    ; Output:
    ;     ld de, 0x4000 + ((0x1F & y ) << 5) + ( 0x1F & x )
    LD_R_XY2addr MACRO _r, _x, _y
        ld _r, 0x5800+((31&(_y))<<5)+(31&(_x))
    ENDM
    
    start:
        LD_R_XY2addr DE,15,12
        ld   HL, TEXT           ; 3:10    adresa prvního znaku v řetězci
    ;    call print_string       ; 3:17    tisk celého řetězce
    
    finish:
    ;    jr finish               ; 2:12    žádný návrat do systému
    
    
    print_string:
        ld    A,(ATTR_T)        ; 3:13
        ld    C, A              ; 1:4
    print_string_l:
        ld    A, (HL)           ; 1:7     načíst kód znaku z řetězce
        inc   HL                ; 1:6     přechod na další znak
    
        cp  0x20                ; 2:7
        call nc, draw_char      ; 3:10/17
        jr   nc, print_string_l ; 2:12    na další znak
    
        or    A                 ; 1:4     test na kód znak s kódem 0
        ret   z                 ; 1:5/11  ukončit podprogram na konci řetězce
    
        call print_set          ; 3:17
        jr   print_string_l     ; 2:12    na další znak
    
    ; Input: A = spec char
    print_set:
        sub  ZX_EOL             ; 2:7
        ret   c                 ; 1:5/11
        jr  nz, print_set_ink   ; 2:7/12
    
        ld    A, 0x1F           ; 2:7
        or    E                 ; 1:4
        ld    E, A              ; 1:4     nastaveni X na 31
        inc  DE                 ; 1:6     prechod na dalsi radek
        ret                     ; 1:10
    print_set_ink:
        sub  ZX_INK-ZX_EOL      ; 2:7
        jr   nz, print_set_paper; 2:7/12
    
        ld    A, C              ; 1:4
        and 0xF8                ; 2:7
        or  (HL)                ; 1:7
        inc  HL                 ; 1:6     přechod na další znak
        ld    C, A              ; 1:4     save new ink
    
        ret                     ; 1:10
    print_set_paper:
        dec   A                 ; 1:4
        jr   nz, print_set_flash; 2:7/12
    
        ld    A,(HL)            ; 1:7
        inc  HL                 ; 1:6     přechod na další znak
        add   A, A              ; 1:4     2x
        add   A, A              ; 1:4     4x
        add   A, A              ; 1:4     8x
        xor   C                 ; 1:4
        and 0x38                ; 2:7
        xor   C                 ; 1:4
        ld    C, A              ; 1:4     save new paper
    
        ret                     ; 1:10
    print_set_flash:
        dec   A                 ; 1:4
        jr   nz, print_set_brig ; 2:7/12
    
        ld    A, C              ; 1:4
        add   A, A              ; 1:4
        or   (HL)               ; 1:7
        inc  HL                 ; 1:6     přechod na další znak
        rrca                    ; 1:4
        ld    C, A              ; 1:4     save new flash
    
        ret                     ; 1:10
    print_set_brig:
        dec   A                 ; 1:4
        jr   nz, print_set_at   ; 2:7/12
    
        ld    A,(HL)            ; 1:7
        inc  HL                 ; 1:6     přechod na další znak
        rrca                    ; 1:4
        rrca                    ; 1:4
        xor   C                 ; 1:4
        and 0x40                ; 2:7
        xor   C                 ; 1:7
        ld    C, A              ; 1:4     save new bright
    
        ret                     ; 1:10
    print_set_at:
        sub  ZX_AT-ZX_BRIGHT    ; 1:4
        ret  nz                 ; 1:5/11
    
        ld    A,(HL)            ; 1:7     new y
        inc  HL                 ; 1:6     přechod na další znak
        ld    D, 0x16           ; 2:7
        add   A, A              ; 1:4
        add   A, A              ; 1:4
        add   A, A              ; 1:4
        add   A, A              ; 1:4
        rl    D                 ; 2:8
        add   A, A              ; 1:4
        rl    D                 ; 2:8
        xor (HL)                ; 1:7     new x
        inc  HL                 ; 1:6     přechod na další znak
        ld    E, A              ; 1:4
    
        ret                     ; 1:10
    
    
    ;  Input: A = char, DE = address, C = attr
    ; Output: DE = adress next char (overflow DE=0x5800)
    ; Poluttes: none
    draw_char:
    
        push AF                 ; 1:11    uschovat AF na zásobník
        push BC                 ; 1:11    uschovat BC na zásobník
        push HL                 ; 1:11    uschovat HL na zásobník
    
        ld    L, A              ; 1:4     kód znaku do L
        ld    A, C              ; 1:4
        ld  (DE),A              ; 1:7     uložení atributu znaku
    
        ld    BC, CHAR_ADR      ; 3:10    adresa, od níž začínají masky znaků
      if CHAR_ADR & 255
          .warning Pouzivas adresu fontu nezarovnanou na segment, to neni nejlepsi napad.
        ld    H, 0x00           ; 1:4     C je nenulové
      else
        ld    H, C              ; 1:4     C je nulové, protože CHAR_ADR=0x..00
      endif
    
        add  HL, HL             ; 1:11    2x
        add  HL, HL             ; 1:11    4x
        add  HL, HL             ; 1:11    8x
        add  HL, BC             ; 1:11    přičíst bázovou adresu masek znaků
    
        ld    B, 8              ; 2:7     počitadlo zapsaných bajtů
    
        ld    C, D              ; 1:4     uschovat D
        sla   D                 ; 2:8     2x
        sla   D                 ; 2:8     4x
        sla   D                 ; 2:8     8x
        res   7, D              ; 2:8
    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 (nemusíme řešit přetečení do vyššího bajtu)
        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     obnovit obsah D
        inc  DE                 ; 1:6
        pop  HL                 ; 1:10    obnovit obsah HL ze zásobníku
        pop  BC                 ; 1:10    obnovit obsah BC ze zásobníku
        pop  AF                 ; 1:10    obnovit obsah AF ze zásobníku
        ret                     ; 1:10    DE+=1
    
    ; nulou ukončený řetězec
    TEXT:   db "Hello, Speccy!", 0x0D,"dalsi radek na ",ZX_PAPER, ZX_YELLOW, "zlute...", ZX_AT,0,0,"pocatek", ZX_INK, ZX_BLUE," modrou!",ZX_AT,7,13,"ZX_AT 7,13 bright: ",ZX_BRIGHT,1,"ON",ZX_BRIGHT,0," OFF",ZX_AT,23,3,"ZX_AT 23,3 FLASH: ",ZX_FLASH,1,"ON",ZX_FLASH,0,"OFF",0

    Stoji tam za povsimnuti jak je udelana ta SWITCH..CASE cast. Je to vnoreno do funkce aby se vyskakovalo pres RET. Hodnota podle ktere se to rozhoduje je v A a pokud mezi sebou vetve jsou vzdaleny jen o 1 tak staci "DEC A".

    9. 3. 2023, 18:19 editováno autorem komentáře