Minule sme si vynimocne ukazali najprv dekomprimacnu rutinku s tym, ze ste si mali na domacu ulohu rozmysliet ako asi bude vyzerat a co vsetko musi vykonat komprimacna rutinka. Uloha to bola pomerne zlozita, ale ja verim, ze ste ju zvladli bez vecsich problemov.
Nasa komprimacna rutinka sa musi najprv pozriet ci za sebou nasleduju aspon tri rovnake bajty. Ak nasleduju tak ich musi spocitat. Ak by ich bolo viac ako 128, musi prestat pocitat, pretoze do pocitadla poctu rovnakych bajtov by sa vyssie cislo nevoslo. Potom ulozi pocet tychto bajtov do specialneho bajtu (ktoreho dolnych 7 bitov sluzi na uchovanie poctu bajtov a siedmy bit tohto bajtu bude 1) a cely algoritmus sa opakuje od zaciatku. Ale ak za sebou nenasleduju tri rovnake bajty, tak potom musi spocitat kolko ich nasleduje nerovnakych. To znamena ze akonahle narazi na prve tri rovnake bajty, tie uz nesmie zaratat do poctu. Tiez musi kontrolovat pocitanie bajtov iba do hodnoty 128. Potom aj v tomto pripade ulozi pocet do toho specialneho bajtu (siedmy bit bude 0) a cely algoritmus ide odznova. Samozrejme ze pocas tohto vsetkeho treba testovat ci sme uz spracovali cely povodny blok - ak ano potom treba cinnost algoritmu vhodne ukoncit.
Preco prave tri rovnake bajty ? Pretoze az komprimacia troch rovnakych bajtov prinesie uzitok - skratenie skomprimovaneho bloku.
Ako vidime, algoritmus komprimacie je pomerne jednoduchy. Avsak jeho realizacia uz bude jednoducha trochu menej... Ale ked si vsimneme nasu dnesnu rutinku a pozorne si ju prejdeme tak urcite nebude problem pochopit do detailov ako pracuje.
Urcite ste si v minulej lekcii vsimli ze v popise rutinky sa spominaju dve pocitadla. Presne take iste pocitadla su aj v dnesnej rutinke. Prve, nazvane hlavne pocitadlo sluzi na odpocitavanie poctu bajtov - kolko nam este zostava dekomprimovat alebo skomprimovat. Je to vlastne pocitadlo dlzky povodneho bloku. Druhe pocitadlo je nazvane minipocitadlo a sluzi na odpocitavanie hodnoty v nizsich siedmich bitoch specialneho bajtu (pri dekomprimacii) alebo na vypocet hodnoty tychto siedmych bitov (pri komprimacii).
kom | ld | hl,#4000 | zaciatok bloku |
ld | de,#8000 | kam ulozit tento blok | |
ld | ix,#1b00 | dlzka bloku | |
rec | ld | a,xh | kontrola hl. pocitadla na nulu |
or | xl | ak je pocitadlo nulove | |
ret | z | tak hotovo a navrat | |
ld | b,#80 | inicializacia minipocitadla | |
call | zisti | su tu aspon 3 bajty rovnake ? | |
jr | nz,nek | ak nie tak sa nebude komprimovat | |
inc | de | ale ak ano tak ich treba spocitat | |
ld | (de),a | ulozenie hodnoty samotneho bajtu | |
dec | de | DE bude ukazovat na "pocet" bajtov | |
kk2 | inc | hl | ukazovatel bloku na dalsi bajt |
dec | ix | a zmensenie hlavneho pocitadla | |
ex | af,af | uschova hodnoty bajtu | |
ld | a,xh | nedosli sme medzitym na koniec | |
or | xl | zdrojoveho bloku ? | |
jr | z,kk3 | ak ano tak prestaneme pocitat bajty | |
ex | af,af | obnova hodnoty bajtu | |
inc | b | zvecsenie minipocitadla, ak pretieklo | |
jr | z,kk3 | tak potom tiez prestaneme pocitat | |
cp | (hl) | porovnanie ci este nasleduje taky | |
jr | z,kk2 | isty bajt, ak ano pocitame dalej | |
kk3 | ld | a,b | bajty sme dopocitali, preto teraz |
or | #80 | treba ulozit stav minipocitadla | |
ld | (de),a | do skomprimovaneho bloku | |
inc | de | presun ukazovatela | |
inc | de | na volnu poziciu | |
jr | rec | a znovu skok do hlavnej slucky | |
Ak sa nenasli rovnake bajty: | |||
nek | ld | (pocet+1),de | uschova pozicie minipocitadla |
inc | de | a ukazovatel na volnu poziciu | |
kk4 | call | zisti | idu za sebou tri rovnake bajty ? |
jr | z,kk5 | ak ano treba skocit | |
ld | (de),a | ulozenie jedneho bajtu | |
inc | de | posun ukazovatelov | |
inc | hl | pre ukladanie roznych bajtov | |
dec | ix | test ci sme uz presli cely | |
ld | a,xh | blok | |
or | xl | ak ano tak tiez musime skoncit | |
jr | z,kk5 | ukladanie roznych bajtov | |
inc | b | zvecsime minipocitadlo | |
jr | nz,kk4 | ak pretieklo, tiez musime skoncit | |
kk5 | ld | a,b | koniec ukladania roznych bajtov - |
and | #7f | ulozenie stavu pocitadla roznych | |
pocet | ld | (#5555),a | bajtov do skomprimovaneho bloku |
jr | rec | a skok na zaciatok hlavnej slucky | |
Test ci sa v bloku nachadzaju | |||
zisti | ld | a,(hl) | za sebou tri rovnake bajty |
inc | hl | - vezme prvy bajt | |
cp | (hl) | porovna s druhym | |
jr | nz,zzno | ak nezhoda tak hned koniec | |
inc | hl | ak zhoda tak sa este | |
cp | (hl) | porovna s tretim | |
dec | hl | Obnova zaciatocneho stavu | |
zzno | dec | hl | ukazovatela do bloku |
ret | a navrat |
Ako vidime aj v tejto rutinke sa dlzka povodneho bloku netradicne vklada do registra IX. Ak chcete mat dlzku v inom registri, urcite uz viete co mate robit (ak nie pozrite sa do minulej lekcie).
Vsimnime si v rutinke jednu zaujimavu vec: instrukciu LD (pocet+1),DE. Na tejto samotnej instrukcii este nie je nic zaujimave. Ale teraz sa pozrime na navestie "pocet" - a vidime ze je v programe a ukazuje na instrukciu LD (#5555),A !!! Tato instrukcia ma operacny kod dlhy presne jeden bajt a za tymto operacnym kodom nasleduje dost nepochopitelne cislo #5555. Ked si lepsie vsimneme prvu instrukciu LD (pocet+1),DE zistime ze tato instrukcia zapisuje register DE prave na tu adresu pameti, kde sa nachadza toto nepochopitelne cislo. Cize vlastne pri pisani rutinky je uplne jedno aku hodnotu napisete namiesto #5555, aj tak sa tato hodnota v priebehu prace programu modifikuje.
Prave toto zaraduje nasu rutinku do triedy tzv. "samomodifikujucich sa programov" - to znamena ze kod rutinky sa v priebehu prace meni. To ale tiez znamena ze tato rutinka by nemohla funguvat keby bola v romke alebo v ramke so zakazanym zapisom. O samomodifikujucich sa programoch este budeme pisat v niektorej z nasledujucich lekcii.
Vas Busy.