Myslim ze se me podarilo zkratit jeste tu rozbalovaci rutinu z 46 bajtu na 41 bajtu a zaroven urychlit.
Zkousel jsem nekolik metod a nektere slibne v jednom smeru selhavaly na tom ze se nacita jednou bajt a podruhe dvoubajt, ale tahle metoda co popisi je lepsi pokud nekde nedelam chybu.
Original (uz zkraceny o 2 bajty a -12 taktu):
Kód:
DEPREP_LZE: ; depack_lze
push BC ; 1:11 depack_lze Save block length
ld A, 0x7F ; 2:7 depack_lze
call DEPNUM_LZE ; 3:17 depack_lze Get relative offset of packed sequence
ex (SP),HL ; 1:19 depack_lze
push HL ; 1:11 depack_lze
ld H, D ; 1:4 depack_lze DE = destination address
ld L, E ; 1:4 depack_lze
sbc HL, BC ; 2:15 depack_lze HL = begin of source sequence in already unpacked data
pop BC ; 1:10 depack_lze BC = length of sequence
ldir ; 2:16/21 depack_lze Copy sequence
pop HL ; 1:10 depack_lze
;[16:124]
; ...fall down to depack_lze
Nove je to o bajt kratsi, ale stejne pomale (ve skutecnosti je to rychlejsi protoze DEPNUM_LZE bezi rychleji)
Kód:
DEPREP_LZE: ; depack_lze
push BC ; 1:11 depack_lze Save block length
ld A,(HL) ; 1:7 depack_lze A = %6543210D; D = Double bit
call DEPNUM_LZE ; 3:17 depack_lze Get relative offset of packed sequence
ex (SP),HL ; 1:19 depack_lze Load block lengt and save address of source packed data
push HL ; 1:11 depack_lze Save block length
ld H, D ; 1:4 depack_lze DE = destination address
ld L, E ; 1:4 depack_lze
sbc HL, BC ; 2:15 depack_lze HL = begin of source sequence in already unpacked data
pop BC ; 1:10 depack_lze BC = length of sequence
ldir ; 2:16/21 depack_lze Copy sequence
pop HL ; 1:10 depack_lze
;[15:124]
Rozdil je v tom ze original nastavuje masku do A a nove se rovnou nacita (HL) s tim ze carry je celou dobu vynulovan.
Hlavni smycka v originale vypada takhle:
Kód:
;# Input:
;# HL = address of source packed data
;# DE = address of destination to depack data
;# ===========================================
DEPACK_LZE: ; depack_lze
bit 6,(HL) ; 2:12 depack_lze Get identification of block: 0=unpacked, 1=packed
push AF ; 1:11 depack_lze
ld A, 0x3F ; 2:7 depack_lze
call DEPNUM_LZE ; 3:17 depack_lze Get length of block
pop AF ; 1:10 depack_lze
jr nz, DEPREP_LZE ; 2:7/12 depack_lze If packed block then jump
;[11:64]
ld A, B ; 1:4 depack_lze
or C ; 1:4 depack_lze If length = 0 then end of depacking
ret z ; 1:5/11 depack_lze
ldir ; 2:16/21 depack_lze Copy unpacked data block
jr DEPACK_LZE ; 2:12 depack_lze
;[18:105]
Je to zalozene na tom ze 7. bit obsahuje informaci o tom zda je to jednobajtovy nebo dvoubajtovy token obsahujici delku bloku a 6. bajt ma informaci o tom jestli je ten blok komprimovany (=nasledujici cast co se ma "rozbalit" uz byla jednou pouzita v rozbalene casti, takze zdroj misto tech dat obsahuje jen dalsi token s relativnim ofsetem vzhledem k DE = aktualni index za posledniho zkopirovany bajt (je posuvan jen pres ldir)) nebo se jen budou kopirovat data o tehle delce ze zdroje.
Aby to fungovalo tak se musi ten 7. a 6. bit vynulovat.
Nova uprava vypada takto:
Kód:
;# Input:
;# HL = address of source packed data
;# DE = address of destination to depack data
;# ===========================================
DEPACK_LZE: ; depack_lze
ld A,(HL) ; 1:7 depack_lze A = %P543210D; P = Packed bit; D = Double bit
or A ; 1:4 depack_lze Reset carry and set sign and zero flag
rla ; 1:4 depack_lze A = %??????D0; sign unaffected
rrca ; 1:4 depack_lze A = %0??????D; sign unaffected, reset carry
call DEPNUM_LZE ; 3:17 depack_lze Get length of block; sign and zero flag unaffected
jp m, DEPREP_LZE ; 3:10 depack_lze If packed block then jump
;[10:46]
ret z ; 1:5/11 depack_lze If zero then end of depacking
ldir ; 2:16/21 depack_lze Copy unpacked data block
jr DEPACK_LZE ; 2:12 depack_lze
Nove je signalizace dvoubajtu v 7. bitu presunuta do nulteho bitu a signalizace "komprimace" v 6. bitu je nyni v 7. bitu.
Vtip je v tom ze DEPNUM_LZE rutina co nacita bajt nebo dvoubajt je napsana tak ze zachovava SIGN a ZERO flag( ale carry musi byt vynulovan).
Takze se nacte hodnota do A, nastavi se SIGN flag pro signalizaci "komprimace" a peclivou kombinaci instrukci zachovavajici priznaky se 7. bit vynuluje.
Tady se usetri bajt a 18 taktu (+ ta rychlejsi subrutina)
Nasleduje ukonceni rutiny (posunul jsem to az za odskok aby to nezpomalovalo pokud je to komprimovany).
Nevim jak je napsana ta komprimacni cast, ale tohle zvladne jen jeden nulovy bajt jako znacku(mark?) ze je konec.
Protoze puvodne je to psane obecne jako "A=B a OR C". Ale pokud je to psane jako jeden nulovy bajt tak by to nemelo nacist dalsi bajt v podrutine, takze by melo stacit "OR C", protoze v A je bud C a B=0 a nebo v A je B a C je druhy bajt. Takze to staci jednou instrukci i kdyby ten pakovac delal zbytecne nulovy dvoubajt.
No minimalne tohle usetri 2 bajty a 8 taktu.
Posledni nejdulezitejsi cast protoze se vola opakovane pro kazdy token je v originale:
Kód:
DEPNUM_LZE: ; depack_lze
and (HL) ; 1:7 depack_lze Mask one-byte value or high byte of two-byte value
ld C, A ; 1:4 depack_lze
ld B, 0x00 ; 2:7 depack_lze BC = value or high type of value
bit 7,(HL) ; 2:12 depack_lze
inc HL ; 1:6 depack_lze
ret z ; 1:5/11 depack_lze If short value then return
;[ 8:41]
ld B, C ; 1:4 depack_lze
ld C,(HL) ; 1:7 depack_lze Get low byte of two-byte value
inc HL ; 1:6 depack_lze
ret ; 1:10 depack_lze
;[4:27]
Nove je to o dost kratsi protoze to nacitani je castecne v kazdem volani:
Kód:
;# Input:
;# reset carry
;# A = (HL)
;# HL = address of source packed data
;# Output1:
;# carry and sign and zero flag unaffected
;# BC = %0000 0000 0s?? ????
;# HL++
;# Output2:
;# carry and sign and zero flag unaffected
;# BC = %0s?? ???? ???? ????
;# HL+= 2
DEPNUM_LZE: ; depack_lze
inc HL ; 1:6 depack_lze
rra ; 1:4 depack_lze 6543210D -> .6543210 carry=D
ld C, A ; 1:4 depack_lze
ld B, 0x00 ; 2:7 depack_lze
ret nc ; 1:5/11 depack_lze If short value then return BC = %0000 0000 0??? ????
;[ 6:26]
ccf ; 1:4 depack_lze
ld B, C ; 1:4 depack_lze
ld C,(HL) ; 1:7 depack_lze Get low byte of two-byte value
inc HL ; 1:6 depack_lze
ret ; 1:10 depack_lze BC = %0??? ???? ???? ????
;[5:31]
Tady se setri 1 bajt a hlavne 11 nebo 15 taktu pro kazdy token. Nevyhoda je ze kvuli odcitani "sbc HL,BC" se musi nulovat carry.
Ta uprava je zpetne nekompatibilni. Algoritmus pro baleni je stejny (mozna se lisi nulovy exit token) ale binarni soubory jsou jiny. Kazdy prvni bajt co se nacita DEPNUM_LZE musi byt o 1 bit rotovany vlevo.
Pro zpetnou kompatibilitu to jde vylepsi tou zmenou na "or C" o jeden bajt a 4 takty.
PS: Tady
https://encode.su/threads/3001-State-of-the-art-byte-compression-(for-8-bit-computers) nekdo popisuje ty komprimacni rutiny modernim zpusobem ze dela graf jak moc to zmensuje a kolik stoji cas to rozbalit. Zajimalo by me jak si asi vede busyho (omg pise se to s malym pocatecnim? Hm.. tak s velkym B je spravne) rutina LZE a jak tahle vylepsena modifikace.
PPS: Pro pobaveni clanek z roku 1999.
http://zxm.cz/zxm/1999-2.pdfCitace:
..ale ta Busyho rutina od Matsofta byla fakt d e b i l n i.
Omg stesti ze nejsem nikdo tak znamy... tohle bych si mozna bral osobne. .)))
PPPS: Proc me to nahrazuje to slovo na D jako "jedinec s IQ 60". Cenzura