V clanku jsou uvedeny konstanty 0×00010000 a 0×5800. To je trochu matouci, protoze prvni je binarni a druha hexadecimalni.
Pasmo rozpozna 0x5800 jako hexadecimalni hodnotu, nejen $5800 nebo #5800.
Binarni zapis je s predponou %, jak je uvedeno v kodu.
Z80 je trosku zvlastni procesor a spousta veci jde delat ruznymi cestami.
org $8000
start:
ld a,%00010000
ld ($5800),a
ret
Jde zapsat se stejnou delkou kodu (2+3+1=6) i takty (7+13+10=30) jako
org $8000
start:
ld hl,$5800
ld (hl),%00010000
ret
3+2+1 = 6 bajtu
10+10+10 = 30 taktu
Jen se pouzije jiny registr. Tohle dokaze byt poradna vyzva uz od par instrukci. Kdyz se budete snazit napsat neco jen trosku mene trivialniho, tak na prvni pohled nebude zrejme, ktera kombinace/varianta je lepsi.
Staci se podivat na vysledky Z80 size programming chalenge, kde i ostrileni programatori se nedostanou na optimalnich 15 bajtu.
http://www.retroprogramming.com/2014/12/z80-size-programming-challenge-1.html
A pokud se pokusite pouzit nejaky prekladac, napr. pro C tak vysledek bude opravdu strasny. Dones neexistuje poradny prekladac u ktereho si nebudete trhat vlasy pri pohledu na vysledny kod.
Z80 neumi efektivne pracovat s parametry ulozenymi na zasobnik, takze to uplne diskvalifikuje C. Pravdepodobne pouzije instrukce typu LD E,(IX+n), ktera ale zabira 3 bajty (jeden pro prefix, dalsi instrukce a treti hodnota n) a trva 19 taktu. Oproti instrukci LD E,(HL), ktera zabira jeden bajt a trva 7 taktu. Takze pri vhodne zvolenem algoritmu, kdy se budeme snazit cist data sekvencne za sebou a pouzijeme k tomu instrukci INC HL (1 bajt a 6 taktu) tak se dostaneme na 2 bajty a 13 taktu.
Ale vetsina prekladacu je jeste horsich budou se snazit neustale ukladat promenne do pameti a opakovane nacitat do registru. Proste bude zapominat co se pred chvili drzel v registrech, protoze uz dela jinou cast programu a nepredava si co si drzi v registrech, zda to bude muset uklidit nebo to muze naopak vyuzit.
Staci se podivat co za hruzu leze z jednoducheho programku co testuje zda retezec je pangram, kdy se pouziva 32 bitove pole pro pouzite znaky.
https://github.com/DW0RKiN/M4_FORTH/blob/master/Benchmark/Pangram.c
https://github.com/DW0RKiN/M4_FORTH/blob/master/Benchmark/Pangram.lst
Misto jednobajtove instrukce o sedmi taktech
or 32
napise sdcc
86 ;Pangram.c:10: c |= 32; // uppercase
004E DD 4E F8 [19] 87 ld c, -8 (ix)
0051 CB E9 [ 8] 88 set 5, c
0053 79 [ 4] 89 ld a, c
Preklad kodu zapsanemu ve FORTHu je nasobne rychlejsi a i ten byva stale 2x horsi nez co napisete primo v assembleru. Protoze Z80 se vlastne nehodi ani na ten FORTH. Chybi mu kratka a rychla instrukce ex SP, HL. Ktera by mu umoznila "zdvojit" zasobnik. Takze si musi druhy zasobnik emulovat pres to inc/dec a ld (HL),register pripadne ld register,(HL). Popripade jinak, protoze to zase existuje vice reseni.
PS: K tomu prekladaci "pasmo" bych podotknul, ze ma nespravne danou prioritu u unarniho znamenka minus. Ma ho misto nejvyssi nejnizsi, takze
ld HL, -100+500
je
ld HL,-600
Ke vsemu uklada pres EQU hodnoty pokazde jako unsigned word (16 bitu, vic neumi). Takze muze byt docela vyzva zapsat vyraz tak aby napriklad dokazal spravne porovnat >,<,>=,<= mezi signed hodnotami.
Napriklad potrebujete zapsat:
ld HL, m <= n
aby se to zkompilovalo jako
ld HL, 0x0000
nebo
ld HL, 0xFFFF
nebo chcete aby to spravne nasobilo nebo delilo signed hodnoty jako
ld HL,m/n
popripade zbytek
ld HL,m % n
Napsat floor divison uz je dost narocne jako vyraz pomoci toho co Pasmo umi.
Kde za m a n si dosadte pres makro nejakou konstantu 16 bitovou signed.
Popripade 32 bit/16 bit, pokud je vysledek 16 bitovy tak s omezenim Pasma na 16 bitu to zapsat sice jde, ale je to na celou obrazovku.
ld HL, 32bit_m/16bit_n
PPS: FUSE emulator ma sice debugger, ale ten je prakticky nepouzitelny, je tezke se vubec dostat k informacim jake zkratky muzete pouzit. Jak zmenit hodnoty registru atd. Ale na linuxu je bohuzel to nejlepsi co muzete mit pokud nechcete pouzivat wine.
Budete pouzivat jen:
breakpoint 0x6000
br 0x8000
ignore id count
ig id count
delete id
del id
Popripadne dvouklik na zasobnik vytvori breakpoint na jedno pouziti na adrese co v nem lezi.
A uz se nedostanete k:
Neco se snazi cist z adresy 0x6000:
breakpoint read $6000
br re $6000
Neco se snazi zapsat na adresu 0x6000:
breakpoint write $6000
br w $6000
break 0xa000 if z80:bc >= 0x8000 && z80:de < 0x1234
set z80:a 0xff
set z80:de 0x1234
7. 2. 2023, 03:49 editováno autorem komentáře