Upravil jsem jeste https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/77-add-hex-numbers.asm bez toho, ze bych pouzil trik s DAA.
Zvlastni, ze se i pres to, ze vypisujes list toho vysledku, se nikdo nepozastavuje nad tim, ze pro druhy CALL pouzivas JP kvuli optimalizaci, ale pritom delas "nulovy" skok.
8028:C32B80 JP 802B 802B: label print_hex_digit
Protoze mas spravne umistenou rutinu print_hex_number nad print_hex_digit. Takze ten kod automaticky spravne "propadne" do print_hex_digit. Neni potreba vubec nic delat. Spravne umisteni rutin za sebou je v asembleru dulezite. Nekdy se dokonce o to misto nad pouzivanou rutinou poperou mezi sebou vic rutin a musis si zvolit, ktera se pouzije casteji.
Dalsi vec je pouziti call na rutiny new_line a space. Obe rutiny zabiraji bez RET 3 bajty (nevim jestli tohle ale normalni clovek hned vidi) a ten CALL samotny je na 3 bajty taky. Takze je to zbytecnych 17 taktu na CALL + 10 taktu na RET a kdyz se to "inkludne" tak ti odpadne i jeden bajt za ten RET.
Dalsi vec je trojnasobne pouziti B = 11. To uz se ti vyplati pouzit BC = 11*257 a k tomu 2x pouzit B = C.
Posledni vec je to neohrabene testovani zda mohu tisknout mezeru za cislo.
print_numbers: next_item: ld A, (HL) ; načíst hodnotu z pole inc HL ; přechod na další prvek pole call print_hex_number ; vytisknout hexa hodnotu ld A, B cp 1 ; za poslední hodnotou už nechceme tisknout mezeru jr Z, skip ; přeskočení tisku mezery u poslední hodnoty call space skip: djnz next_item ; zpracování dalšího prvku pole ret
To jde napsat mnohem lepe pouhym preskupenim kodu. Tisk mezery das pred fci a vstupni bod bude az za tiskem mezery. Ale smycka bude skakat/se vracet na tisk mezery. Tim zarucis, ze mezera se netiskne jako prvni znak, ani jako posledni.
ENTRY_POINT equ $8000 ROM_CLS equ $0DAF OUT_NUM_1 equ $1A1B org ENTRY_POINT start: call ROM_CLS ; smazání obrazovky a otevření kanálu číslo 2 (screen) ld HL, array1 ; vytištění 11 hodnot z pole array1 v hexadecimálním formátu ld BC, 0x0B0B ; B = 11, C = 11 call print_numbers ld HL, array2 ; vytištění 11 hodnot z pole array2 v hexadecimálním formátu ld B, C call print_numbers ; odřádkování ld A, 0x0d ; kód znaku pro odřádkování rst 0x10 ; zavolání rutiny v ROM ld A, 0x0d ; kód znaku pro odřádkování rst 0x10 ; zavolání rutiny v ROM ld DE, array1 ; adresa pole s první řadou sčítanců ld HL, array2 ; adresa pole se druhou řadou sčítanců ld B, C next_add: ld A, (DE) ; načíst první sčítanec z pole add A, (HL) ; načíst druhý sčítanec z pole inc DE ; posun ukazatele na další sčítanec inc HL ; dtto call print_hex_number ; vytisknout hexa hodnotu výsledku ld A, 32 ; kód mezery rst 0x10 ; zavolání rutiny v ROM djnz next_add ; kontrola počtu zobrazených výsledků ret ; podprogram pro tisk sekvence numerických hodnot v hexadecimálním formátu ; vstupy: ; HL - ukazatel na pole s hodnotami ; B - počet hodnot (délka pole) next_item: ld A, 32 ; kód mezery rst 0x10 ; zavolání rutiny v ROM print_numbers: ; entry point ld A, (HL) ; načíst hodnotu z pole inc HL ; přechod na další prvek pole call print_hex_number ; vytisknout hexa hodnotu djnz next_item ; zpracování dalšího prvku pole ret array1: db 0x00, 0x01, 0x05, 0x09, 0x09, 0x09, 0x10, 0x10, 0xa0, 0xfe, 0xff array2: db 0x01, 0x02, 0x05, 0x01, 0x06, 0x07, 0x09, 0x10, 0x01, 0x01, 0x01 print_hex_number: push AF ; uschovat A pro pozdější využití rrca ; rotace o čtyři bity doprava rrca rrca rrca and $0f ; zamaskovat horní čtyři bity call print_hex_digit; vytisknout hexa číslici pop AF ; obnovit A and $0f ; zamaskovat horní čtyři bity ; jp print_hex_digit ; vytisknout hexa číslici a návrat z podprogramu ; fall to print_hex_digit print_hex_digit: cp 0x0a ; test, jestli je číslice menší než 10 jr c, print_0_to_9 ; ok, hodnota je menší než 10, budeme tedy tisknout desítkovou číslici add A, 65-10-48 ; ASCII kód znaku 'A', ovšem začínáme od desítky, ne od nuly (+ update pro další ADD) print_0_to_9: add A, 48 ; ASCII kód znaku '0' rst 0x10 ; zavolání rutiny v ROM pro tisk jednoho znaku ret ; návrat ze subrutiny end ENTRY_POINT
Ze 118 bajtu se dostanes na 101 bajtu.
no vidíš, toho jsem si nevšiml. Zase ale pokud by někdo neznalý toho triku udělal refactoring a strčil si subrutiny někam do dalšího souboru, už by to takto nešlo (ale tím v žádném případě, neříkám, že nemáš pravdu - máš!)
OT: se tak dívám, že příště budu psát o Tvé doméně, pokud se tedy dívám na Tvoje repo s FP subrutinami (a není to shoda nicků).
Jestli tim trikem myslis nepouzivat skok a umistit rutina za sebe tak jsem to zkousel jeste krome komentare ze ty rutiny jsou "slepene" :
; fall to print_hex_digit
osetrit pres nejaky
if ($ != print_hex_digit)
.error Blabla
endif
ale to pasmo nezvladne protoze print_hex_digit pry jeste nezna i kdyz lezi pod tim a nekdy se sam prepne do vic pruchodu.
Tak jsem se to snazil obejit pres
omg equ print_hex_digit
if ($ != omg)
.error Blabla
endif
ale to selze stejne uz u omg. Mozna to jde jinym trikem, ale nevim jak.
PS: Tu bfloat, danagy a binary16 floating-point knihovnu jsem psal. Na FB existovala (mozna jeste existuje) skupina lidi z celeho sveta stale programujici pro ZX. A krome ruznych soutezi tam ukazoval Daniel Nagy i Ray tracing pro ZX. Chtel jsem jen vedet zda to nebude lepsi kdyz pouziji jiny format, ale stale 16 bitovy. On zvolil 8 bitu mantisu ja testoval jak 9 bitu tak 7 bitu. Drzel jsem se jeho navrhu "api" a drzel vstupy a vystupy ce stejnych registrech. Delal jsem to zamerene na rychlost, ale snazil se zaroven, aby pokud to jde po operaci byly vzdy vsechny bity mantisy i ten nejnizsi spravne zaokrouhlene. Co on nemel, takze jsem nakonec prepsal i jeho kod. Pak jsem to zpomalil uz jen tim, ze jsem vracel pri preteceni nebo podteceni priznaky.
Psal jsem to cely rok, nez se mi podarilo konecne vygenerovat ten obrazek. Byla tam spousta triku jak to delat pres male tabulky. Zjistil jsem ze napriklad nasobeni je snazsi nez scitani a odcitaniu FP. Deleni je problem, ale jde to pres 1/mantisa tabulku s tim, ze nekdy nejnizsi bit neni dobre. LN je silenost. Delat to nejakym vzorcem pomoci uz vytvorenych operaci jen ztracis bity a bude to pomale. Takze pouzit tabulku s mezivysledky a nejaka interpolace? Je tam i zavislost na exponentu. U nekterych vstupnich hodnot bylo nakonec vic bitu spatne na vystupu.
Z toho githubu se da spoustu veci odvodit, ale neni tam vsechno. Treba nektere tabulky jsem vytvarel pomoci spatlaneho programu v C co me to pocital iteracne (nahodne jsem drobne menil hodnoty tabulky a opravoval zbytek pro nejmensi chyby, mel vic variant a pak nejlepsi ponechal a opakoval) a snazil se mit pro vsechny vstupy minimalni chybu nebo zadnou na vystupu. Aby probehlo vsude spravne zaokrouhleni. Zkousel jsem ruzne verze tabulek. Pocital to kolikrat hodiny co byl v praci na modernim CPU. Proste neco co by pred 40 lety neslo udelat.
Ale uz jsou to 3 roky, moc si toho nepamatuji. Jen ze danagyho format to vyhral. binary16 melo vubec problem to vykreslit, tam uz temer nevyslo pro rozsah exponentu. A byl pomaly a i kdyz nejpresnejsi rozbrazeni stale mel chyby oproti bezchybne basic verzi. Bfloat nepresny a stejne rychly jak Danagy. Ale mensi tabulky, kdyz je mensi mantisa.
1 BORDER 0: PAPER 0: INK 9: BRIGHT 1: CLS: POKE 23672,0: POKE 23673,0: POKE 23674,0 10 LET spheres=2: IF spheres THEN DIM c(spheres,3): DIM r(spheres): DIM q(spheres) 20 FOR k=1 TO spheres: READ c(k,1),c(k,2),c(k,3),r: LET r(k)=r: LET q(k)=r*r: NEXT k 30 DATA -0.3,-0.8,3,0.6 40 DATA 0.9,-1.1,2,0.2 50 FOR i=0 TO 175: FOR j=0 TO 255 60 LET x=0.3: LET y=-0.5: LET z=0 70 LET dx=j-128: LET dy=88-i: LET dz=300: LET dd=dx*dx+dy*dy+dz*dz 80 GO SUB 100: NEXT j: NEXT i 90 PAUSE 1: LET s=PEEK 23672+256*PEEK 23673+65536*PEEK 23674: LET s=s/50: LET m=INT (INT s/60): LET h=INT (m/60): PRINT "Time: ";h;"h ";m-60*h;"min ";INT((s-60*m)*100)/100;"s ";PAUSE 0:STOP 100 LET n=-(y>=0 OR dy<=0): IF NOT n THEN LET s=-y/dy 110 FOR k=1 TO spheres 120 LET px=c(k,1)-x: LET py=c(k,2)-y: LET pz=c(k,3)-z 130 LET pp=px*px+py*py+pz*pz 140 LET sc=px*dx+py*dy+pz*dz 150 IF sc<=0 THEN GO TO 200 160 LET bb=sc*sc/dd 170 LET aa=q(k)-pp+bb 180 IF aa<=0 THEN GO TO 200 190 LET sc=(SQR bb-SQR aa)/SQR dd: IF sc<s OR n<0 THEN LET n=k: LET s=sc 200 NEXT k 210 IF n<0 THEN RETURN 220 LET dx=dx*s: LET dy=dy*s: LET dz=dz*s: LET dd=dd*s*s 230 LET x=x+dx: LET y=y+dy: LET z=z+dz 240 IF n=0 THEN GO TO 300 250 LET nx=x-c(n,1): LET ny=y-c(n,2): LET nz=z-c(n,3) 260 LET nn=nx*nx+ny*ny+nz*nz 270 LET l=2*(dx*nx+dy*ny+dz*nz)/nn 280 LET dx=dx-nx*l: LET dy=dy-ny*l: LET dz=dz-nz*l 290 GO TO 100 300 FOR k=1 TO spheres 310 LET u=c(k,1)-x: LET v=c(k,3)-z: IF u*u+v*v<=q(k) THEN RETURN 320 NEXT k 330 IF (x-INT x>.5)<>(z-INT z>.5) THEN PLOT j,i 340 RETURN
Ta trva vic jak 8 hodin a 46 minut.