Kompresja od środkaKompresja danych to tylko połowa sukcesu. Nigdy do końca nie wiadomo, czy kompresja przebiega prawidłowo, dopóki nie powstaną procedury DEKOMPRESJI, czyli odkodowywania. Dziś ostatnia część tych procedur. Tym, którzy potrafili napisać je sami składam gratulacje - naprawdę to nie jest takie łatwe! A więc do roboty. Pobierzmy jeden bit. Sprawdźmy, czy podczas procedury CIO nie wystąpił błąd (jeśli znacznik N jest ustawiony, to znaczy, że wystąpił) lub czy plik nie został odczytany w całości. * rozpakowywanie deco_f jsr getbit bpl *+5 jmp deco_erSkontrolujmy flagę C procesora. W przypadku ustawienia znaczy to, że następny będzie tylko jeden bajt. bcs only_youFlaga skasowana świadczy o większej ilości takich samych bajtów. Stała OUTBIT była dokładnie opisywana w poprzednim odcinku, lecz skupienie większej uwagi na jej wartości nie będzie błędem. Wartość stałej znacznie wpływa na stopień kompresji danych, np. dla danych, w których liczba pojedynczych bajtów nie przekracza trzech (np.tekst) stała powinna przyjąć wartość dwa; dla danych, w których liczba bajtów nie przekracza siedmiu znaków (np. fonty, skomplikowane obrazki w grafice 8) stałą należy przyjąć równą trzy. Dla pozostałych zbiorów wartość stałej można wybierać doświadczalnie, pamiętając o tym, że Jej wartość nie jest zapamiętywana przez ATARI. Zmusza to użytkownika do stosowania różnych wersji programu do różnego rodzaju plików. Szybko przekonacie się jednak, że istnieją o wiele wydajniejsze algorytmy kompresji i odstąpicie od PSE. Powróćmy jednak do naszych wskaźników. Pobierz wskaźnik o długości OUTBIT bitów i zapamiętaj jego wartość w zmiennej deco_cnt. ldx #outbit jsr gt_xbit bpl *+5 jmp deco_er sta deco_cntNastępnie odbierz znak o długości ośmiu bitów, który się powtarza i przechowaj go. jsr gt_8bit bpl *+5 jmp deco_er sta rebyteKolejno odczytując wartość znaku, zapisuj go w pamięci. deco_p lda rebyte jsr put_onePrzed zapisaniem bajtu sprawdźmy, czy jest miejsce na jego wpisanie. Znacznik C skasowany - jest miejsce. bcc deco_jZnacznik ustawiony - niestety, miejsca brak. Odpowiedni komunikat poinformuje nas o tym niezwykłym fakcie. deco_t ldx #long_m jsr dsp_msg jmp decodeZmniejszmy licznik powtórzeń znaku. deco_j dec deco_cnt deco_cnt equ *+1 lda #0 -*Porównajmy wartość licznika z liczbą $ff. Nie jest ona przypadkowa, dlaczego nie porównać go z zerem, lub nie sprawdzić czy nie osiągnął wartości ujemnej przez BMI? Ja wiem, a Wy wiecie? Piszcie! cmp #$ff bne deco_p jmp deco_fDo wysłania pojedynczy bajt. only_you equ * jsr gt_8bit bpl *+5 jmp deco_er jsr put_one bcs deco_t - brak miejscaWszystkie dotychczasowe operacje powtarzaj w kółko aż do odczytania wszystkich bajtów pliku lub całkowitego wypełnienia pamięci danymi. jmp deco_fNa koniec wystarczy sprawdzić, czy przyczyną przerwania procesu odkodowywania był błąd transmisji czy zakończenie pliku. deco_er cpy #eof beg deco_out jmp decodeZostał osiągnięty koniec pliku. deco_out ldx #chn1 jsr closeZapytajmy o specyfikacje zbioru do zapisu, otwórzmy plik i wyślijmy cały plik, uprzednio obliczając jego długość. ldx #put_m jsr get_text bpl *+5 jmp decode ldx #chn1 lda #8 jsr open bmi deco_out sec lda pse_z0 sbc bufa sta io_len,x lda pse_z0+1 sbc bufa+1 sta io_len+1,x jsr mcio jmp deco_outI to już koniec kompresji metodą Powtarzających Się Elementów. Wszyscy, którzy zrozumieli, na czym ona polega mogą przystąpić do czytania dalszej części artykułu. Pozostali niechaj wysilą swe szare robaczki i zaczną od początku. Dla wszystkich, którzy lubią wiedzieć, co się dzieje i widzieć, jak się dzieje pozostaje dopisać poniższe procedury, które sprawią, że po naciśnięciu klawisza SHIFT podana zostanie wiadomość o ilości przeglądniętych (spakowanych) danych. Aby uzyskać wynik wyrażony procentowo należy skorzystać z wzoru: K=(X/Y)*100% gdzie: X - zmienna określająca liczbę spakowanych danych. W końcowej fazie kodowania zmienna przyjmie wartość Y - cały plik poddany kompresji. Y - stała wyrażająca rozmiar całego pliku objętego kompresją. Ze względu na bardzo prostą budowę procedur, co wiąże się z bardzo dużym czasem wykonywania, wynik będzie wyświetlany wówczas, gdy użytkownik naciśnie klawisz SHIFT. Dane te aktualizowane będą, jeżeli klawisz nie zostanie zwolniony. Powtórne naciśnięcie spowoduje kolejną aktualizację. lda skctl and #shift bne comp_c - SHIFT zwolniony!Wartość zmiennej X obliczymy w bardzo prosty sposób, odejmując od aktualnej pozycji wskaźnika kodowania (PSE_ZO) wartość początku bufora kompresji (BUFA). Starszy bajt wyniku przekażmy w rejestrze X, zaś młodszy w akumulatorze. * wyświetl wyniki pakowania sec lda pse_z0 sbc bufa pha lda pse_z0+1 sbc bufa+1 tax plaWynik wyświetlony zostanie w szóstej pozycji za obecną pozycją kursora na ekranie. ldy #6 jsr prnt_prcPowyższe linie należy dołączyć do listingu z poprzedniego odcinka przed etykietą COMP_B EQU *+1 (końcówka bloku kompresji). Niezależnie od nas pokażmy uzyskane wyniki pakowania. Zmienna WRITE zawiera liczbę wysłanych pełnych bajtów. * wyświetl wyniki kompresji ldy #6 lda write ldx write+1 jsr prntprcPrzenieśmy kursor do następnej linii, aby wyświetlany kolejny tekst nie zniszczył naszej informacji. lda #eol jsr dscharPowyższy fragment należy umieścić przed ostatnią linią w bloku kompresji (przed JMP CODE_OUT). * wyślij procentowo * uzyskane wyniki prnt_prc sta prc_lsb stx prc_msb lda #0 sta prc_r sta prc_r+1 sta prc_r+2 * dodaj do siebie 100 razy * otrzymaną wartość ldx #100 pr_pl clc lda prc_lsb adc prc_r sta prc_r lda prc_r+1 adc prc_msb sta prc_r+1 bcc *+5 inc prc_r+2 dex bne pr_pl * wynik dodawania podziel * przez READ stosując * kolejne odejmowanie pr_pd sec lda prc_r sbc read sta prc_r lda prc_r+1 sbc read+1 sta prc_r+1 lda prc_r+2 sbc #0 sta prc_r+2 bcc pr_pt inx bne pr_pdW rejestrze X otrzymamy wynik obliczeń podany w procentach. Pozostaje jedynie doprowadzić go do czytelnej postaci i pokazać na ekranie. pr_pt stx byte lda #')'-$20 jsr to_msg lda #'%'-$20 jsr to_msg jsr convr jsr word jsr disp_2 lda word+1 jsr disp_1 lda #'('-$20 jmp to_msg disp_2 pha jsr disp_1 pla lsr @ lsr @ lsr @ lsr @ disp_1 and #%00001111 ora #'0'-$20 to_msg sta (savmsg),y dey rts convr lda #0 sta word sta word+1 lda #8 sed cv1 asl byte lda word adc word sta word rol word+1 dex bne cv1 cld rts byte org *+1 word org *+2 prc_lsb org *+1 prc_msb org *+1 prc_r org *+3Wszystkie powyższe procedury celowo nie są skomplikowane, co łączy się z olbrzymim czasem wykonywania. Jak inaczej można pomnożyć lub podzielić liczbę trzybajtową pozostanie tajemnicą aż do następnego odcinka. Za miesiąc pełny opis nowej, lepszej, wydajniejszej metody zwanej Imploding. MATHNOID'93
P.S. Szczególne podziękowania dla M-y P. oraz A.P. za wyrozumiałość podczas powstawania artykułu. |