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_er
Skontrolujmy flagę C procesora. W przypadku ustawienia znaczy to, że następny będzie tylko jeden bajt.
bcs only_you
Flaga 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_cnt
Nastę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 rebyte
Kolejno odczytując wartość znaku, zapisuj go w pamięci.
deco_p lda rebyte
jsr put_one
Przed zapisaniem bajtu sprawdźmy, czy jest miejsce na jego wpisanie. Znacznik C skasowany - jest miejsce.
bcc deco_j
Znacznik ustawiony - niestety, miejsca brak. Odpowiedni komunikat poinformuje nas o tym niezwykłym fakcie.
deco_t ldx #long_m
jsr dsp_msg
jmp decode
Zmniejszmy 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_f
Do wysłania pojedynczy bajt.
only_you equ *
jsr gt_8bit
bpl *+5
jmp deco_er
jsr put_one
bcs deco_t - brak miejsca
Wszystkie dotychczasowe operacje powtarzaj w kółko aż do odczytania wszystkich bajtów pliku lub całkowitego wypełnienia pamięci danymi.
jmp deco_f
Na koniec wystarczy sprawdzić, czy przyczyną przerwania procesu odkodowywania był błąd transmisji czy zakończenie pliku.
deco_er cpy #eof
beg deco_out
jmp decode
Został osiągnięty koniec pliku.
deco_out ldx #chn1
jsr close
Zapytajmy 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_out
I 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
pla
Wynik wyświetlony zostanie w szóstej pozycji za obecną pozycją kursora na ekranie.
ldy #6
jsr prnt_prc
Powyż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 prntprc
Przenieśmy kursor do następnej linii, aby wyświetlany kolejny tekst nie zniszczył naszej informacji.
lda #eol
jsr dschar
Powyż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_pd
W 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 *+3
Wszystkie 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. |