speccy.pl
Facebook Like


SPECCY.PL

[SPECCY.PL PARTY 2023.1]

[WIKI SPECCY.PL]
Polecamy

KOMITET SPOŁECZNY KRONIKA POLSKIEJ DEMOSCENY
PIXEL HEAVEN 2023
AYGOR
Forum ZX Spectrum
Zawartość panelu chwilowo niedostępna
Archiwum plików ZX Spectrum
Nawigacja
Z taśmy na dysk.
PIERWSZE KROKI: Obrazy taśm TAP, TZX, loadery, manipulacje nad nimi itd...

1. Obraz taśmy

Pliki TAP oraz TZX to wirtualne obrazy programów zapisywanych na taśmie. Zawierają w sobie wszelkie informacje niezbędne do wczytania, tak zapisanego programu, przez emulator lub też ponownego jego zapisania na prawdziwą kasetę audio.

TZX to bardziej skomplikowany brat TAPa. Zawiera w sobie dokładnie wszystkie informacje dotyczące struktury zapisu – niestandardowe odstępy pomiędzy blokami, pojedyncze piski, trzaski i bleepy (które występowały w przypadku taśm zabezpieczonych przed kopiowaniem).

TAP to wersja uproszczona. Z reguły kiedy mamy do czynienia z plikiem TAP – jest to obraz odbezpieczonej taśmy i „poukładanego” systemu plików zgodnego z procedurami obsługi magnetofonu zawartymi w ROM.

Reasumując – TZX nadaje się idealnie do prezerwacji taśm czyli zachowania ich idealnej kopii w formie cyfrowej. Natomiast TAP to format łatwiejszy do manipulacji – na przykład konwersji do formatów dyskowych, a także zrozumiały dla DivIDE czyli współczesnego szybkiego „wczytywacza” programów do prawdziwego ZX Spectrum.

2. Narzędzia do obróbki

Do „rozbierania” czyli edycji obrazów taśm będziemy używali, windowsowego programu ZX-Blockeditor, o którym już kilkakrotnie wspominałem na forum.
Program został stworzony przez Clausa Jahna i dostępny jest na stronie http://www.zx-modules.de/. Wchodzimy na stronę i pobieramy następujące programy z pakietu:

  • ZX-Blockeditor
  • ZX-Editor – program potrzebny do przeglądania oraz edycji bloków BASIC
  • ZX-Preview – będzie nam potrzebny do podglądania (disasemblacji) bloków kodu maszynowego.
  • ZX-Paintbrush – gdybyśmy zechcieli pobawić się grafiką

3. Coś łatwego czyli rozbieramy pierwszego „prostego” TAPa

Na pierwszy ogień bierzemy program Marsport wydany w roku 1985 przez firmę Gargoyle Games. Pobieramy plik TAP spod załączonego linku WOS: http://www.worldofspectrum.org/infoseekid.cgi?id=0003040

bezpośredni link:

http://www.worldofspectrum.org/pub/sinclair/games/m/Marsport.tap.zip

i otwieramy przy pomocy ZX-Blockeditor.

'Rys1. Plik Marsport.TAP otwarty w ZX-Blockeditor Rys1. Plik Marsport.TAP otwarty w ZX-Blockeditor

Przyjrzyjmy się strukturze edytowanego pliku.

Pozycje 0001 (FILE TYPE) oraz 0002 (FILE INFO) nie mają dla nas żadnego znaczenia. To informacje dodane do obrazu przez program, który posłużył do jego utworzenia. Nas interesują pozycje zaznaczone przeze mnie żółtym kolorem.

Pozycja 0003 to nagłówek (ang: header) bloku programu w BASIC'u o długości 17 bajtów. Zaraz po nim pozycja 0004 – to już blok BASICa (w tym przypadku o długości 90 bajtów)

Fizycznie jeśli odsłuchujemy wczytującego się programu to słyszymy ciągły sygnał trwający kilka sekund i na obrzeżu ekranu (ang: border) pojawiają się czerwono, turkusowe paski. Ten ciągły sygnał to tak zwany pilot synchronizujący komputer z sygnałem taśmy.

Po około 2 sekundach ciągłego pisku słyszymy głośniejsze „piknięcie” lub raczej jakby urwane zaskrzeczenie i na ekranie pojawia się napis: „Program: MARSPORT”.
Właśnie w tym momencie wczytał się 17 bajtowy nagłówek informujący o nazwie następującego po nim bloku, jego typie (BASIC lub CODE czyli kod maszynowy), a także długości bloku, numeru linii od której program ma się uruchomić (w przypadku bloku BASIC).

W naszym przypadku jest informacja LINE 0 czyli program uruchamia się od linii oznaczonej numerem 0.

Tak naprawdę jest to rodzaj zabezpieczenia BASIC'owego bloku programu przed wylistowaniem i / lub edycją ale nie będę teraz o tym zbyt wiele pisał, ponieważ ZX-Blockeditor radzi sobie bez problemu z tego typu zabezpieczeniem.

Jeżeli po nagłówku ma się wczytać blok programu w kodzie maszynowym to wtedy nagłówek także zawiera informację o adresie w pamięci, od którego ma rozpocząć się wczytywanie kodu

Tak więc kontynuując nasze organoleptyczne pojmowanie odczytu z taśmy – po krótkim „skrzeku” i pojawieniu się napisu „Program: MARSPORT” następuje kolejny (tym razem bardzo krótki) sygnał ciągły (pilot) - i po nim słyszymy dłuższe „skrzeczenie”, które trwa kolejnych kilka sekund, na obrzeżu ekranu przesuwają się żółto granatowe paski, zaś po zakończeniu odczytu - na ekranie, widzimy zmianę – w przypadku naszej gry - zmianę koloru ekranu.

Do pamięci naszego komputerka został wczytany 90 bajtowy (w przypadku gry MARSPORT) blok programu w BASIC, uruchomił się i „przejął kontrolę” nad dalszym wczytywaniem się gry. Ten ładujący program w języku BASIC nazywamy loaderem

Zobaczmy co ten nasz loader ma w środku:

Klikamy prawym przyciskiem myszki na pozycję 0004 opisaną jako Program Data i następuje rozwinięcie dodatkowego menu wyboru. Klikamy na Edit datablock with ZX-Editor...

Rys2. Edytujemy BASIC Rys2. Edytujemy BASIC'owy loader Marsport.TAP w programie ZX-Editor Otwiera się okno ZX Editor'a - dodatkowego programu z pakietu ZX Modules, który nam posłuży do podejrzenia oraz edycji BASIC'owego loadera Rys3. Okno ZX Editor'a Rys3. Okno ZX Editor'a

Co zatem widzimy? Oczywiście to jest standardowy, składający się z jednej linijki, program napisany w języku BASIC.

Zauważmy, że początkowa linia ma numer 10 podczas kiedy nagłówek informował nas o starcie programu od linii oznaczonej numerem 0. Zwracam na to uwagę jedynie jako na ciekawostkę i dowód na to, że nie zawsze informacje podane w nagłówku pliku są zgodne z rzeczywistością.

Dokonajmy analizy naszego „jednolinijkowca”

Pierwsze trzy komendy to sterowanie kolorami ekranu. W tym przypadku ustawiają kolor tła liter (PAPER) na czarny, kolor liter (INK) na czarny oraz kolor obrzeża ekranu (BORDER) na czarny.

Jeżeli chcecie się dowiedzieć coś więcej na temat kolorów ZX Spectrum – odwiedźcie stronę :
http://eduinf.waw.pl/inf/retro/006_zx_spect_inst/0016.php

Obrzeże ekranu (border) jest też nazywane ramką ekranu. W przypadku ustawiania koloru czarnego, dla zaoszczędzenia pamięci, programiści często zamiast cyfry 0 używają wyrażenia logicznego NOT PI

Faktem jest, że wyrażenie NOT PI oznacza 0 (a raczej jest równe 0) ponieważ w logice NOT X (w przypadku kiedy X jest różne od zera) jest właśnie równe 0.

Bardzo często po trzech komendach PAPER x: INK x: BORDER x w loaderach występuje komenda CLS czyli wyczyszczenie ekranu (na przykład w celu usunięccia napisu PROGRAM: nazwa) W naszym przypadku nie ma tej komendy – bo tak naprawdę nie musi być (o tym za chwile), poza tym, jeśli wszystko (PAPER, INK, BORDER) ustawimy na jeden kolor, to wtedy nie będzie widać napisu.

Wracając do interpretacji naszego loadera widzimy komendę CLEAR 24099

Ta komenda to ustawienie tak zwanego RAMTOP. - czyli najwyższego adresu pamięci, używanego przez program w języku BASIC. Oprócz tego CLEAR czyści ekran, czyli działa jak CLS

Kolejna komenda to LOAD "S"SCREEN$ wczytująca nagłówek, a następnie blok danych obrazka tytułowego (o nazwie „S”)

Tutaj muszę opowiedzieć troszkę więcej.

Komenda LOAD ""SCREEN$ wczytuje do pamięci ekranu obrazek tytułowy, zwany także po angielsku loading screen.

W ZX Spectrum pamięć ekranu zaczyna się od adresu 16384 ($4000) i to właśnie pod ten adres jest wczytywany obrazek, który przecież, tak naprawdę, jest zwykłym blokiem danych o długości 6912 bajtów.

Stąd też wynika, że LOAD "" SCREEN$ możemy zastąpić LOAD "" CODE 16384,6912. Parametry występujące po instrukcji CODE są rozdzielone przecinkiem.
Pierwszy parametr to adres od którego ma nastąpić wczytanie bloku kodu maszynowego. Drugi parametr to długość (w bajtach) tego bloku.

Wracając do procedury ładowania obrazka do pamięci obrazu. W realu wygląda to tak, że od góry ekranu zaczyna się pojawiać obraz. Obraz jednak nie pojawia się linia po linii (tak jakbyśmy mogli się tego spodziewać) lecz z pewnymi odstępami pomiędzy liniami. Wynika to z nieliniowej organizacji pamięci ekranu ZX Spectrum, ale o tym, w tym momencie, nie będę się rozpisywał.

Wczytywany obraz jest z reguły monochromatyczny, a dopiero przy samym końcu ładowania obrazka, zostaje pokolorowany.

Wygląda to dość efektownie, nie jest to jednak żaden trick programistyczny lecz wynika z organizacji pamięci (obrazu oraz atrybutów) do których nasz obrazek jest ładowany jako ciąg danych.

Rys 4. Pamięć obrazu i inne...
Rys4. Pamięć obrazu i inne...

Jak już wspomniałem obrazek o długości 6912 bajtów jest wczytywany do pamięci ZX Spectrum począwszy od adresu 16384 ($4000) Z rysunku 4 wynika, że pamięć obrazu kończy się na adresie 22528 ($5800) czyli obszar pamięci obrazu ma długość 6144 bajtów. Tak jest rzeczywiście, że pierwsze 6144 bajtów w pliku obrazka to powiedzmy „kontury” natomiast pozostałe 768 bajtów ładują się począwszy od adresu 22528 ($5800) czyli do obszaru atrybutów. Te 768 bajtów danych to nie tylko informacja o kolorach, ale także, może to być informacja o mruganiu części obrazka oraz jaskrawości (FLASH oraz BRIGHT będące częściami atrybutów).

Generalnie, zapamiętajmy sobie tą magiczną liczbę 6912 jako wielkość obrazka w bajtach. Dzięki temu będziemy taki blok dosyć łatwo rozpoznawali, podczas rozgryzania tajemnic TAP/TZX..

Oczywiście, jak to zwykle bywa, występują odstępstwa od reguły i podczas naszych dalszych działań z różnymi obrazami taśm, przekonamy się, że kreatywność programistów była pod tym względem bardzo wysoka.

Blok obrazka może być mniejszy niż 6912 bajtów - w takim wypadku możemy podejrzewać że mamy do czynienia ze skompresowanym obrazkiem, który nie ładuje się bezpośrednio do pamięci obrazu czyli od adresu 16384 ($4000) lecz gdzieś indziej, a następnie zostaje rozpakowany pod adres 16384 ($4000).

Może się zdarzyć, że plik obrazka ma długość większą niż 6912 bajtów. Bardzo często w takim pliku jest dodany (czy raczej wmiksowany) krótki programik w kodzie maszynowym, który na przykład doładowuje kolejny blok danych z taśmy. Będę omawiał takie przypadki w dalszej części tego artykułu.

Plik obrazka nie musi się ładować od razu do pamięci obrazu (czyli wyświetlać stopniowo w czasie ładowania) lecz często się zdarza, że ładuje się pod inny adres, a następnie przy pomocy procedury w kodzie maszynowym zostaje, w okamgnieniu, przekopiowany pod adres 16384 ($4000). W takim wypadku widzimy, na ekranie efekt „wyskakującego” obrazka.

Wróćmy do naszego obrazu taśmy, a przede wszystkim do analizy loadera gry MARSPORT.

Po instrukcji wczytania obrazka zostaje wykonana kolejna instrukcja PRINT AT 13,0;

W tym przypadku można to nazwać trickiem programistów ponieważ ta instrukcja wymusza pozycję, w której,
na ekranie ma się pojawić napis: „Вytes: nazwa_bloku”.

Rys 5. Obrazek tytułowy gry Marsport
Rys 5. Obrazek tytułowy gry Marsport

Ustawienie tej pozycji na wiersz 13-ty (licząc od góry) powoduje, że napis pojawia się troszkę poniżej środka, w czarnym miejscu obrazka i dzięki temu nie jest widoczny. Innym rozwiązaniem może być także instrukcja POKE 23739,111 wstawiona w naszym loaderze pomiędzy instrukcjami LOAD "S"SCREEN$ oraz LOAD "P"CODE.

POKE 23739,111 jest czasami używana w formie POKE 23739, CODE "o" lub jeszcze bardziej ciekawie: POKE VAL "23739", CODE "o" Dlaczego? Oczywiście dla ratowania wiecznie brakującej pamięci. Aby samemu się przekonać czym jest CODE "o" wpisz w swoim ZX Spectrum następujący rozkaz: PRINT CODE "o" i zobaczysz, że na ekranie pojawi się liczba 111.

Warto wspomnieć, że instrukcja POKE 23739,111 zadziała jedynie wtedy, jeżeli nie będziemy mieli podpiętego interfejsu IF1 czyli microdrive, ponieważ po podłączeniu IF1 do naszej maszynki, adres pamięci 23739 staje się adresem, z którego korzystają microdrive'y (ale tak naprawdę, kto to teraz posiada i podpina?)

Można też (aby było uniwersalnie i nie gryzło się z interfejsami) zapisać to tak:

POKE PEEK 23631+256*PEEK 23632+5,111 

Także tą samą funkcję pełni POKE 23570,16 dla której odwołania stosujemy POKE 23570,6 – można to stosować jedynie w programach tylko dla wersji 48k.

Kolejna instrukcja LOAD "P"CODE wczytuje nagłówek oraz blok programu (o nazwie „P”) w kodzie maszynowym.

Ostatnia instrukcja to RANDOMIZE USR 26980. Ta instrukcja nakazuje komputerowi skoczyć do komórki pamięci o adresie 26980 i uruchomić program w kodzie maszynowym, czyli naszą grę.

4. Konwertujemy nasz TAP do obrazu dyskietki +3DOS lub DISCiPLE / +D

Poznaliśmy, krok po kroku, zasadę działania loadera gry Marsport. Dokonamy teraz konwersji obrazu tej gry do formatów dyskowych: DISCiPLE / +D oraz +3DOS (dla ZX Spectrum 128+3).

Najpierw biorę się za loader w BASIC.

Spróbuję skopiować jego listing do windows'owego notatnika. Tutaj okazuje się, że zwykłe zaznaczenie wylistowanego programu w oknie ZX-Editor'a, oraz próba użycia kopiuj/wklej przynosi niezbyt oczekiwany rezultat:

 
0Ú0:Ů0:ç0:ý24099:ď"S"Ş:ő¬13,0;:
_ď"P"Ż:ůŔ26980

Aby skopiować ten „jednolinijkowiec” do notatnika, należy zamknąć ZX-Editor i w oknie ZX-Blockeditor'a kliknąć prawym przyciskiem myszki na blok „0004 Program data”, następnie w menu wyboru wybrać Send to ZX-Preview.


Rys6. „Wysyłamy” nasz BASIC'owy loader do programu ZX-Preview.

Otworzy nam się okno programu ZX-Preview

Wybieramy zakładkę Text view i widzimy możliwy do skopiowania tekst naszego loadera:


Rys7. Loader podglądany w ZX-Preview. Teraz można go skopiować i wkleić do notatnika.

To powyższe kopiowanie i wklejanie do notatnika oczywiście nie jest konieczne aby edytować nasz listing. Zmian dokonujemy bezpośrednio w oknie ZX-Editora i zapisujemy je klikając w lewym, dolnym rogu przycisk OK. Wspomniałem o kopiowaniu do notatnika, ze względu na to, że w późniejszych, dużo bardziej skomplikowanych przypadkach, będzie nam potrzebne posiadanie takiego listingu loadera gdzieś pod ręką.

Zatem wracamy do edycji (konwersji) naszego obrazu TAP na wspomniane wyżej systemy dyskowe.

Oryginalny listing wygląda tak:

10  PAPER 0:  INK 0:  BORDER 0:  CLEAR 24099: LOAD "S"SCREEN$ : PRINT AT 13,0;: LOAD "P"CODE : RANDOMIZE USR 26980

Po przeróbce na loader dla systemów dyskowych DISCiPLE / +D - listing będzie wyglądał tak:

10 PAPER 0: INK 0: BORDER 0: CLEAR 24099: LOAD d*"S"SCREEN$ : PRINT AT 13,0;:LOAD d*"P"CODE : RANDOMIZE USR 26980

Zauważyliście różnicę? W instrukcjach LOAD przed znakiem cudzysłowu wstawiamy literkę „d” wraz ze znaczkiem gwiazdki „*”

Jeszcze jedna sugestia oraz ważna informacja. W przypadku naszej gry, programiści nadali nazwy ładowanym blokom danych. W przypadku obrazka jest to „S” (zapewne od słowa screen) zaś w przypadku bloku w kodzie maszynowym jest to „P”.

Jednak w przeważającej większości przypadków nagłówki zapisane na taśmie nie będą miały swoich nazw, zaś w listingach loaderów będą występować instrukcje ładowania, bez podanych nazw bloków czyli:

LOAD ""SCREEN$  oraz  LOAD ""CODE

Zatem aby uniknąć pomyłek oraz nauczyć się porządku, od razu zacznijmy nadawać blokom odpowiednie nazwy w ich nagłówkach.

W przypadku systemu DISCiPLE / +D nazwa bloku ma się składać maksymalnie z 10 znaków. W przypadku +3DOS nazwa bloku to 8 znaków, kropka i 3 znaki dla rozszerzenia.

Moja rada: działajmy uniwersalnie, czyli tak aby było łatwo konwertować nasze obrazy na inne systemy dyskowe lub po prostu wrócić do formatu taśmowego.

W przypadku LOAD d*"S"SCREEN$ zmieniłbym nazwę bloku z „S” na „marspo$” czyli komenda w loaderze wyglądałaby tak: LOAD d*"marspo$"SCREEN$ zaś blok kodu nazwałbym „marspoC” a więc LOAD d*"marspoC"CODE. Nagłówki bloków BASIC zawsze nazywam używając tylko dużych liter.

Finalnie nasz loader w BASIC'u wyglądać będzie tak:

10 PAPER 0: INK 0: BORDER 0: CLEAR 24099: LOAD d*"marspo$"SCREEN$ : PRINT AT 13,0;:LOAD d*"marspoC"CODE : RANDOMIZE USR 26980

Pamiętajmy, że nazwy bloków w obrazie dyskietki nie mogą się powtarzać. W przypadku systemu +3DOS nie dodajemy „d*” przed znakiem cudzysłowu. Zatem program loadera dla ZX Spectrum 128+3 będzie wyglądał tak:

10  PAPER 0:  INK 0:  BORDER 0:  CLEAR 24099:  LOAD "marspo$"SCREEN$ :  PRINT AT 13,0;:LOAD "marspoC"CODE :  RANDOMIZE USR 26980

Po dokonaniu zmian w loaderze, naciskamy przycisk „OK” w lewym, dolnym rogu ZX-Editor'a i po chwili wrócimy do okna ZX-Blockeditor'a.
Musimy teraz pozmieniać nazwy naszych bloków – tak aby się zgadzały z nazwami bloków w loaderze.
W ZX-Blockeditor klikamy prawym przyciskiem myszki na nazwę bloku (nagłówek) obrazka (w naszym przypadku pozycja 0005) następnie w menu wyboru klikamy na „Modify datablock...”

Rys8. Zmieniamy nazwy nagłówków przy pomocy narzędzia „Modify datablock...
Rys8. Zmieniamy nazwy nagłówków przy pomocy narzędzia „Modify datablock...”

W kolejnym okienku, które się otworzy, zmieniamy nazwę bloku w pozycji „header name”.
Rys9. Tak wygląda zmienianie nazwy w narzędziu „Modify datablock...”
Rys9. Tak wygląda zmienianie nazwy w narzędziu „Modify datablock...”
Zatwierdzamy OK i wracamy do okna ZX-Blockeditor'a, w którym, w analogiczny sposób zmieniamy nazwę bloku kodu maszynowego (czyli nazwę nagłówka) z pozycji 0007.
Po dokonaniu zmian nazw nagłówków, będziemy mieli taki widok w ZX-Blockeditor.

Rys10. Obraz Marsport.TAP po dokonaniu zmian nazw nagłówków bloków.
Rys10. Obraz Marsport.TAP po dokonaniu zmian nazw nagłówków bloków.

Teraz przystępujemy do właściwej konwersji na obraz dyskowy.
Usuwamy pozycje 0001 oraz 0002 czyli FILE TYPE i FILE INFO (CTRL oraz lewy przycisk myszki aby zaznaczyć pozycje do skasowania, następnie CTRL + Y aby skasować).


Następnie używamy ponownie narzędzia „Modify datablock...”, którego wcześniej użyliśmy do zmiany nazw bloków.
Zaczynamy od nagłówka naszego loadera w BASIC występującego pod nazwą MARSPORT
Po otwarciu „Modify datablock...” widzimy, począwszy od lewego, górnego rogu, zakładki TZX, TAP, DSK, TRD, SCL, MGT.

Obecnie jesteśmy na zakładce TAP (ponieważ pracujemy na pliku TAP) i bardzo istotne jest abyśmy zwrócili baczną uwagę na pole wyboru znajdujące się poniżej wspomnianych już zakładek.
Tam jest ustawione select block: program autostart header
Oznacza to, że jest to nagłówek bloku BASIC auto-startującego Jest to oczywiste, ponieważ po załadowaniu bloku BASICa, musi się on automatycznie uruchomić.
Jeżeli chcemy przerobić ten nagłówek na zgodny z systemem +3DOS, należy kliknąć na zakładkę DSK. Natomiast jeżeli będziemy dokonywali przeróbki na DISCiPLE / +D, klikamy na zakładkę MGT.
Właśnie w tym momencie w programie ZX-Blockeditor występuje wg mnie błąd ponieważ po kliknięciu na zakładkę DSK lub MGT pole wyboru select block: program autostart header zmienia się i ustawia się na select block: program header.

Musimy, przy pomocy strzałki w dół, zmienić pole wyboru z powrotem na select block: program autostart header i dopiero wtedy zatwierdzić zmiany dokonane w nagłówku, klawiszem OK
Sprawa jest niezwykle ważna, ponieważ, jeżeli sobie zapomnimy o dokonaniu tej zmiany, wtedy przy ładowaniu gry, program loadera w BASIC nie uruchomi się automatycznie i nie zostaną wczytane pozostałe bloki danych.

Zmieniliśmy zatem nagłówek bloku BASIC i jeżeli się dokładniej przyjrzycie, wtedy zobaczycie, że malutki obrazek przy liczbie 0001 zmienił kolor z czerwonego na różowy.
Pozmieniajmy zatem pozostałe nagłówki bloków na dyskowe – tak aby też zapaliły się na różowo. Robimy to analogicznie jak postępowaliśmy z nagłówkiem loadera czyli pierwszego bloku w języku BASIC.
Podczas zmiany nagłówka obrazka zadbajmy o to aby nie uległo zmianie ustawienie w polu wyboru: select block screen header (będzie się usiłowało zmienić na select block: byte header)
Po dokonaniu wszelkich zmian, obraz naszej taśmy TAP nie będzie już obrazem taśmy, lecz wstępnym obrazem dysku DSK w formacie +3DOS (zmienialiśmy zakładki na DSK).

Gdybyśmy pozmieniali zakładki na MGT, wtedy otrzymalibyśmy wstępny obraz dysku w formacie zgodnym z DISCiPLE / +D.
Jedyne na co chciałbym zwrócić Waszą uwagę to, że przy konwersji na +3DOS/DSK nastąpiła zmiana wielkości liter – obecnie mamy wszystko dużą literą.
W przypadku plików systemu +3DOS nie ma to większego znaczenia ponieważ system nie zwraca uwagi na wielkość liter.
Przy konwersji nagłówków na format DISCiPLE / +D wielkość liter nie zostaje zmieniona. W tym systemie plików, należy bacznie uważać aby się nie pomylić, wpisując np. nazwę bloku małą literą w loaderze, zaś w nagłówku używając wielkiej litery – wtedy przy ładowaniu gry pojawi się błąd.

Tak wygląda nasza gra jako wstępny obraz dysku DISCiPLE / +D :

Baczny obserwator zauważy, że w przypadku obrazów taśm TAP/TZX małe ikonki nagłówków bloków mają kolor czerwony, zaś wielkość każdego nagłówka wynosi 17 bajtów.
W przypadku obrazu dysku DSK w formacie +3DOS, ikonki mamy różowe, zaś rozmiar nagłówka wynosi 140 bajtów.
Dla odmiany w przypadku DISCiPLE / +D ikonki mają kolor granatowy, a nagłówki rozmiary 59 bajtów.
Kilkakrotnie użyłem sformułowania „wstępny obraz dysku” ponieważ, aby nasz obraz stał się właściwym obrazem dysku, musimy do niego dodać informacje dotyczące formatu.
Stańmy kursorem myszki w ZX-Blockeditor gdziekolwiek poniżej przetworzonych nagłówków i bloków danych. Kliknijmy prawym przyciskiem myszki. Pojawi się menu wyboru i na samej górze wybierzmy narzędzie „Compose datablock...”

Konwertujemy na obraz dysku DSK/+3DOS. Zatem klikamy na zakładkę DSK (po prawej stronie, zaraz obok TRD).

W polu wyboru select block ustawiamy DSK format +3/180k.

W tabelce Parameter, w polu wyboru image file format: Select image file format ustawiamy format obrazu Extended DSK
Pozostaje nam teraz kliknąć na przycisk Add first w lewym dolnym rogu okna i do początku obrazu zostaną dodane wszystkie niezbędne informacje dotyczące jego formatu.
W ten sposób otrzymujemy finalny, kompletny obraz dysku DSK/+3DOS.

Podobnie postępujemy w przypadku konwertowania obrazu taśmy na dyski DISCiPLE / +D lecz w tym przypadku w Datablock composer musimy wybrać zakładkę MGT i w polu wyboru select block ustawiamy MGT format (DS, 80 tracks).

Przekonwertowane obrazy dysków zapisujemy na twardym dysku klikając na FILE → SAVE AS i dokonujemy wyboru:
+3 Disk image files (*.dsk) dla obrazów +3DOS
lub
M.G.T./Disciple/PlusD files (*.mgt) dla obrazów DISCiPLE / +D
Możemy sobie pogratulować! Właśnie dokonaliśmy konwersji z formatu kasetowego na dyskowy.

5. Zaczynają się schody. Kolejna gra i trochę asemblera

Zauważcie jak proste było przekonwertowanie gry, w której obrazie, układ plików był poukładany standardowo.
001 Nagłówek Programu BASIC (loadera)
002 Blok programu BASIC (loader)
003 Nagłówek obrazka SCREEN$
004 Blok danych obrazka SCREEN$
005 Nagłówek bloku danych gry
006 Blok danych gry
Aby przerobić grę na system dyskowy, wystarczy dokonać kilka zmian w loaderze BASIC, następnie - pozmieniać nagłówki na zgodne z systemami dyskowymi i szafa gra!
Nie zawsze jednak będzie tak pięknie.

Na naszym stole operacyjnym ląduje gra Molecule Man wydana w roku 1986 przez firmę Mastertronic Ltd. http://www.worldofspectrum.org/infoseekid.cgi?id=0003242 http://www.worldofspectrum.org/pub/sinclair/games/m/MoleculeMan.tap.zip

Pobierzmy plik MoleculeMan.tap.zip i rozpakujmy gdzieś na naszym dysku twardym.
Następnie otwieramy plik TAP przy pomocy ZX-Blockeditor i widzimy istną sieczkę...

Nie przerażajmy się jednak zbytnio. Bloki od pozycji 0012 w dół to dodatek do gry o nazwie MAZE DESIGNER, który umożliwia stworzenie własnych plansz. Nas interesuje przekonwertowanie samej gry zatem cały ten dodatek możemy usunąć.
Podobnie wygląda sytuacja z dodatkowym, początkowym blokiem w BASIC..
Podglądamy pierwszy blok BASIC'a w ZX-Editor:

To co widzimy to żadna magia.
Linia 10 to „ukryty asembler” czyli kod maszynowy po instrukcji REM
Linia 20 to wywołanie procedury maszynowej z linii 10
Reszta to wyczyszczenie ekranu, wyświetlenie napisu i przystąpienie do ładowania kolejnego bloku (komenda LOAD "" w linii numer 40).
Ten pierwszy blok w języku BASIC to nic innego tylko procedura przełączająca ZX Spectrum 128K w tryb 48K.

Ta gra działa bez błędów jedynie w trybie 48K.

Powstała ona w roku 1986, kiedy już były obecne na rynku wersje ZX Spectrum 128K. Dodanie tego „dodatku” przełączającego w tryb 48K nie czyniło krzywdy użytkownikom ZX Spectrum 48K, dla których program był obojętny (nie zawieszał komputera) natomiast użytkownicy ZX Spectrum 128K w przypadku kiedy zapomnieli przełączyć swoją maszynę w tryb 48K nie doznali szoku w postaci zwiechy komputera bo ten programik ich automatycznie przełączał.

Nas ten program nie interesuje, więc go kasujemy.
Przy pomocy klawisza CTRL oraz myszki zaznaczamy bloki 0003, 0004 oraz 0012 w dół.
Po wykasowaniu niepotrzebnych bloków, obraz naszej taśmy wygląda tak:

Patrząc na to możemy sobie wyobrazić, że podczas ładowania gry z taśmy:
a) na początku zostaje wczytany loader BASIC (bloki 0003 i 0004)
b) następnie króciutki 14-bajtowy blok kodu maszynowego pod adres 23296 (pozycja 0005 i 0006)
c) zaraz po nim nastąpi ładowanie obrazka, ale pod dziwny adres pamięci 40000 (pozycja 0007 i 0008)
d) ostatnia pozycja z naszej listy (0009) to beznagłówkowy blok kodu maszynowego o długości 40500 bajtów, ładowany nie wiadomo gdzie.

Nazwałem ten blok beznagłówkowy (ang: headerless) ponieważ nie posiada nagłówka. Zatem bezpośrednia konwersja takiego obrazu do formatów dyskowych jest niemożliwa – ponieważ tam muszą być nagłówki.
Nie załamujmy się. Musimy postarać się przekonwertować wszystko do „normalnego” formatu czyli takiego gdzie każdy blok danych posiada swój nagłówek.
Najpierw zobaczmy jak to wszystko rzeczywiście się ładuje.
Podejrzyjmy zatem nasz BASIC'owy loader.

Linia 40 i komenda LOAD ""CODE to załadowanie tego krótkiego 14-bajtowego bloku danych pod adres wskazany w jego nagłówku czyli 23296. Po jego załadowaniu następuje ładowanie obrazka LOAD ""SCREEN$ pod adres 16384. Nie przejmujmy się fejkowym adresem 40000 podawanym w nagłówku. Dla komputera ważniejsza jest informacja zawarta w loaderze. Ta ściema z adresem w nagłówku miała wyprowadzić w pole domorosłych włamywaczy. Pamiętajmy, że w tamtych czasach nie dysponowali tak zaawansowanymi narzędziami jak my teraz i podstawowym, pierwszym krokiem przy analizie gry było podglądanie informacji zawartych w nagłówkach bloków.
Dalej, po załadowaniu obrazka, przechodzimy do linii 50, w której mamy:
RANDOMIZE USR 23296 czyli uruchomienie tego krótkiego 14-bajtowego kodu który został wczytany właśnie pod adres 23296.
Podejrzyjmy zatem co robi ten kod....
Klikamy prawym przyciskiem myszki na pozycji 0006 (blok kodu) i w menu wyboru klikamy na Send to ZX-Preview...

Otwiera się okno podprogramu ZX-Preview i tam wybieramy zakładkę Debug view.
Proponuję wziąć głęboki oddech bo teraz czeka nas pierwsza lekcja bardzo prostego asemblera.

To co widzimy to nic innego tylko podstawowa procedura załadowania bloku danych z magnetofonu do pamięci komputera.
Wygląda to tak:

LD IX, ADRES            ; gdzie ADRES to adres pod który ma być załadowany blok danych
LD DE, DLUGOSC     ; gdzie DLUGOSC to długość bloku danych do załadowania
LD A, 255            ; ma być załadowany sam blok bez nagłówka, gdyby był nagłówek to LD A,0
SCF                     ; ustawia flagę przeniesienia na 1 *
CALL 1366        ; wywołanie procedury LD-BYTES w ROM 
RET                    ; po załadowaniu bloku danych, wróć do BASIC'a

* Gdyby nie została ustawiona flaga przeniesienia (zwana też znacznikiem przeniesienia) na 1, wtedy procedura LD-BYTES zawarta w ROM ZX Spectrum pod adresem 1366 ($556) wykonałaby VERIFY zamiast LOAD.

Zatem nasz 14-bajtowy programik wykonuje zadanie analogiczne do instrukcji:

LOAD ""CODE 25000,40500

Czyli już wiemy, że ten ostatni beznagłówkowy blok kodu maszynowego o długości 40500 zostaje załadowany do pamięci począwszy od adresu 25000.
Następnie, po załadowaniu tego bloku, następuje powrót do BASIC loadera (komenda RET) i już w loaderze, wykonanie instrukcji RANDOMIZE USR 57060 czyli uruchomienie gry.
Chcemy doprowadzić do sytuacji, w której każdy blok ma swój nagłówek. Musimy zatem dokonać zmiany w obrazie taśmy.
Jestem człowiekiem z natury leniwym zatem nie lubię zbyt dużo klikać myszką. Staram się ograniczyć swoją pracę do minimum.
W obrazie MOLECMAN.TAP usuwam ten krótki 14-bajtowy blok kodu (pozycja 0006), ponieważ nie będzie nam już potrzebny.
Pozostały po nim nagłówek (pozycja 0005) przesuwam przy pomocy zielonej strzałki w dół, tak aby stał się nagłówkiem tego ostatniego (wcześniej beznagłówkowego) bloku danych o długości 40500 bajtów.
Pozostaje nam zmienić dane bloku w nagłówku (tam wciąż jest CODE 23296,14), zatem najeżdżamy na niego myszką i klikamy prawym przyciskiem. Otwieramy narzędzie Modify datablock...

w rubryce code name: zmieńmy od razu nazwę nagłówka. Tam jest teraz wykrzyknik „!”. Zmieńmy nazwę na „molecmC”.

W tabelce start address: wpisujemy adres, od którego, ten blok danych, ma się ładować. Pamiętamy, z podejrzanego wcześniej 14-bajtowego programiku w asemblerze, że ten adres to 25000. Zmieńmy zatem poprzednią wartość 23296 na 25000 i przechodzimy dalej czyli do tabelki code length:

Tutaj zamieniamy starą wartość (14 bajtów) na długość bloku dla którego przerabiamy nagłówek, czyli 40500 bajtów.

Klikamy OK i nasz beznagłówkowy blok danych właśnie otrzymał nowy nagłówek.

Pozostaje nam jeszcze tylko (dla utrzymania porządku) poprawić nagłówek obrazka, tak aby nas nie mylił (gdyż w chwili obecnej pokazuje, że obrazek jest ładowany pod adres 40000).

Po kliknięciu na Modify datablock... nie musimy zmieniać w nim wartości 40000 na 16384. Dużo lepszym pomysłem jest przestawienie pola wyboru select block: byte header na select block screen header oraz, przy okazji, zmiana nazwy nagłowka na „molecm$” Po dokonaniu zmian, zatwierdzamy je klikając na przycisk OK.

Mamy zatem „poukładany” jak należy system plików w naszym obrazie taśmy:

Teraz edytujemy loader w BASIC i dokonujemy niezbędnych zmian.
Przy pomocy ZX-Editor, otwieramy program loadera, który w tej chwili wygląda tak:

10 INK 4: PAPER 0: BORDER 0: CLEAR 24999
20 PRINT AT 11,1; INVERSE 1;"MOLECULE MAN IS LOADING ......"
30 INK 0
40 LOAD ""CODE : LOAD ""SCREEN$ 
50 RANDOMIZE USR 23296
60 RANDOMIZE USR 57060

Dokonamy następujących zmian:
Linia 40 - usuwamy instrukcję LOAD ""CODE, która ładowała, nie istniejący już 14-bajtowy blok kodu maszynowego. Instrukcję LOAD ""SCREEN$ modyfikujemy wstawiając nazwę obrazka pomiędzy cudzysłowy. Czyli będzie: LOAD "molecm$"SCREEN$
Linia 50 - usuwamy instrukcję RANDOMIZE USR 23296 która uruchamiała nieistniejący już, 14-bajtowy programik zaś w jej miejsce wstawiamy instrukcję ładowania ostatniego bloku kodu maszynowego czyli LOAD "molecmC"CODE
Zatem, po przeróbce loadera, powinno to tak wyglądać:

10 INK 4: PAPER 0: BORDER 0: CLEAR 24999
20 PRINT AT 11,1; INVERSE 1;"MOLECULE MAN IS LOADING ......"
30 INK 0
40 LOAD "molecm$"SCREEN$ 
50 LOAD "molecmC"CODE 
60 RANDOMIZE USR 57060

Zatwierdźmy zatem dokonanie zmian klikając w przycisk OK (lewy dolny róg).
Pozostaje nam teraz (zanim przerobimy obraz kasety na dyskowy) sprawdzić czy wszystko działa w emulatorze ZX Spectrum.
Zapiszmy zatem obraz taśmy na którym pracowaliśmy, ale najlepiej pod inną nazwą niż MOLECMAN.TAP. (aby nie nadpisywać oryginału).
Ja w takim wypadku dodaje do istniejącej nazwy pliku, literkę „b” (od słowa beta). Tak więc zapisujemy obraz jako MELECMANb.TAP.
Plik sprawdzamy, ładując do emulatora bez włączonych jakichkolwiek przyśpieszaczy, fastloaderów itd., czyli tak, jakbyśmy ładowali program do prawdziwego ZX Spectrum. Chodzi o to abyśmy zobaczyli jak zachowuje się nasz przerobiony program w trakcie wczytywania. Czy wczytuje się poprawnie obrazek, wyświetlają jakieś komunikaty itd., itp.
W przypadku MELECMANb.TAP wszystko wczytało się poprawnie i gra uruchamia się bez problemu. Próbowałem trochę pograć, aby sprawdzić, czy nie zawiesi się podczas grania i moje testy zakończyły się sukcesem.
Jedyny niespodziewany, niemiły akcent to pojawienie się czarnego, wydłużonego prostokąta na załadowanym obrazku w trakcie wczytywania bloku danych (chodzi o ten czarny pasek, który najechał na nos naszego bohatera).

Ten pasek to pozostałość napisu Bytes: MOLECMC czyli informacji wyświetlanej przez system podczas wczytywania kolejnego bloku danych z taśmy.
Aby się nie pojawiał i nie psuł nam obrazka wystarczy pomiędzy instrukcjami LOAD "molecm$"SCREEN$ oraz LOAD "molecmC"CODE wstawić już wspominaną wcześniej komendę POKE 23739,111 która wyłącza pojawianie się napisu Bytes: NAZWA_BLOKU
Jeżeli planujemy później przekonwertować nasz plik MELECMANb.TAP na obraz dyskowy, wtedy nie ma konieczności użycia POKE 23739,111 ponieważ, w systemach dyskowych, podczas ładowania kolejnych bloków z dyskietki, nie pojawiają się na ekranie informacje o ich nazwach. Zatem załadowany obrazek nie zostanie nadpisany na ekranie przez niepotrzebny komunikat.

6. SPELLBOUND (Mastertronic)

Kolejną grą nad którą posiedzimy jest, chyba wszystkim, dobrze znana SPELLBOUND. Gra wydana w roku 1985 przez firmę Mastertronic Added Dimension. http://www.worldofspectrum.org/pub/sinclair/games/s/Spellbound48.tap.zip

Ściągamy plik TAP (w wersji 48k) i otwieramy pod ZX-Blockeditor.

Widzimy, że sytuacja jest podobna do poprzedniej tylko tym razem nie mamy tego krótkiego kilkunastobajtowego bloku kodu maszynowego. Jest natomiast dziwny blok danych o długości 6940 bajtów, ładowany pod adres 50000 (zgodnie z informacją odczytaną z jego nagłówka).
Przejdźmy zatem do podglądu loadera w BASIC, który edytujemy w ZX-Editor.

Teraz przyglądając się pierwszej i jedynej instrukcji LOAD ""CODE 16384, widzimy, że ten blok danych, o długości 6940 bajtów, ładuje się nie pod adres 50000 lecz do pamięci obrazu – jest zatem obrazkiem, ale jak już wiemy obrazek ma 6912 bajtów. Co więc jest zawarte w 28 bajtach które ładują się za pamięć obrazu i obszar atrybutów (czyli do bufora drukarki) ?

Edytujmy zatem nasz blok 6940 bajtów i zobaczmy co w nim siedzi (oprócz danych obrazu). Nachodzimy myszką na interesujący nas blok danych (pozycja 0006) i klikamy prawym przyciskiem myszki wybierając Send to ZX-Preview... Po otwarciu tego narzędzia przechodzimy od razu do zakładki Debug view

W oknie ZX-Preview / Debug preview zobaczymy obszar pamięci począwszy od adresu 50000, (adres ten został pobrany z nagłówka naszego bloku). Oczywiście dane w nagłówku bloku są typowym fejkiem ponieważ z loadera wiemy, że blok powinien załadować się pod adres 16384. Zatem w pole Org: wpisujemy właściwy adres 16384, natomiast w pole Start: wpisujemy 23296 ponieważ to jest adres startowy procedury zawartej w naszym bloku (instrukcja RANDOMIZE USR 23296 w kodzie loadera BASIC-owego).
Teraz widzimy już całkiem czytelną zawartość, dobrze nam już znaną z poprzedniego przypadku.

LD IX, 26064     ; począwszy od adresu 26064 załaduj blok programu
LD DE, 39470    ; ładowany blok programu ma długość 39470 bajtów
LD A,255            ; to blok programu, (a nie nagłówek)
SCF                        ; ustaw znacznik przeniesienia na 1
CALL 1366          ; wywołuje procedurę LD-BYTES zawartą w ROM pod adresem 1366 ($556)
RET                      ; po załadowaniu bloku powrót do loadera w BASIC

Pozostałe instrukcje (INC BC oraz LD L,B) nie mają tutaj znaczenia.
Musimy zatem stworzyć nowy nagłówek dla ostatniego beznagłówkowego bloku (tego o długości 39470 bajtów).
Ja w takim wypadku (z lenistwa) klikam na nagłówek bloku obrazka (pozycja 0005) oraz wykonuję operację CTRL+C (kopiuj) i stanąwszy gdzieś całkiem poniżej klikam CTRL+V (wklej).
Poniżej wszystkich nagłówków i bloków zostanie wklejony zduplikowany nagłówek obrazka, który następnie przesuwamy, przy pomocy zielonej strzałki w górę, do pozycji tuż nad beznagłówkowym blokiem 39740 bajtów. Czyli znajdzie się on w pozycji 0007.

Teraz (przy pomocy narzędzia Modify datablock... zmieniamy nazwę tego ostatniego, dodanego nagłówka (na SPELLC), a także adres ładowania bloku oraz jego długość. W nagłówku obrazka zmieniamy informacje o jego adresie ładowania (z 50000 na 16384).

Teraz pozostaje nam zmienić loader w BASIC.
Mamy:

10 CLEAR 26060: POKE 23693,71: BORDER 0: CLS : LOAD ""CODE 16384: RANDOMIZE USR 23296: RANDOMIZE USR 26624

Zmieniamy na:

10 CLEAR 26060: POKE 23693,71: BORDER 0: CLS : LOAD "SPELL$"CODE 16384 : 
LOAD "SPELLC"CODE : RANDOMIZE USR 26624

Czyli wyrzucamy instrukcję RANDOMIZE USR 23296 , która uruchamiała tą krótką procedurkę zawartą w bloku danych obrazka.
Teraz przerobiony w powyższy sposób obraz taśmy SPELLBOUN.TAP zapisuję jako SPELLBOUNb.TAP i testuje pod emulatorem.
Wszystko się ładuje jak należy, po czym gra się uruchamia i można pograć. Można by stwierdzić, że kolejny raz się udało, ale...

Podczas pisania tego artykułu, konsultowałem się z Tygrysem i zwrócił mi uwagę na jeden ważny fakt. Mianowicie ten obrazek, który ma niestandardową długość 6940 bajtów (z powodu doczepionego do swego „ogona”, programiku ładującego) podczas wczytywania do pamięci komputera, po załadowaniu danych obrazu (obszar 16384-22527) oraz atrybutów (obszar 22528-23295) zacznie się ładować (pozostałe 28 bajtów) do bufora drukarki (obszar 23296-23551) i nadpisze dane w nim zawarte.
W przypadku wersji 48K nie ma problemu (bo nie korzystamy z drukarki) lecz ZX Spectrum 128K ma w tym miejscu obszar, w którym znajdują się procedury przełączania banków pamięci. Wystarczy, że napisze się pierwszy bajt tej procedury i komputer się zresetuje przy operacjach w BASIC-u.
Jakie zatem jest wyjście jeżeli chcemy by gra chodziła na maszynie128k? Mało profesjonalnie, określę to tak, że wystarczy temu zbyt długiemu plikowi 6940 obciąć 28-bajtowy (już nie potrzebny) „ogon” i szafa gra. Ale jak jak „przycinać” takie pliki?
Otóż w ZX-Blockeditor nachodzimy na nasz blok o długości 6940 bajtów, a następnie prawym klawiszem myszki wybieramy funkcję Modify datablock... a tam w okienku data length: zmieniamy wartość 6940 na 6912 i program obcina „ogon” naszego bloku danych (obrazka).
Ostatnia rzecz to zmiana danych w nagłówku tego obrazka – tam jest teraz błędna wartość długości bloku. Poprawiamy na 6912 i wszystko powinno teraz działać także na ZX Spectrum 128K.

Jest jeszcze jedna możliwość – podmienienie bloku 6940 na blok obrazka 6912 bajtów.
Taki gotowy plik obrazka dla tej gry możemy pobrać z WOS.

http://www.worldofspectrum.org/infoseekid.cgi?id=0004744

Pobieram stamtąd plik SCR będący zrzutem ekranu ładującego grę SPELLBOUND.
Można to też zrobić w każdym emulatorze podczas ładowania tej gry – pauza i zapisz ekran jako SCR.
Mając już gdzieś na dysku plik SCR dla naszej gry, możemy spokojnie skasować w ZX-Blockeditor ten przydługi obrazek, a następnie klikając na TOOLS → Import file... importujemy nasz zapisany plik SCR do obrazu taśmy.

Pamiętajmy aby podczas importowania zaznaczyć do importu jedynie dane obrazu czyli Screen data.
Następnie (przy pomocy zielonych strzałek) ustawiamy nasz blok obrazu (już w odpowiedniej wielkości 6912 bajtów) dokładnie tam gdzie był poprzedni, skasowany blok 6940 bajtów.czyli pozycja 0006.

7. Kolejna (i ostatnia) gra Freddy Hardest

Wszystkie poprzednio przerobione gry (oprócz pierwszej, w której nie mieliśmy do czynienia z procedurami ładowania w asemblerze) miały jeden wspólny mianownik.
Mianowicie po załadowaniu ostatniego bloku przy pomocy procedury w asemblerze, wykonywana była instrukcja RET czyli powrót z kodu maszynowego do loadera w BASIC i uruchomienie gry poprzez instrukcję RANDOMIZE USR.
Teraz, na przykładzie gry Freddy Hardest, wydanej w roku 1987 przez hiszpańską firmę Dinamic Software, zobaczymy, że można uruchomić grę nie „wyskakując” z powrotem do BASIC loadera.

http://www.worldofspectrum.org/infoseekid.cgi?id=0001860

Pobieramy drugi od góry plik TAP.

http://www.worldofspectrum.org/pub/sinclair/games/f/FreddyHardest_2.tap.zip

Będziemy mieli do czynienia z hiszpańską wersją gry. Niestety nie ma sensu aby pobierać wersję angielską ponieważ obie wersje English są zabezpieczone przy pomocy SpeedLock i nie damy rady pracować na tym materiale.
Otwieramy FREDDY.TAP przy pomocy ZX-Blockeditor.

Widzimy, że w obrazie TAP mamy zawarte obie strony taśmy czyli FREDDY1 oraz FREDDY2.
Obraz drugiej strony taśmy jest stworzony analogicznie do pierwszego, zatem jeśli razem przekonwertujemy pierwszą stronę to z drugą poradzicie sobie sami bez najmniejszego problemu.
Zauważcie, że BASIC loader będący na pozycji 0003 ma jakby 2 bloki oznaczone tym samym numerem 0004. Nie należy się tego obawiać. To nie są dwa oddzielne bloki danych. Tak naprawdę to jeden blok. ZX-Blockeditor rozbija dosyć często w ten sposób bloki BASIC na dwie części.
Zobaczmy co ma w sobie loader w BASICu.
Edytujemy przy pomocy ZX-Editor i widzimy:

10 BORDER NOT PI: PAPER NOT PI: CLEAR VAL "65535": PRINT AT VAL "21",NOT PI; PAPER VAL "2"; INK VAL "7";"DINAMIC PRESENTA.."; FLASH VAL "1";"FREDDY HARDEST"
20 PRINT AT NOT PI,NOT PI: LOAD ""CODE : RANDOMIZE USR VAL "24700"

Zwróćmy uwagę, że w naszym programie po raz pierwszy pojawiły się wyrażenia typu VAL oraz NOT PI.
Wyrażenie NOT PI już omawialiśmy – to po prostu 0 VAL używa się także aby oszczędzić pamięć w ZX Spectrum ponieważ CLEAR VAL "65535" zajmuje w pamięci mniej miejsca niż CLEAR 65535.
Nie przejmujmy się tym zbytnio. Nas interesuje linia nr 20 i zawarte w niej instrukcje:

LOAD ""CODE oraz RANDOMIZE USR VAL "24700"

Widzimy, że instrukcja LOAD ""CODE ładuje pierwszy 40-bajtowy blok kodu (pozycja 0006) do pamięci począwszy od adresu 24700. Po załadowaniu zostaje wykonana instrukcja RANDOMIZE USR VAL "24700" czyli uruchomienie załadowanej procedury maszynowej. Na tym kończy się rola naszego loadera w BASIC.
Zobaczmy zatem (przy pomocy Send to ZX-Preview...) jaka jest zawartość tego 40-bajtowego kodu.

>

Kod jest dla nas jakby znajomy. Kilka komend zostało przestawionych miejscami (naprawdę nie ma to najmniejszego znaczenia) oraz doszło kilka nowych rzeczy.
Przeprowadźmy analizę naszego kodu:

LD A, 255         ; załaduj blok danych 
SCF                      ; ustaw znacznik przeniesienia na 1
LD DE, 6912      ; blok danych ma mieć długość 6912 bajtów
LD IX, 30000     ; załaduj ten blok począwszy od adresu 30000
CALL 1366           ; wywołaj procedurę LD-BYTES z ROM

kolejne komendy to coś nowego, ale dokładnie to podstawowa procedura kopiowania bloków danych z jednego do innego miejsca w pamięci:

LD DE 16384     ; pod ten adres skopiuj blok danych
LD HL, 30000    ; dane kopiuj począwszy od adresu 30000
LD  BC,6912     ; dane mają długość 6912
LDIR                      ; kopiuj dane aż cały blok zostanie przekopiowany

Czyli mamy do czynienia z dwoma procedurami. Najpierw pod adres 30000 zostaje załadowany z taśmy blok danych o długości 6912 bajtów (czyli po prostu obrazek). Następnie druga procedura przekopiowuje dane obrazka do adresu począwszy od 16384 (czyli pamięci obrazu). Czyli obrazek „wyskoczy” w całości na ekran, a nie będzie się ukazywał na ekranie powolutku bajt po bajcie. Jednak to nie koniec. Mamy jeszcze kolejną procedurę ładowania.

LD A, 255            ; załaduj blok danych 
SCF                          ; ustaw znacznik przeniesienia na 1
LD DE, 40650    ; blok danych ma mieć długość 40650 bajtów
LD  IX, 24800  ; załaduj ten blok począwszy od adresu 24800
CALL 1366            ; wywołaj procedurę LD-BYTES z ROM
JP 25856               ; skocz do adresu pamięci 25856 

Ta trzecia procedura ładuje ostatni beznagłówkowy blok danych o długości 40650 bajtów, a po jego załadowaniu skacze do adresu 25856 i uruchamia grę.
Wiemy już wszystko jak działa i co się ma gdzie ładować. Zatem przerabiamy nasz obraz taśmy tak, aby każdy blok posiadał swój nagłówek.
W ZX-Blockeditor przy pomocy myszki zaznaczam nagłówek tego 40-bajtowego bloku kodu. Robię CTRL+C (kopiuj) a następnie wklejam CTRL+V.
Przy pomocy zielonej strzałki w dół przesuwam zduplikowany nagłówek tuż nad ostatni blok kodu (czyli ten o długości 40650 bajtów).

Ponieważ zajmujemy się tylko stroną A naszej taśmy zatem aby nie zaciemniać obrazu zaznaczyłem interesujące nas bloki na kolor żółty.
Teraz możemy skasować ten krótki blok 40-bajtowy ponieważ nie będzie nam już potrzebny (pozycja 0006) . Zaś pozostały po nim nagłówek stanie się, po przeróbce, nagłówkiem obrazka będącego teraz na pozycji 0007.
Po dokonaniu zmian, dodaniu nagłówkom odpowiednich nazw oraz poprawieniu adresów ładowania i zmianie wielkości bloków, powinno to wyglądać tak:

Teraz przystępujemy do zmian w BASIC loaderze:
Jest tak:

10 BORDER NOT PI: PAPER NOT PI: CLEAR VAL "65535": PRINT AT VAL "21",NOT PI; PAPER VAL "2"; INK VAL "7";"DINAMIC PRESENTA.."; FLASH VAL "1";"FREDDY HARDEST"
20 PRINT AT NOT PI,NOT PI: LOAD ""CODE : RANDOMIZE USR VAL "24700"

Edytujemy i dokonujemy zmian:
10 BORDER NOT PI: PAPER NOT PI: CLEAR VAL "65535": PRINT AT VAL "21",NOT PI; PAPER VAL "2"; INK VAL "7";"DINAMIC PRESENTA.."; FLASH VAL "1";"FREDDY HARDEST" 20 PRINT AT NOT PI,NOT PI: LOAD "Freddy$"SCREEN$ : LOAD "FreddyC"CODE: RANDOMIZE USR VAL "25856"

Ta ostatnia komenda RANDOMIZE USR VAL "25856" to nic innego, tylko zastąpienie ostatniej komendy naszej procedury w asemblerze JP 25856, która po załadowaniu wszystkich bloków, skakała pod adres 25856, uruchamiając grę.
Zapisujemy tak zmieniony obraz taśmy jako FREDDYb.TAP i sprawdzamy w emulatorze.
Wszystko się załadowało i gra ruszyła. Wysłuchujemy oklasków i idziemy na spacer.
Osobom, które zainteresował temat, pragnę polecić powrót do przeszłości, czyli przejrzenie kilku artykułów w czasopismach BAJTEK.

1. Na temat kopiowania blokowego oraz pamięci obrazu polecam artykuł z BAJTKA 1986 / 8 „Jak schować obrazek” autorstwa Artura Szymańskiego: http://www.marcin-marcin-marcin.com/JakSchowacObrazek.html

2. Cykl artykułów „Od środka” z BAJTKÓW 1988 / 1-8 autorstwa Tomasza Surmacza i Roberta Dudzika: http://www.spectrum.8bit.pl/bajtek/odsrodka.html

3. Artykuły „Krótka rozprawa z taśmą” autorstwa naszego forumowego kolegi Jacka Trojańskiego, które ukazały się w BAJTKACH 1993 / 1,2,5: http://www.marcin-marcin-marcin.com/Rozprawa_z_Tasma/Part1/index.html

Autor: Ikci

Licencja Creative Commons Artykuł autorstwa Ikci został wydany na licencji Creative Commons Uznanie autorstwa - Użycie niekomercyjne - Bez utworów zależnych 4.0 Międzynarodowe License.
W oparciu o utwór dostępny pod adresem http://speccy.pl/articles.php?article_id=49

RafalM
RafalM dnia 13.11.2015 17:33:05

No Ikci, napracowałeś się z tym artykułem. Dzięki za wysiłek.

Napisane jest w bardzo przyjazny i przystępny sposób.

A środowisko od Clausa Jahna jest naprawdę świetne i używam go regularnie do różnych rzeczy. Chociaż pewnie tutaj tego nie przeczyta to dołączam jeszcze wielkie dzięki dla Clausa.

Canga
Canga dnia 14.11.2015 14:33:14

Gratuluję pomysłu, wytrwałości i wspaniałego artykułu!

zoon
zoon dnia 14.11.2015 23:37:34

Super artykuł. Dużo szczegółowych przykładów - sam dotąd nie korzystałem z ZX-Blockeditora a jak widać jest to bardzo przydatne narzędzie.

ikci
ikci dnia 15.11.2015 10:02:19

Panowie, bardzo dziękuję za pozytywne komentarze. Zachęcacie mnie tym samym do dalszego działania!

Dodaj komentarz
Zaloguj się, aby móc dodać komentarz.
Oceny
Tylko zarejestrowani użytkownicy mogą oceniać zawartość strony
Zaloguj się , żeby móc zagłosować.

Brak ocen. Może czas dodać swoją?