Odpovídáte na názor k článku Vývoj her a dem pro ZX Spectrum: vlastní vykreslovací subrutiny podruhé. Názory mohou přidávat pouze registrovaní uživatelé. Nově přidané názory se na webu objeví až po schválení redakcí.
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