Jenze tady porovnavam
JR nz,... ; 2:7/12
s
DJNZ ... ;2/8/13
Takze nemusim resit ze to jednou neskonci, vsechny varianty jsou o takt rychlejsi.
A ano, JP by byl rychlejsi o 3*256-2 taktu, ale delsi o bajt a kdyz dokazi napsat neco kratsiho a stale jeste rychlejsiho nez original tak dam prednost delce.
Dokonce mam pravidlo kde porovnavam jablka s hruskama.
1 bajt = 4 takty
Kde beru do uvahy zda je to ve smycce, to pak s timto pravidlem vyhrava vzdy delsi kod. Asi jsem to nerekl dost jasne, ale neva.
Tohle pasmo nezvladne
sbc A
sbc B
ale jen
sbc A,A ; A = A-A-carry
sbc A,B ; A = A-B-carry
Protoze sbc (odcitani s carry ) muze byt i pro HL
Nektere jine prekladace zase vyzaduji cilovy registr tam, kde pasmo ma implicitni A. Myslim ze to bylo u "sub B", ale nejsem si jisty.
PS: Sorry jeste jsem to stale nedocetl.
Tak jeste optimalizace pro posledni 16 bitovou smycku.
org 0x8000
start:
ld hl, 0x59FF ; adresa pro zápis
ld a, 0x57 ; stop pro horni bajt adresy
loop:
ld (HL),L ; zápis hodnoty na adresu (HL)
dec HL ; snížní adresy i zapisované hodnoty
cp H ; počitadlo vnější smyčky
jp nz, $-3 ; skok pokud nejsme pod atributovou pamětí
ret
ORG 8000
8000: label start
8000:21FF59 LD HL, 59FF
8003:3E57 LD A, 57
8005: label loop
8005:75 LD (HL), L
8006:2B DEC HL
8007:BC CP H
8008:C20580 JP NZ, 8005
800B:C9 RET
To by melo byt o 4 bajty kratsi, ale skoro o 512 taktu pomalejsi (jsem linej to pocitat). Dalo by se to zkratit o další bajt a zpomalit o dalsich 1024 taktu prostym nahrazenim instrukce skoku za relativni skok.
Djnz je sice efektivni, ale ne vzdy.
Nasel jsem o bajt kratsi reseni a jeste k tomu rychlejsi.
Neni to ale 16 bitova smycka, ale 8 bitova, jen staci zvednou a snizit H.
Puvodni (12 bajtu a cca 27 taktu na bajt, oproti 16 bajtu a cca 26 taktu na bajt z clanku):
org 0x8000
; t= 10+7+10+512*(7+6+4+10)=27+512*27=13851
start:
ld HL, 0x59FF ; 3:10 adresa pro zápis
ld A, 0x57 ; 2:7 stop pro horni bajt adresy
loop:
ld (HL),L ; 1:7 zápis hodnoty na adresu (HL)
dec HL ; 1:6 snížní adresy i zapisované hodnoty
cp H ; 1:4 počitadlo vnější smyčky
jp nz, loop ; 3:10 skok pokud nejsme pod atributovou pamětí
ret ; 1:10
Nove (11 bajtu a cca 38/2=19 taktu na bajt):
org 0x8000
; t= 10+256*(4+7+4+7+4+12)-5+10=15+256*38=9743
start:
ld HL, 0x5800 ; 3:10 adresa pro zápis
loop:
inc H ; 1:4
ld (HL),L ; 1:7 zápis hodnoty na adresu (HL)
dec H ; 1:4
ld (HL),L ; 1:7 zápis hodnoty na adresu (HL)
inc L ; 1:4 zvýšení adresy i zapisované hodnoty
jr nz, loop ; 2:7/12
ret ; 1:10
Tohle reseni by slo prepsat na o neco pomalejsi variantu, ale ktera je schopna zvladnout vice 256 bajtovych bloku.
Univerzalnejsi (11 taktu a cca 41/2=20.5 taktu na bajt):
org 0x8000
; t= 7+256*(7+7+4+7+4+12)-5+10=12+256*41=10508
start:
ld L, 0x00 ; 2:7 lo(adresa) pro zápis
loop:
ld H, 0x58 ; 2:7 hi(adresa) pro zápis
ld (HL),L ; 1:7 zápis hodnoty na adresu (HL)
inc H ; 1:4
ld (HL),L ; 1:7 zápis hodnoty na adresu (HL)
inc L ; 1:4 zvýšení adresy i zapisované hodnoty
jr nz, loop ; 2:7/12
ret ; 1:10
PS: Jeste by slo pouzit smycku kde counter by byl carry!
Protoze se ma zopakovat jen jednou (kod probehne 2x) a nikde carry nemenime.
Ale u takhle kratkeho kodu se to vyplati spis zduplikovat.
or A loop: ... ccf jr c,loop
Nejkratsi varianta pro 16 bitovou smycku by byla s instrukci testu bitu.
0x59 = 0101 1001
0x58 = 0101 1000
0x57 = 0101 0111
0x57 se lisi u trech bitu.
Smycka je pomalejsi uz o 7 taktu na pruchod.
Puvodni - 13 (djnz) + 8 (bit) + 12 (jr)
org 0x8000
ld hl, 0x59FF ; adresa pro zápis
ld (HL),L ; zápis hodnoty na adresu (HL)
dec HL ; snížní adresy i zapisované hodnoty
bit 3,H ; test bitu 3
jr nz, $-4 ; skok pokud nejsme pod atributovou pamětí
ret
ORG 8000
8000:21FF59 LD HL, 59FF
8003:75 LD (HL), L
8004:2B DEC HL
8005:CB5C BIT 3, H
8007:20FA JR NZ, 8003
8009:C9 RET
PS: Jak se tu vlastne spravne vklada kod, aby zachoval odsazeni a neskoncil pri prvnim zalomeni?
Myslim ze spravna odpoved je ti rici ze absolutni skok je rychlejsi ale o bajt delsi, protoze musi uchovavat celou adresu cile, tedy 2 bajty.
Pokud to vis, tak bych mel otazku zase ja, proc bys pouzival JP kdyz muzes pouzit kod stejne delky s tou variantou co jsem psal nad timhle kde je konec testovan pres
CP H
JR nz,$-$
co trva 4+12 = 16 taktu oproti
BIT 3,H
JP $-4
ktery trva 8+10 = 18 taktu? A kod je stejne dlouhy? Duvod by totiz stale nejaky byt asi mohl protoze je to Z80... .)
A jinak bych nenazýval tu smyčku s šestnáctibitovým counterem jako naivní variantu, je to prostě nejčitelnější a správné řešení.
Tady ty hacky v diskuzi kolikrát nepřežijí přesun pracovního prostoru na jinou adresu.
Ta varianta s pseudo 16-bitovym registrem AB je validní, ale na zásobník se mnohem lépe ukládá BC než AB.
Myslim ze treba ten hack s testovanim bitu prezije cokoliv. Ze u tri po sobe jdoucich adresach se vzdy najde 1 bit u ktereho se bude kazdy lisit od zbyvajichich dvou. Mozna ani nemusi byt po sobe jdouci.
A u toho prikladu kde vyplnujes adresu 0x58.. a 0x59.. jdou udelat obe varianty s jak sestupnym tak vzestupnym posunem indexu.
Pravdu mas s tim ze pri jinych prikladech, kdy nelezi zacatky a konce (vyjma) na nulovych bajtech nizsi adresy muze byt kod s djnz efektivnejsi. Ale to je proste psani asembleru pro Z80. Efektivni kod se bude lisit podle konstant.
Dokonce nekdy muzes vzit nejlepsi kod a napsat o bajt kratsi jen tim ze ho ulozis na jedinou spravnou konkretni adresu do pameti.
Zajimave cviceni je napsat kod typu
cp DEHL, 32bitova konstanta
To je fakt temny les kolik optimalizaci tady muze vzniknout a co vsechno se da vyuzit. Jen to tomhle by se dal napsat fakt dlouhy clanek.
Jop. Z80 měla hromadu nedokumentovaných instrukcí, narazil jsem na to, když jsem v mládí programoval emulátor, že jsem u některých pokročilejších programech, které jsem pak něm spouštěl, narážel na neznámé instrukční sekvence ... a netušil jsem, co mají ty sekvence dělat, protože neoficiální dokumentace těch instrukcí se v té době - internet neměl kde kdo - blbě sháněla
Diky, je to nostalgie. Kde jsou ty casy se ZX a pozdeji SAM coupe, kdy jsem si hral s asemblerem Z80 a hral hry od FUXOFT. Kdyz se divam na ten kod porad si to vybavuju, LD, JP NZ, ... Pak jsem chtel prejit s PC na intelovy asm ale nikdy k tomu nedoslo, proste ta slozitost narostla, jine zkratky (MOV, ...). Je to davno.
ASM Z80 jsem použil tak před 30 lety. Možná ještě dříve.
Dokonce pana Fuku jsem osobně několikrát viděl na stanici mladých techniků v Praze v Dejvicích. Nevím jak dopadl.
Nakonec jsem se k tomu dokopal a napsal i něco v moderních assemblerech x86 a x64. Zjistil jsem, že mnoho instrukcí x86 procesoru prostě "nechutná" a jediná instrukce trvá déle, než třeba 3 instrukce jiné. Ono je to třeba 10x pomalejší. Je tam spousta "plonkových" instrukcí, které se nepoužívají. Abych byl konkrétní tak <b>XCHG [paměť],registr</b>
U Z80 bylo časování deterministické, nové superskalární procesory zvládnou 3 instrukce v jednom taktu. A když se nezadaří tak to trvá výrazně déle.
Možná je dobré s trochou nadsázky dodat, že cokoli vytvoříte pro ZX Spectrum, tak bude spustitelný přes emulátor (i webovej) na prakticky jakékoli platformě. DOS, Windows, Linux, Mac, Android, iPhone, webové emulátory, asi to půjde emulovat i na emulátoru Amigy :-). To je docela unikátní platforma :-)
To normálně klíčovalo videosignál. Jen program ZX nevěděl, kde se právě paprsek generovaný ULA nachází. ULA buď generovala border, nebo obsah videoram. Dokonce se ty pruhy daly udělat v BASICu smyčkou:
1: LET i = 0
10: BORDER i
20: ... nejaké zpoždění
30: LET i = i+1
40: GOTO 10
ale opravdu bez záruky. Už si to detailně nepamatuji.
Myslíš toto?
10 BORDER 1: BORDER 2: BORDER 3: BORDER 4: BORDER 5: BORDER7: PAUSE1: GO TO 10
... to udělá relativně tlusté (vysoké) pruhy a protože to je běžící BASIC a běží při tom IM 1 přerušení pro obsluhu klávesnice, tak ty pruhy při stisku klávesy mírně poskakují (mění se jejich tloušťka) podle toho, jakou větví programu to při zpracování proběhne.
PAUSE 1 způsobí, že se počká 1/50s , resp. zbytek té 1/50 a GO TO začne po přerušení, kdy se začíná kreslit obsah obrazovky od levého horního rohu.
A ano, je tam malý rozdíl mezi tím, kdy je to na jednom řádku, nebo na více. Protože přechod mezi řádky BASICového programu sežere trochu času.
Praktické využití to má malé, ale přesto se to v pár programech objevilo jako efekt při čekání na stisk klávesy v menu.
Ve strojáku změna BORDERu trvá mnohem kratší dobu, takže se na jednom mikrořádku dá změnit i několikrát, v extrému se to dá použít i k sestavení několika znakového nápisu. Podobný princip využívají i multicolor efekty, kde se programem stihnou změnit atributy během kreslení obrazovky a v jednom čtverci může být víc barev než jen dvě.
Co se týče počítání cyklů - viz https://www.overtakenbyevents.com/tstates/
Není to perfektní. Myslím, že tam je chyba u jedné instrukce a autor nekomunikuje, ale i tak je to nástroj, který hodně pomáhá a šetří práci. Alespoň pro základní orientaci s následnou kontrolou.
Když už jsme u literatury - dobré jsou i Universumovy "Assembler a ZX Spectrum" - díky Softhousovi ke stažení zde https://softhouse.speccy.cz/dokumenty.htm společně s komentovaným výpisem ZX ROM od D. Jenneho... (se všemi pozdějšími korekcemi).
Zvláště první Assembler a ZX Spectrum je unikátní nejenom zajímavým obsahem, ale i tím, že to je kniha vysázená v programu Desktop na ZX Spectru (pravděpodobně nejrozsáhlejší dílo, co v Desktopu vzniklo). Přičemž Desktop je asi jediný opravdu plně WYSIWYG editor pro ZX Spectrum.
Pravděpodobně i Daniel Jenne psal své knihy na ZX Spectru, některé jsou sazbou shodné D-Textem, který D. Jenne počeštil původně ze Spectral Writeru.