Zepsułem progtam na taśmie

"Zepsułem program na taśmie"

Autor: Wojciech Indyk)

Źródło: "Bajtek" 2/88

Sytuacja wydaje się beznadziejna. Zepsułem początek programu nagranego na taśmę. Nie mam listingu i w ten sposób wiele godzin spędzonych przy pisaniu programu poszło na marne (nie licząc nabytego doświadczenia). Zepsuty jest tak nagłówek jak i sygnał pilotujący wraz z początkiem programu. Była to chwila nieuwagi lub wyłączenie prądu w czasie nagrywania na taśmę w tym samym miejscu, gdzie była poprzednia wersja tego programu. AIe przecież fizycznie reszta programu na taśmie istnieje? Czy nie ma żadnej możliwości aby się do niej dobrać? Czy mam wszystko pisać od początku? Otóż nie, jeżeli znasz dobrze swój komputer i sprawa jest warta tego, aby poświęcić jej więcej czasu. Na początku trochę wiadomości ogólnych o sposobie nagrywania na taśmie przez ZX-Spectrum. Procedura ładująca i weryfikująca dowolny moduł z taśmy znajduje się w ROM-ie pod adresem #0556. Przed wywołaniem tej procedury należy umieścić w rejestrze IX adres początku wgrywanego bloku, w DE jego długość a w akumulatorze typ bloku (0-nagłówek, 255-właściwy blok). Brak ustawienia znacznika C oznacza weryfikację. Nagrana na taśmie ilość bajtów jest zawsze o 2 bajty większa od tej długości, jaką deklarujemy w rejestrach DE. Na samym początku zapisywana jest zawartość rejestru A, co umożliwia sprawdzenie rodzaju bloku, oraz na samym końcu bajt parzystości budowany na bieżąco jako funkcja XOR z wszystkich nagrywanych bajtów. Pozwala to na końcowe sprawdzenie poprawności Nczytanego bloku. W trakcie ładowania modułu do komputera jedynym sprawdzianem poprawności ładowania jest odliczanie taktów zegara między kolejnymi zboczami napięcia przychodzącymi do portu #FE. Różnica czasu przekraczająca około 2400 taktów powoduje znany nam wszystkim komunikat "Tape loading error" już w trakcie wczytywania. Nie istnieje żadne inne sprawdzanie, czy aktualna para zboczy reprezentująca "O" lub "1" należy jeszcze do poprzedniego, czy już do następnego bajtu. Po odliczeniu 8 bitów komputer oczekuje następnej ósemki, itd. aż do osiągnięcia żądanej długości bloku. Kłopot w tym, że opisana wcześniej procedura ładująca wymaga na początku sygnału pilotującego o większej dległości między zboczami oraz specjalnego impulsu synchronicznego, przed właściwym czytaniem bajtów. A przecież my właśnie to zniszczyliśmy! Może więc ominąć część tej procedury i przejść od razu do czytania poszczególnych bitów? Ale nie mamy wtedy żadnej pewności czy nasze czytanie rozpocznie się od początku bajtu! I jest to prawda. Z tym problemem postaramy się, przynajmniej częściowo, uporać później. Na razie krótki program, napisany w assemblerze, umożliwiający wykorzystanie procedury ładującej z ominięciem opisanych wcześniej kłopotów.
ADRES EQU adres	    ; tu wstawić początek bloku
ORG 65000
LD IX, ADRES        ; ustawienie adresu początku bloku w IX
LD DE, #FFFF        ; maksymalna długość (i tak	jej nie znamy)
LD C, #O6           ;ustawienie koloru ramki
XOR A               ; ustawienie znacznika Z, nie będzie 
                    ;sprawdzana zgodność pierwszego bajtu
SCF	                ; ustawienie znacznika C, adowanie
EX AF,AF'           ; przechowanie znaczników w rejestrze F'
DI                  ; wyłączenie przerwań maskowalnych
LD HL,POWR6T        ; odłożenie na stosie adresu powrotnego
PUSH HL             ; z procedury ładującej
JP #05A3            ; skok do czytania pierwsze	go bitu
POWRÓT LD HL, #FFFF ; obliczanie ilości wczytanych bajtów
SBC HL,DE
LD B,H              ; załadowanie ilości wczytanych bajtów
LD C,L              ; rejestrów BC
EI                  ; włączenie przerwań maskowalnych
RET	
Przykładowy loader w ZX-Basic dla tej procedury przedstawia się następująco:
10 CLEAR 29999: LET adres =30000
20 FOR n=0 TO 28: READ a: POKE 65500+n, a: NEXT  n: STOP
100 DATA 221, 33, adres-256~INT (adres/256), INT  (adres/256)
110 DATA 17, 255, 255, 14, 6, 175, 55, 8, 243, 33, 240,  255, 229, 195, 163, 5
120 DATA 33, 255, 255, 237, 82, 68, 77, 251, 201
Po zainstalowaniu procedury ustawiamy magnetofon w miejscu, gdzie jesteśmy pewni, że znajduje się już nasz odzyskiwany kawałek programu. Następnie włączamy magnetofon i wysyłamy w trybie bezpośrednim PRINT USR 65500. Istotna jest tutaj kolejność - najpierw włączamy magnetofon a później uruchamiamy procedurę. Wynika to z faktu, że procedura natychmiast przechodzi do czytania kolejnych bitów, co w przypadku niewłączonego jeszcze magnetofonu spowoduje powrót do ZX-BASIC. Istnieje także możliwość złego trafienia w przedziały czasowe nagrane na taśmie, co także zakończy się natychmiastowym powrotem do interpretera. Musimy wtedy przewinąć taśmę i ponownie uruchomić procedurę. Po pozytywnym zakończeniu wgrywania na ekranie zostanie wprowadzona ilość wczytanych do komputera bajtów. Powróćmy teraz do problemu kolejności bitów w poszczególnych bajtach. Sytuacja jest najprostsza w przypadku programu napisanego w ZX-BASIC i nagranego bez wartości zmiennych. Wtedy znamy ostatni bajt (przed bajtem kontrolnym) jaki został nagrany na taśmę - jest nim liczba 13 (ENTER), która kończy każdy wiersz programu. Posłużmy się przykładem. Niech dwa ostatnie bajty wczytane z taśmy wynoszą 48 i 107. Rozkład bitów w tych bajtach oraz w liczbie 13 jest następujący (zaczernienie oznacza jedynkę)
ilustracja
Linią przerywaną zaznaczono lokalizację bajtu o wartości 13 w dwóch ostatnich wczytanych bajtach. Wynika z tego, że ostatni bajt powinien być przesunięty o trzy bity w prawo oraz trzy bity najbardziej znaczące winny być wzięte z poprzedniego bajtu. Funkcję przesunięcia o trzy bity możemy zrealizować dzieląc dany bajt przez 8. Aby przesunąć wszystkie bajty odzyskiwanego programu wystarczy napisać krótki program:
1000 LET końcówka=0: FOR n=adres TO adreskonca
1010 LET bity przesuwane=INT (PEEK n/8): LET  nowakoncowka=PEEK n-8*bity przesuwane
1020 POKE n, 32*końcówka+bity przesuwane: LET  końcówka=nowakońcówka: NEXT n
Musimy jeszcze ustalić prawidłowy początek naszego bloku. W tym celu przeglądamy początek wczytanego modułu zwracając uwagę, gdzie znajduje się liczba 13. Po niej powinna następować dwubajtowa liczba opisująca numer wiersza programu. Liczba 13 może jeszcze występować wewnątrz 5-cio bajtowej reprezentacji liczby w ZX-BASIC, po liczbie 14. Gdy zlokalizowaliśmy prawidłowy początek wiersza nagrywamy tak odzyskany moduł na taśmie jako moduł binarny instrukcją
SAVE "nazwa" CODE adrespoczątku, adreskońca-adrespoczątku+l
Pozostaje nam jeszcze tylko wgrać go ponownie pod programem COPY-COPY. Zmieniamy informacje zawarte w nagłówku:
1. wpisujemy do pierwszego bajtu 0,
2. wpisujemy do hajtu 14-tego wartość 32768,
3. wpisujemy do bajtu 16-tego długość modułu (wielkość podawana jako "dług" w trakcie wyświetlania nagłówków).
Po ponownym nagraniu na taśmie dysponujemy już odzyskanym fragmentem naszego "straconego" programu. Niestety, w przypadku pozostałych modułów (tablice, binaria i programy w ZX-BASIC nagrana wraz ze zmiennymi) nie mamy żadnej informacji o ostatnim bajcie modułu. Pozostaje więc 7 możliwości przesuwania bitów w kolejnych bajtach, która z nich jest prawidłowa, możemy tylko próbować ocenić przyglądając zawartość pamięci po kolejnych przesunięciach kierując się własnym doświadczeniem i wiadomościami o tym, co powinien zawierać dany moduł. Oczywiście jest to wtedy bardzo pracochłonne i należy się zastanowić czy naprawdę warto odzyskiwać dany moduł o i tak zniszczonym bezpowrotnie początku.

Wojciech Indyk


Powrót do strony głównej...