Quido
Z PMD 85 Infoserver
(Drobné opravy a doplnenie downloadu) |
(Aktualizácia verzie utility Quido) |
||
6 medziľahlých revízií nie je zobrazených. | |||
Riadok 1: | Riadok 1: | ||
{{VelkyNadpis|Quido}} | {{VelkyNadpis|Quido}} | ||
+ | |||
+ | {{Infobox Software | ||
+ | | name = QUIDO | ||
+ | | licence = Copyright © 2016 RM-TEAM | ||
+ | | author = Roman Bórik | ||
+ | | version = v1.4 ''(8/2016)'' | ||
+ | | operating_system = windows {{!}} unix | ||
+ | | language = angličtina | ||
+ | | download = '''[[download:118|quido14.zip]]''' - ZIP archív obsahujúci binárky pre win32 konzolu a Linux + zdrojové texty Quida a zdrojové texty rozpakovacích rutín | ||
+ | }} | ||
__TOC__ | __TOC__ | ||
- | Quido je PC utilita určená pre pakovanie dát a programov pre (obvykle) 8 bitové počítače. Quido, ako taký, pôvodne vznikol ako obrazovková utilita pre [http:// | + | Quido je PC utilita určená pre pakovanie dát a programov pre (obvykle) 8 bitové počítače. Quido, ako taký, pôvodne vznikol ako obrazovková utilita pre [http://blog.borik.net/2008/11/quido-v12.html ZX Spectrum], ale keďže pri tvorbe novej hry [[Kvádro]] pre [[PMD 85]] kvôli nedostatku miesta v pamäti vznikla nutnosť mať "nepotrebné" dáta spakované, prepísal som Quida v jazyku C ako utilitu pre PC. Myšlienka preportovania Quida na PMD 85 bola zavrhnutá okamžite kvôli pomerne komplikovaným algoritmom, ktoré by sa v assembleri i8080 písali veľmi problematicky (i keď by to nebolo nemožné) a zároveň by samotné pakovanie na PMD 85 trvalo odhadom dva až tri-krát dlhšie, ako na ZX Spectre. Quido okrem spakovania daných dát poskytuje možnosť pripojiť k spakovaným dátam aj rozpakovaciu rutinu a vytvoriť aj súbor pásky pre emulátory. |
== Základné vlastnosti == | == Základné vlastnosti == | ||
Riadok 13: | Riadok 23: | ||
* možnosť uložiť iba samotný spakovaný blok dát | * možnosť uložiť iba samotný spakovaný blok dát | ||
* možnosť uložiť spakované dáta vrátane rozpakovacej rutiny, ktorá môže byť buď vo verzii pre Z80 alebo vo verzii pre Intel 8080; naviac, v prípade PMD 85 môže byť rozpakovacia rutina umiestnená do nevyužitej oblasti VRAM | * možnosť uložiť spakované dáta vrátane rozpakovacej rutiny, ktorá môže byť buď vo verzii pre Z80 alebo vo verzii pre Intel 8080; naviac, v prípade PMD 85 môže byť rozpakovacia rutina umiestnená do nevyužitej oblasti VRAM | ||
- | * uloženie výsledku do súboru pásky PTP (PMD 85) alebo TAP (ZX Spectrum); v prípade TAP môže byť naviac pridaný aj BASICový zavádzač (ako to robí utilita bin2tap) | + | * uloženie výsledku do súboru pásky PTP (PMD 85) alebo TAP (ZX Spectrum); v prípade TAP môže byť naviac pridaný aj BASICový zavádzač (ako to robí utilita [http://zeroteam.sk/bin2tap.html bin2tap]) |
- | Algoritmus Implodu je prevzatý, resp. vychádza z algoritmu Turbo Implodera a tak aj Quido môže pri pakovaní zlyhať. Najkritickejším okamihom je úvod pakovania, teda prípad, kedy na konci dát (Módy 1 a 2), resp. na začiatku dát (Módy 3 a 4) nie je pakovateľná sekvencia. Dôvodom je skutočnosť, že v takomto prípade flag byte označujúci nepakovateľné dáta prekryje pôvodné dáta. Táto skutočnosť je o to nepríjemnejšia, že dáta ako celok s najväčšou pravdepodobnosťou pakovateľné sú a problémovým miestom je iba úvod dát. V tomto prípade je riešením | + | Algoritmus Implodu je prevzatý, resp. vychádza z algoritmu Turbo Implodera a tak aj Quido môže pri pakovaní zlyhať. Najkritickejším okamihom je úvod pakovania, teda prípad, kedy na konci dát (Módy 1 a 2), resp. na začiatku dát (Módy 3 a 4) nie je pakovateľná sekvencia. Dôvodom je skutočnosť, že v takomto prípade flag byte označujúci nepakovateľné dáta prekryje pôvodné dáta. Táto skutočnosť je o to nepríjemnejšia, že dáta ako celok s najväčšou pravdepodobnosťou pakovateľné sú a problémovým miestom je iba úvod dát. V tomto prípade je riešením (pokiaľ je to možné) rozšírenie dát o vhodne dlhú sekvenciu rovnakých bytov buď na začiatku alebo na konci dát. Na to má utilita prepínače {{Príkaz|-ei}}, {{Príkaz|-ez}} alebo {{Príkaz|-em}}. K zlyhaniu môže pochopiteľne dôjsť aj v priebehu pakovania, pokiaľ sa zdrojový a cieľový ukazovateľ stretnú. |
== Použitie == | == Použitie == | ||
Riadok 21: | Riadok 31: | ||
Quido je konzolová utilita, takže sa dá s výhodou použíť v dávkových súboroch. Požadované chovanie utility sa volí príslušnými prepínačmi. V hranatých zátvorkách sú uvedené defaultné hodnoty parametrov, pokiaľ sa daný prepínač nepoužije. | Quido je konzolová utilita, takže sa dá s výhodou použíť v dávkových súboroch. Požadované chovanie utility sa volí príslušnými prepínačmi. V hranatých zátvorkách sú uvedené defaultné hodnoty parametrov, pokiaľ sa daný prepínač nepoužije. | ||
- | + | Príkazový riadok: | |
- | + | {{Príkaz|quido [prepinace] vstupny_subor.ext}} | |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | * {{Príkaz|-o vystup.ext}}<br />určuje názov výstupného súboru. Pokiaľ sa neuvedie, výstupný súbor bude mať názov podľa vstupného súboru a prípona sa zmení na "pck", "tap" alebo "ptp", podľa toho, či sa má vytvoriť súbor pásky alebo nie. | |
- | + | * {{Príkaz|-append}}<br />spôsobí, že výsledok sa pripojí na koniec výstupného súboru. Pokiaľ nie je nastavený, existujúci výstupný súbor sa prepíše. | |
- | + | * {{Príkaz|-m 1234}}<br />umožňuje voľbu módov pakovania. Za prepínačom môže byť akákoľvek kombinácia číslic 1 až 4. Quido použije na pakovanie iba uvedené módy. {{GreyKbd|[1234]}} | |
- | + | * {{Príkaz|-z80}}<br />vloží pred dáta rozpakovciu rutinu pre Z80. | |
- | + | * {{Príkaz|-i8080}}<br />vloží pred dáta rozpakovciu rutinu pre Intel 8080. | |
- | + | * {{Príkaz|-a adresa}}<br />určuje adresu, kde majú ležať rozpakované dáta a zároveň aj adresu od ktorej sa spúšťa samotné rozpakovanie. Defaultné hodnoty sa líšia pre Z80 a i8080 a sú obvyklé pre ZX Spectrum, či PMD 85. {{GreyKbd|[32768 (z80) / 0 (i8080)]}} | |
- | + | * {{Príkaz|-ra adresa}}<br />určuje adresu kam sa umiestni rozpakovacia rutina. {{GreyKbd|[23456 (z80) / 32512 (i8080)]}} | |
- | + | * {{Príkaz|-ja adresa}}<br />určuje adresu kam sa skočí po rozpakovaní dát. Pokiaľ sa neuvedie, prevedie sa návrat inštrukciou RET. | |
- | + | * {{Príkaz|-ei}}<br />pri nemožnosti dáta spakovať sa dáta rozšíria o niekoľko núl a pakovanie sa zopakuje (ina módy 1 a 2). | |
- | + | * {{Príkaz|-ez}}<br />vstupné dáta sa rozšíria o niekoľko núl implicitne. | |
- | + | * {{Príkaz|-em size}}<br />vstupné dáta budú rozšírené maximálne do {{GreyKbd|[size]}} bytov. | |
- | + | * {{Príkaz|-force}}<br />do výstupného súboru pôvodné nepakované dáta, ak je pakovanie neúspešné. | |
- | + | * {{Príkaz|-vb}}<br />Quido bude pri pakovaní "ukecanejší". | |
- | + | * {{Príkaz|-h}}<br />zobrazí "help" | |
- | + | * {{Príkaz|-v}}<br />zobrazí verziu programu | |
- | + | ||
- | + | ||
- | + | '''Možnosti špecifické pre PMD 85:''' | |
- | + | ||
- | + | * {{Príkaz|-ptp}}<br />výsledok sa uloží do [[PTP]] súboru pásky pre [[Emulátor]] PMD 85. | |
- | + | * {{Príkaz|-n name}}<br />názov bloku v PTP (max. 8 znakov). | |
- | + | * {{Príkaz|-p}}<br />pred rozpakovaciu rutinu vloží "prolog" - kód pre prepnutie do [[AllRAM]] módu. | |
- | + | * {{Príkaz|-sp address}}<br />adresa SP registra pre "prolog" [49152]. | |
- | + | * {{Príkaz|-vram}}<br />rozpakovacia rutina bude relokovaná tak, aby mohla byť umiestnená do nevyužitej oblasti VRAM PMD 85. V tomto prípade ale zvolená adresa umiestnenia rutiny prepínačom {{Príkaz|-ra}} musí spĺňať nasledujúcu podmienku:<br />''addr >= 0xC030 AND addr <= 0xFDF0 AND (addr & 0xC03F) = 0xC030'' | |
- | + | ||
- | + | ||
- | + | '''Možnosti špecifické pre ZX-Spectrum:''' | |
- | + | ||
- | + | * {{Príkaz|-tap}}<br />výsledok sa uloží do TAP súboru pásky pre ZX Spectrum emulátory. | |
- | + | * {{Príkaz|-n name}}<br />názov bloku v TAP (max. 10 znakov). | |
- | + | * {{Príkaz|-b}}<br />do pásky sa pred spakovaný blok dát vloží BASICový loader. | |
- | + | * {{Príkaz|-c adresa}}<br />adresa pre príkaz 'CLEAR adr' v BASICovom loaderi. {{GreyKbd|[24575]}} | |
- | + | * {{Príkaz|-r adresa}}<br />adresa pre príkaz 'RANDOMIZE USR adr' v BASICovom loaderi. {{GreyKbd|[32768]}} | |
- | + | * {{Príkaz|-cb}}<br />voľba farby BORDER pre BASICovy loader. {{GreyKbd|[0]}} | |
+ | * {{Príkaz|-cp}}<br />voľba farby PAPER pre BASICovy loader. {{GreyKbd|[0]}} | ||
+ | * {{Príkaz|-ci}}<br />voľba farby INK pre BASICovy loader. {{GreyKbd|[7]}} | ||
+ | * {{Príkaz|-d80}}<br />príkaz LOAD bude obsahovať '*' pre nahratie súboru z diskety. | ||
+ | * {{Príkaz|-hp}}<br />pred riadok s príkazom LOAD vloží príkaz POKE pre zamedzenie výpisu kazetových hlavičiek. | ||
+ | |||
+ | |||
+ | Všetky číselné hodnoty je možné zadávať v týchto troch číselných sústavách: | ||
+ | * desiatkovo (decimal): {{Príkaz|12345}} | ||
+ | * osmičkovo (octal): {{Príkaz|01234}} | ||
+ | * šestnástkovo (hexadecimal): {{Príkaz|0x1234}} | ||
== Módy pakovania == | == Módy pakovania == | ||
Riadok 91: | Riadok 93: | ||
Pre reprezentáciu pakovaných dát sa používa značkový flag byte, ktorý informuje o type nasledujúcich dát. Značkový byte pre Implod je uvedený pre oba prípady a v samotných pakovaných dátach sa vyskytuje pochopiteľne iba jeden z nich podľa módu pakovania. Pre módy 1 a 2 platí uvedené poradie flag bytu a dát. V prípade módov 3 a 4 sú pakované dáta v opačnom poradí. | Pre reprezentáciu pakovaných dát sa používa značkový flag byte, ktorý informuje o type nasledujúcich dát. Značkový byte pre Implod je uvedený pre oba prípady a v samotných pakovaných dátach sa vyskytuje pochopiteľne iba jeden z nich podľa módu pakovania. Pre módy 1 a 2 platí uvedené poradie flag bytu a dát. V prípade módov 3 a 4 sú pakované dáta v opačnom poradí. | ||
- | * IMPLOD - offset ku kopírovanej fráze 12 bitov / 4kB, dĺžka frázy 3 bity / 3 až 10 bytov | + | * '''IMPLOD''' - offset ku kopírovanej fráze 12 bitov / 4kB, dĺžka frázy 3 bity / 3 až 10 bytov |
- | + | {| cellpadding="0" cellspacing="0" border="0" class="wikitable" | |
- | + | |- | |
- | + | | width="70" | | |
- | + | ! width="25" | 7 | |
- | + | ! width="25" | 6 | |
- | + | ! width="25" | 5 | |
- | + | ! width="25" | 4 | |
- | + | ! width="25" | 3 | |
+ | ! width="25" | 2 | ||
+ | ! width="25" | 1 | ||
+ | ! width="25" | 0 | ||
+ | |- | ||
+ | | [0] flag | ||
+ | | align="center" | 0 | ||
+ | | align="center" colspan="3" | {{Príkaz|FR_LEN-3}} | ||
+ | | align="center" colspan="4" | {{Príkaz|OFFSET_HI}} | ||
+ | |- | ||
+ | | [1] | ||
+ | | align="center" colspan="8" | {{Príkaz|OFFSET_LO}} | ||
+ | |} | ||
- | * IMPLOD - offset ku kopírovanej fráze 11 bitov / 2kB, dĺžka frázy 4 bity / 3 až 18 bytov | + | * '''IMPLOD''' - offset ku kopírovanej fráze 11 bitov / 2kB, dĺžka frázy 4 bity / 3 až 18 bytov |
- | + | {| cellpadding="0" cellspacing="0" border="0" class="wikitable" | |
- | + | |- | |
- | + | | width="70" | | |
- | + | ! width="25" | 7 | |
- | + | ! width="25" | 6 | |
- | + | ! width="25" | 5 | |
- | + | ! width="25" | 4 | |
- | + | ! width="25" | 3 | |
+ | ! width="25" | 2 | ||
+ | ! width="25" | 1 | ||
+ | ! width="25" | 0 | ||
+ | |- | ||
+ | | [0] flag | ||
+ | | align="center" | 0 | ||
+ | | align="center" colspan="3" | {{Príkaz|OFFSET_HI}} | ||
+ | | align="center" colspan="4" | {{Príkaz|FR_LEN-3}} | ||
+ | |- | ||
+ | | [1] | ||
+ | | align="center" colspan="8" | {{Príkaz|OFFSET_LO}} | ||
+ | |} | ||
- | * Dlhý SHRINK - počet opakovaných bytov 67 až 322 | + | * '''Dlhý SHRINK''' - počet opakovaných bytov 67 až 322 |
- | + | {| cellpadding="0" cellspacing="0" border="0" class="wikitable" | |
- | + | |- | |
- | + | | width="70" | | |
- | + | ! width="25" | 7 | |
- | + | ! width="25" | 6 | |
- | + | ! width="25" | 5 | |
- | + | ! width="25" | 4 | |
- | + | ! width="25" | 3 | |
- | + | ! width="25" | 2 | |
- | + | ! width="25" | 1 | |
- | + | ! width="25" | 0 | |
- | + | |- | |
+ | | [0] flag | ||
+ | | align="center" | 1 | ||
+ | | align="center" | 0 | ||
+ | | align="center" | 0 | ||
+ | | align="center" | 0 | ||
+ | | align="center" | 0 | ||
+ | | align="center" | 0 | ||
+ | | align="center" | 0 | ||
+ | | align="center" | 0 | ||
+ | |- | ||
+ | | [1] | ||
+ | | align="center" colspan="8" | {{Príkaz|COUNT-67}} | ||
+ | |- | ||
+ | | [2] | ||
+ | | align="center" colspan="8" | {{Príkaz|REPT_BYTE}} | ||
+ | |} | ||
- | * Krátky SHRINK - počet opakovaných bytov 3 až 66 | + | * '''Krátky SHRINK''' - počet opakovaných bytov 3 až 66 |
- | + | {| cellpadding="0" cellspacing="0" border="0" class="wikitable" | |
- | + | |- | |
- | + | | width="70" | | |
- | + | ! width="25" | 7 | |
- | + | ! width="25" | 6 | |
- | + | ! width="25" | 5 | |
- | + | ! width="25" | 4 | |
- | + | ! width="25" | 3 | |
+ | ! width="25" | 2 | ||
+ | ! width="25" | 1 | ||
+ | ! width="25" | 0 | ||
+ | |- | ||
+ | | [0] flag | ||
+ | | align="center" | 1 | ||
+ | | align="center" | 1 | ||
+ | | align="center" colspan="6" | {{Príkaz|COUNT-3}} | ||
+ | |- | ||
+ | | [1] | ||
+ | | align="center" colspan="8" | {{Príkaz|REPT_BYTE}} | ||
+ | |} | ||
- | * Nepakovateľné - počet nepakovateľných bytov 1 až 63 | + | * '''Nepakovateľné''' - počet nepakovateľných bytov 1 až 63 |
- | + | {| cellpadding="0" cellspacing="0" border="0" class="wikitable" | |
- | + | |- | |
- | + | | width="70" | | |
- | + | ! width="25" | 7 | |
- | + | ! width="25" | 6 | |
- | + | ! width="25" | 5 | |
- | + | ! width="25" | 4 | |
- | + | ! width="25" | 3 | |
- | + | ! width="25" | 2 | |
- | + | ! width="25" | 1 | |
- | + | ! width="25" | 0 | |
- | + | |- | |
- | + | | [0] flag | |
- | + | | align="center" | 1 | |
+ | | align="center" | 0 | ||
+ | | align="center" colspan="6" | {{Príkaz|COUNT}} | ||
+ | |- | ||
+ | | [1]<br /> ...<br />[n] | ||
+ | | align="center" colspan="8" | {{Príkaz|...<br />BYTES<br />...}} | ||
+ | |} | ||
== Rozpakovacia rutina == | == Rozpakovacia rutina == | ||
Riadok 194: | Riadok 254: | ||
|} | |} | ||
- | Pre zaujímavosť ešte | + | Pre zaujímavosť ešte uvedieme zdrojový kód rozpakovacej rutiny pre i8080 pre mód 1, ostatné verzie sú analogické a sú súčasťou archívu na stiahnutie: |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | == | + | UnpackMode1: LXI H,M1 |
+ | LXI D,RoutineAddr | ||
+ | MVI B,M1Length | ||
+ | PUSH D | ||
+ | UnpackMode1_L: MOV A,M | ||
+ | STAX D | ||
+ | INX H | ||
+ | INX D | ||
+ | DCR B | ||
+ | JNZ UnpackMode1_L | ||
+ | LXI H,Data1+PackedLength-1 | ||
+ | LXI D,BeginAddr+OrigLength-1 | ||
+ | LXI B,PackedLength | ||
+ | RET | ||
+ | Mover1Length equ $-UnpackMode1 ; 27 bytov | ||
+ | |||
+ | M1: CALL M1Move ; presun pakovane data na koniec oblasti, kde az | ||
+ | LXI H,1323h ; budu vysledne rozpakovane data zasahovat | ||
+ | SHLD M1MoveID ; uprav kopirovaciu rutinu na opacny smer | ||
+ | XCHG | ||
+ | LXI D,BeginAddr ; zaciatocna adresa vyslednych dat | ||
+ | INX H ; adresa spakovanych dat | ||
+ | M1NextByte: MOV A,M ; vezmi flag byte | ||
+ | RLC ; je to Implod ? | ||
+ | RRC | ||
+ | JC M1NoImplod ; nie, skoc dalej | ||
+ | ANI 15 ; odmaskuj vyssie 4 bity offsetu ku kopirovanej fraze | ||
+ | MOV B,A ; uloz do B | ||
+ | MOV A,M ; dlzku frazy presun do A | ||
+ | RRC | ||
+ | RRC | ||
+ | RRC | ||
+ | RRC | ||
+ | ANI 7 | ||
+ | ADI 3 ; uprav na spravny rozsah 3 az 10 | ||
+ | MOV C,A ; a uloz do C | ||
+ | INX H ; posun ukazatel na nizsi byte offsetu frazy | ||
+ | MOV A,E ; odpocitaj nizsi byte offsetu | ||
+ | SUB M | ||
+ | INX H ; posun ukazatel na spakovane data | ||
+ | PUSH H ; a odloz si ho | ||
+ | MOV L,A ; uloz nizsi byte adresy zdrojovej frazy | ||
+ | MOV A,D ; a odpocitaj aj vyssi byte offsetu | ||
+ | SBB B | ||
+ | MOV H,A ; HL=zdrojova adresa frazy | ||
+ | MVI B,0 ; BC=dlzka frazy | ||
+ | JMP M1FillBlock | ||
+ | |||
+ | M1NoImplod: INX H ; posun ukazatel na spakovane data | ||
+ | ANI 127 ; odmaskuj iba platne bity | ||
+ | JZ M1BigBlock ; je to dlhy Shrink ? Ak ano, skoc dalej | ||
+ | CPI 64 ; je to kratky Shrink ? | ||
+ | JNC M1LitBlock ; ano, skoc dalej | ||
+ | MOV C,A ; su to nepakovatelne data - BC=pocet | ||
+ | CALL M1Move ; presun na cielovu adresu v DE | ||
+ | JMP M1NextByte ; spracuj dalsi flag | ||
+ | |||
+ | M1LitBlock: ANI 63 ; pocet rovnakych bytov | ||
+ | ADI 3-1 ; uprav pocet na 3 az 66 - bez jedneho, ktory | ||
+ | JMP M1Block ; sa predpripravi | ||
+ | |||
+ | M1BigBlock: MOV A,M ; pocet rovnakych bytov | ||
+ | INX H ; posun ukazatel na spakovane data | ||
+ | ADI 67-1 ; uprav velkost na 67 az 322 - bez jedneho, ktory | ||
+ | JNC M1Block ; sa predpripravi | ||
+ | INR B | ||
+ | M1Block: MOV C,A ; BC=pocet | ||
+ | MOV A,M ; skopiruj opakujuci sa byte | ||
+ | INX H | ||
+ | STAX D | ||
+ | PUSH H ; odpamataj ukazatel spakovanych dat | ||
+ | MOV H,D ; budeme vyplnovat | ||
+ | MOV L,E | ||
+ | INX D ; DE=HL+1, BC=pocet-1 | ||
+ | M1FillBlock: CALL M1Move ; prekopiruj/vypln blok | ||
+ | POP H ; obnov ukazatel na spakovane data | ||
+ | MOV A,H ; ak sa DE s HL stretnu, je to koniec rozpakovania | ||
+ | CMP D | ||
+ | JNZ M1NextByte ; opakuj pre cely blok | ||
+ | MOV A,L | ||
+ | CMP E | ||
+ | JNZ M1NextByte ; opakuj pre cely blok | ||
+ | JMP RunAddr ; skok na zvolenu adresu alebo navrat cez RET | ||
+ | |||
+ | ; Rutina pre presun/kopirovanie/vyplnanie - modifikuje sa pre zmenu smeru | ||
+ | M1Move: MOV A,M | ||
+ | STAX D | ||
+ | M1MoveID: DCX H ; INX H | ||
+ | DCX D ; INX D | ||
+ | DCX B | ||
+ | MOV A,B | ||
+ | ORA C | ||
+ | JNZ M1Move | ||
+ | RET | ||
+ | |||
+ | M1Length equ $-M1 ; 116 bytov | ||
+ | |||
+ | Data1: ds PackedLength ; samotne pakovane data | ||
- | + | [[Category:Utility]] |
Aktuálna verzia
QUIDO | |
Autor: | Roman Bórik |
---|---|
Verzia: | v1.4 (8/2016) |
Operačný systém: | windows | unix |
Lokalizácia: | angličtina |
Licencia: | Copyright © 2016 RM-TEAM |
Download: | quido14.zip - ZIP archív obsahujúci binárky pre win32 konzolu a Linux + zdrojové texty Quida a zdrojové texty rozpakovacích rutín |
Obsah |
Quido je PC utilita určená pre pakovanie dát a programov pre (obvykle) 8 bitové počítače. Quido, ako taký, pôvodne vznikol ako obrazovková utilita pre ZX Spectrum, ale keďže pri tvorbe novej hry Kvádro pre PMD 85 kvôli nedostatku miesta v pamäti vznikla nutnosť mať "nepotrebné" dáta spakované, prepísal som Quida v jazyku C ako utilitu pre PC. Myšlienka preportovania Quida na PMD 85 bola zavrhnutá okamžite kvôli pomerne komplikovaným algoritmom, ktoré by sa v assembleri i8080 písali veľmi problematicky (i keď by to nebolo nemožné) a zároveň by samotné pakovanie na PMD 85 trvalo odhadom dva až tri-krát dlhšie, ako na ZX Spectre. Quido okrem spakovania daných dát poskytuje možnosť pripojiť k spakovaným dátam aj rozpakovaciu rutinu a vytvoriť aj súbor pásky pre emulátory.
Základné vlastnosti
Quido používa pri pakovaní dva algoritmy. Prvým je Shrink a druhým Implod. Tieto dva algoritmy sa v priebehu pakovania striedajú, resp. sa na práve nasledujúcom bloku dát aplikujú oba tieto algoritmy a do pakovaného prúdu dát sa použije ten, ktorý vyšiel lepšie. To bol aj dôvod, prečo pôvodná Speccy verzia Quida pakovala aj dva-krát dlhšie, ako Turbo Imploder. V prípade PC verzie je čas pakovania pochopiteľne zanedbateľný.
- maximálna veľkosť zdrojového súboru je 49152 bytov
- 4 voliteľné módy pakovania (detailne ďalej) - pokiaľ sa užívateľ nerozhodne inak, Quido vyskúša všetky 4 módy a použije ten, ktorý vyšiel najlepšie
- možnosť uložiť iba samotný spakovaný blok dát
- možnosť uložiť spakované dáta vrátane rozpakovacej rutiny, ktorá môže byť buď vo verzii pre Z80 alebo vo verzii pre Intel 8080; naviac, v prípade PMD 85 môže byť rozpakovacia rutina umiestnená do nevyužitej oblasti VRAM
- uloženie výsledku do súboru pásky PTP (PMD 85) alebo TAP (ZX Spectrum); v prípade TAP môže byť naviac pridaný aj BASICový zavádzač (ako to robí utilita bin2tap)
Algoritmus Implodu je prevzatý, resp. vychádza z algoritmu Turbo Implodera a tak aj Quido môže pri pakovaní zlyhať. Najkritickejším okamihom je úvod pakovania, teda prípad, kedy na konci dát (Módy 1 a 2), resp. na začiatku dát (Módy 3 a 4) nie je pakovateľná sekvencia. Dôvodom je skutočnosť, že v takomto prípade flag byte označujúci nepakovateľné dáta prekryje pôvodné dáta. Táto skutočnosť je o to nepríjemnejšia, že dáta ako celok s najväčšou pravdepodobnosťou pakovateľné sú a problémovým miestom je iba úvod dát. V tomto prípade je riešením (pokiaľ je to možné) rozšírenie dát o vhodne dlhú sekvenciu rovnakých bytov buď na začiatku alebo na konci dát. Na to má utilita prepínače -ei, -ez alebo -em. K zlyhaniu môže pochopiteľne dôjsť aj v priebehu pakovania, pokiaľ sa zdrojový a cieľový ukazovateľ stretnú.
Použitie
Quido je konzolová utilita, takže sa dá s výhodou použíť v dávkových súboroch. Požadované chovanie utility sa volí príslušnými prepínačmi. V hranatých zátvorkách sú uvedené defaultné hodnoty parametrov, pokiaľ sa daný prepínač nepoužije.
Príkazový riadok: quido [prepinace] vstupny_subor.ext
- -o vystup.ext
určuje názov výstupného súboru. Pokiaľ sa neuvedie, výstupný súbor bude mať názov podľa vstupného súboru a prípona sa zmení na "pck", "tap" alebo "ptp", podľa toho, či sa má vytvoriť súbor pásky alebo nie. - -append
spôsobí, že výsledok sa pripojí na koniec výstupného súboru. Pokiaľ nie je nastavený, existujúci výstupný súbor sa prepíše. - -m 1234
umožňuje voľbu módov pakovania. Za prepínačom môže byť akákoľvek kombinácia číslic 1 až 4. Quido použije na pakovanie iba uvedené módy. [1234] - -z80
vloží pred dáta rozpakovciu rutinu pre Z80. - -i8080
vloží pred dáta rozpakovciu rutinu pre Intel 8080. - -a adresa
určuje adresu, kde majú ležať rozpakované dáta a zároveň aj adresu od ktorej sa spúšťa samotné rozpakovanie. Defaultné hodnoty sa líšia pre Z80 a i8080 a sú obvyklé pre ZX Spectrum, či PMD 85. [32768 (z80) / 0 (i8080)] - -ra adresa
určuje adresu kam sa umiestni rozpakovacia rutina. [23456 (z80) / 32512 (i8080)] - -ja adresa
určuje adresu kam sa skočí po rozpakovaní dát. Pokiaľ sa neuvedie, prevedie sa návrat inštrukciou RET. - -ei
pri nemožnosti dáta spakovať sa dáta rozšíria o niekoľko núl a pakovanie sa zopakuje (ina módy 1 a 2). - -ez
vstupné dáta sa rozšíria o niekoľko núl implicitne. - -em size
vstupné dáta budú rozšírené maximálne do [size] bytov. - -force
do výstupného súboru pôvodné nepakované dáta, ak je pakovanie neúspešné. - -vb
Quido bude pri pakovaní "ukecanejší". - -h
zobrazí "help" - -v
zobrazí verziu programu
Možnosti špecifické pre PMD 85:
- -ptp
výsledok sa uloží do PTP súboru pásky pre Emulátor PMD 85. - -n name
názov bloku v PTP (max. 8 znakov). - -p
pred rozpakovaciu rutinu vloží "prolog" - kód pre prepnutie do AllRAM módu. - -sp address
adresa SP registra pre "prolog" [49152]. - -vram
rozpakovacia rutina bude relokovaná tak, aby mohla byť umiestnená do nevyužitej oblasti VRAM PMD 85. V tomto prípade ale zvolená adresa umiestnenia rutiny prepínačom -ra musí spĺňať nasledujúcu podmienku:
addr >= 0xC030 AND addr <= 0xFDF0 AND (addr & 0xC03F) = 0xC030
Možnosti špecifické pre ZX-Spectrum:
- -tap
výsledok sa uloží do TAP súboru pásky pre ZX Spectrum emulátory. - -n name
názov bloku v TAP (max. 10 znakov). - -b
do pásky sa pred spakovaný blok dát vloží BASICový loader. - -c adresa
adresa pre príkaz 'CLEAR adr' v BASICovom loaderi. [24575] - -r adresa
adresa pre príkaz 'RANDOMIZE USR adr' v BASICovom loaderi. [32768] - -cb
voľba farby BORDER pre BASICovy loader. [0] - -cp
voľba farby PAPER pre BASICovy loader. [0] - -ci
voľba farby INK pre BASICovy loader. [7] - -d80
príkaz LOAD bude obsahovať '*' pre nahratie súboru z diskety. - -hp
pred riadok s príkazom LOAD vloží príkaz POKE pre zamedzenie výpisu kazetových hlavičiek.
Všetky číselné hodnoty je možné zadávať v týchto troch číselných sústavách:
- desiatkovo (decimal): 12345
- osmičkovo (octal): 01234
- šestnástkovo (hexadecimal): 0x1234
Módy pakovania
Quido pakuje štyroma módmi, ktoré sa líšia smerom pakovania a vlastnosťami algoritmu Implod:
- pakuje sa spätne od konca bloku dát, veľkosť Implod okna sú 4kB a maximálna dĺžka hľadanej frázy je 10 bytov
- pakuje sa spätne od konca bloku dát, veľkosť Implod okna sú 2kB a maximálna dĺžka hľadanej frázy je 18 bytov
- pakuje sa dopredu od začiatku bloku dát, veľkosť Implod okna sú 4kB a maximálna dĺžka hľadanej frázy je 10 bytov
- pakuje sa dopredu od začiatku bloku dát, veľkosť Implod okna sú 2kB a maximálna dĺžka hľadanej frázy je 18 bytov
Shrink je pre všetky módy rovnaký a má dve "formy". Prvá, pre blok maximálne 66 opakujúcich sa bytov. Druhá, pre blok maximálne 322 opakujúcich sa bytov. Minimálna dĺžka Implod frázy, resp. minimálny počet opakujúcich sa bytov je 3.
Formát pakovaných dát
Pre reprezentáciu pakovaných dát sa používa značkový flag byte, ktorý informuje o type nasledujúcich dát. Značkový byte pre Implod je uvedený pre oba prípady a v samotných pakovaných dátach sa vyskytuje pochopiteľne iba jeden z nich podľa módu pakovania. Pre módy 1 a 2 platí uvedené poradie flag bytu a dát. V prípade módov 3 a 4 sú pakované dáta v opačnom poradí.
- IMPLOD - offset ku kopírovanej fráze 12 bitov / 4kB, dĺžka frázy 3 bity / 3 až 10 bytov
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
---|---|---|---|---|---|---|---|---|
[0] flag | 0 | FR_LEN-3 | OFFSET_HI | |||||
[1] | OFFSET_LO |
- IMPLOD - offset ku kopírovanej fráze 11 bitov / 2kB, dĺžka frázy 4 bity / 3 až 18 bytov
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
---|---|---|---|---|---|---|---|---|
[0] flag | 0 | OFFSET_HI | FR_LEN-3 | |||||
[1] | OFFSET_LO |
- Dlhý SHRINK - počet opakovaných bytov 67 až 322
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
---|---|---|---|---|---|---|---|---|
[0] flag | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
[1] | COUNT-67 | |||||||
[2] | REPT_BYTE |
- Krátky SHRINK - počet opakovaných bytov 3 až 66
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
---|---|---|---|---|---|---|---|---|
[0] flag | 1 | 1 | COUNT-3 | |||||
[1] | REPT_BYTE |
- Nepakovateľné - počet nepakovateľných bytov 1 až 63
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
---|---|---|---|---|---|---|---|---|
[0] flag | 1 | 0 | COUNT | |||||
[1] ... [n] | ... BYTES ... |
Rozpakovacia rutina
Rozpakovacia rutina a jej dĺžka sa líši podľa módu pakovavania a podľa toho, či je určená pre Z80 alebo Intel 8080. Gro rutiny je vždy rovnaké, rozdiel je iba v interpretovaní flag bytu pre Implod a smer rozpakovania.
Z80 verzia rozpakovacej rutiny potrebuje na zásobníku 4 byty, ak bola volaná pomocou CALL a predpokladá sa návrat cez RET. V opačnom prípade postačujú na zásobníku 2 byty. i8080 verzia rozpakovacej rutiny potrebuje na zásobníku 6 bytov, ak bola volaná pomocou CALL a predpokladá sa návrat cez RET. V opačnom prípade postačujú na zásobníku 4 byty.
Nasledujúca tabuľka ukazuje dĺžky jednotlivých rutín. Pred lomítkom je celková dĺžka, za lomítkom je dĺžka po prenesení na pracovné miesto. Dĺžky rutín pre i8080 sú dlhšie z niekoľkých dôvodov. i8080 nepozná relatívne skoky, takže všetky skoky sú o byte dlhšie. Z80 inštrukcie LDIR, LDDR a RLD museli byť pre i8080 zodpovedajúco "rozpísané", čo rutiny podstatne predĺžilo. Rutiny umiestnené v nevyužitej oblasti VRAM PMD 85 sú ešte dlhšie kvôli nutnosti "nasekať" ich na 16 bytové bloky, z ktorých väčšina obsahuje skok do ďalšieho 16 bytového bloku vo VRAM.
Dĺžky rozpakovacích rutín v bytoch | |||
Z80 | i8080 | i8080 pre PMD 85 VRAM | |
---|---|---|---|
Mód 1 | 101 / 79 | 143 / 116 | 177 / 139 |
Mód 2 | 103 / 81 | 143 / 116 | 177 / 139 |
Mód 3 | 98 / 79 | 140 / 116 | 177 / 139 |
Mód 4 | 100 / 81 | 140 / 116 | 177 / 139 |
Pre zaujímavosť ešte uvedieme zdrojový kód rozpakovacej rutiny pre i8080 pre mód 1, ostatné verzie sú analogické a sú súčasťou archívu na stiahnutie:
UnpackMode1: LXI H,M1 LXI D,RoutineAddr MVI B,M1Length PUSH D UnpackMode1_L: MOV A,M STAX D INX H INX D DCR B JNZ UnpackMode1_L LXI H,Data1+PackedLength-1 LXI D,BeginAddr+OrigLength-1 LXI B,PackedLength RET Mover1Length equ $-UnpackMode1 ; 27 bytov M1: CALL M1Move ; presun pakovane data na koniec oblasti, kde az LXI H,1323h ; budu vysledne rozpakovane data zasahovat SHLD M1MoveID ; uprav kopirovaciu rutinu na opacny smer XCHG LXI D,BeginAddr ; zaciatocna adresa vyslednych dat INX H ; adresa spakovanych dat M1NextByte: MOV A,M ; vezmi flag byte RLC ; je to Implod ? RRC JC M1NoImplod ; nie, skoc dalej ANI 15 ; odmaskuj vyssie 4 bity offsetu ku kopirovanej fraze MOV B,A ; uloz do B MOV A,M ; dlzku frazy presun do A RRC RRC RRC RRC ANI 7 ADI 3 ; uprav na spravny rozsah 3 az 10 MOV C,A ; a uloz do C INX H ; posun ukazatel na nizsi byte offsetu frazy MOV A,E ; odpocitaj nizsi byte offsetu SUB M INX H ; posun ukazatel na spakovane data PUSH H ; a odloz si ho MOV L,A ; uloz nizsi byte adresy zdrojovej frazy MOV A,D ; a odpocitaj aj vyssi byte offsetu SBB B MOV H,A ; HL=zdrojova adresa frazy MVI B,0 ; BC=dlzka frazy JMP M1FillBlock M1NoImplod: INX H ; posun ukazatel na spakovane data ANI 127 ; odmaskuj iba platne bity JZ M1BigBlock ; je to dlhy Shrink ? Ak ano, skoc dalej CPI 64 ; je to kratky Shrink ? JNC M1LitBlock ; ano, skoc dalej MOV C,A ; su to nepakovatelne data - BC=pocet CALL M1Move ; presun na cielovu adresu v DE JMP M1NextByte ; spracuj dalsi flag M1LitBlock: ANI 63 ; pocet rovnakych bytov ADI 3-1 ; uprav pocet na 3 az 66 - bez jedneho, ktory JMP M1Block ; sa predpripravi M1BigBlock: MOV A,M ; pocet rovnakych bytov INX H ; posun ukazatel na spakovane data ADI 67-1 ; uprav velkost na 67 az 322 - bez jedneho, ktory JNC M1Block ; sa predpripravi INR B M1Block: MOV C,A ; BC=pocet MOV A,M ; skopiruj opakujuci sa byte INX H STAX D PUSH H ; odpamataj ukazatel spakovanych dat MOV H,D ; budeme vyplnovat MOV L,E INX D ; DE=HL+1, BC=pocet-1 M1FillBlock: CALL M1Move ; prekopiruj/vypln blok POP H ; obnov ukazatel na spakovane data MOV A,H ; ak sa DE s HL stretnu, je to koniec rozpakovania CMP D JNZ M1NextByte ; opakuj pre cely blok MOV A,L CMP E JNZ M1NextByte ; opakuj pre cely blok JMP RunAddr ; skok na zvolenu adresu alebo navrat cez RET ; Rutina pre presun/kopirovanie/vyplnanie - modifikuje sa pre zmenu smeru M1Move: MOV A,M STAX D M1MoveID: DCX H ; INX H DCX D ; INX D DCX B MOV A,B ORA C JNZ M1Move RET M1Length equ $-M1 ; 116 bytov Data1: ds PackedLength ; samotne pakovane data