Winter Olympiad 88 - Turbo version by *AJEK
Hej!
Trochę to zajęło, ale w końcu znalazłem czas aby dokończyć sprawę odzyskania Winter Olympiad 88 w wersji dla Turbo 2000 (KSO/F) którą zrobił swego czasu *AJEK, a którą to udostępnił tutaj QTZ.
Gra w wersji turbo została podzielona na kilka bloków, na które składają się loader, intro, oraz pliki zawierające poszczególne dyscypliny (Downhill, Ski Jump, Biathlon, Slalom, Bobsled).
Konwersja tego zajęła mi trochę czasu, ponieważ borykałem taśmy z których zrzutu dokonał QTZ były już dość stare, a więc wysokie częstotliwości zapisane na taśmie były już na poziomie tak niskim że ledwie udało się to wszystko odzyskać. Na szczęście QTZ zgrał kilka wersji, i tylko dzięki temu udało się poskładać całość, wybierając najlepsze fragmenty nagrań z kilku plików źródłowych.
Do kompletu *AJEK postanowił zabezpieczyć swoją wersję przed kopiowaniem, zapewne dlatego aby konkurencja giełdowa nie mogła “bezstratnie” powielać jego wersji. Nie będę tutaj ukrywał faktu, że przez zabawę z tymi nagraniami i próbami odtworzenia całości, nabyłem też nieco więcej doświadczenia z obróbką tego typu sygnałów. Zauważyłem że uparte siedzenie i walka z jakimś nieczytelnym fragmentem zapisu nie jest dobrym pomysłem, bo w człowieku szybko rodzi się frustracja. Mi pomagało oderwanie się na jakiś czas od tematu i zajęcie się czymś innym. Potem wracałem do tego po jakimś czasie z nowymi siłami.
Na moją frustrację nałożyło się też to że *AJEK wykonał swoją pracę nieco “na odwal się”, byle działało to “jakoś”, początkowo myślałem że to przekłamania w nagraniach i przypadkowo tylko zgodziła mi się suma kontrolna, ale analizując kod doszedłem do wniosku że pod koniec roboty *AJK-owi się już nie chciało. Popełnił kilka kardynalnych błędów, które wymagały “patchowania”, niektórych miejsc pliku. Pojawiało się też kilka tzw. “glitch”, spowodowanych brakiem czyszczenia pamięci, albo wykorzystaniem miejsc pamięci (na loadery czy inny kod) co do których producenci gry oczekiwali że będą puste.
Poprawiłem najważniejsze tego typu “zaciachy”, a resztę (takie usterki które nie powodowały zawieszania się programu) zostawiłem w takim stanie w jakim zastałem. Jedną z widocznych pozostałości, jest to że gdy gramy we wszystkie dyscypliny po kolei i dokonamy pierwszego startu w konkurencji “Bobsled”, to zamiast animacji nóg postaci ujrzymy śmiecie, na grafice, jednak ponowne rozpoczęcie tej konkurencji powoduje że animacja wyświetla się już poprawnie. Do kompletu początkowo wersja z loaderem dla “Turbo 2000F” (dane pojawiają się na SIO DATA IN), nie działała poprawnie, tzn. gra nie wykrywała naciśnięcia klawiszy… a to tylko dlatego że kod sprawdzający wciśnięcie klawisza, jest naprawdę jakiś “porąbany”, i zamiast “filtrować” z rejestru SKSTAT nieistotne bity, jest skonstruowany tak że bierze pod uwagę nieistotne bity… nie wiem czy to jest jakiś fragment zabezpieczenia oryginalnej wersji, czy też po prostu nielogiczy i bezsensowy kod, jednak występuje on w oryginalnej wersji dyskowej, zatem go zostawiłem z niezmienionej formie:
14B7: A9 00 LDA #$00
14B9: 8D 0E D2 STA IRQEN
14BC: AD 0F D2 LDA SKSTAT
14BF: 09 08 ORA #$08
14C1: C9 FF CMP #$FF
14C3: D0 F7 BNE $14BC
14C5: E6 A3 INC $A3
14C7: A2 00 LDX #$00
14C9: AD 0F D2 LDA SKSTAT
14CC: 29 04 AND #$04
14CE: F0 06 BEQ $14D6
14D0: CA DEX
14D1: D0 F6 BNE $14C9
14D3: A9 00 LDA #$00
14D5: 60 RTS
Do działania klawiatury w przypadku wersji Turbo 2000F doprowadziłem, dbając o to aby wejście szeregowe pozostało po transmisji w odpowiednim stanie i tak aby bit 4, rejestru SKSTAT był w takim stanie aby powyższa procedura działała poprawnie.
Jeżeli chodzi o patch w krytycznym miejscu, to po zakończeniu wszystkich dyscyplin, wersja *AJKA powinna była wypisać komunikat o ustawieniu taśmy na początku i wciśnięciu klawisza “OPTION” celem, wykonania zimnego startu komputera. Jednak kod który miał zostać uruchomiony wyglądał na uszkodzony, tzn. domyślam się że miało być tak:
LDX #$00
CPL LDA $BB00,X
STA $BD00,X
INX
BNE CPL
…
co po przełożeniu na kod maszynowy daje następującą sekwencję bajtów:
gdzie bajty “A2 00”, odpowiadają instrukcji LDX #0, jednak którą z części nagrania bym nie przetwarzał to zamiast “A2 00”, wychodziło mi że tam jest “52 00”, a więc sądziłem że to przekłamanie w nagraniu, poprawiłem więc szybko na “A2 00” i sądziłem że sprawa jest załatwiona. Niestety, okazało się że owo “52”, należy do tablicy zawierającej poszczególne adresy ładowania kolejnych bloków. A owa tablica “zadeptała” ów nieszczęsny kod, a więc “Boblsed” po zakończeniu rozgrywki skakał pod adres i CPU próbował wykonać instrukcję “52”, która jest po prostu niezdefiniowaną instrukcją, w tym wypadku “CIM” czy “KIL”, z 6502 po napotkaniu bajtu 52, po prostu się zawiesza i tylko reset jest w stanie wyprowadzić go z tego stanu. Należało więc tak poprawić kod aby bajty tabeli adresów ładowania pozostały niezmienione, a jednocześnie kod mógł być wykonany poprawnie. Skończyło się na tym że poprawiłem inny kawałek, modyfikując go tak i skracając aby procedura wywołująca ten kod skakała dwa bajty dalej, a w rej. X przed skokiem znajdowała się wartość 0. Po dokonaniu poprawek okazało się że komunikat o przewinięciu taśmy do “HEAD 1”, pokazuje się (zamiast zawieszenia się maszyny). A OPTION powoduje reboot. Tyle walki o tak bezsensowny drobiazg? :) no cóż… wnerwiało mnie to, więc poprawiłem. Wiem że niewiele to wnosi, jednak nie potrafiłem przejść obojętnie obok takiej “fuszerki” :P (oczywiście piszę to trochę z przymrużeniem oka, zapewne *AJEK zorientował się że popełnił taki błąd, jednak pewnie nie chciało mu się tego już poprawiać”, kod obsługujący to wszystko znajduje się bowiem w pierwszym bloku nagrana, tzn. “HEAD 1”)
Ufff…. to by było na tyle jeżeli chodzi o krótki wstęp i wprowadzenie do tegoż tematu. Teraz przejdźmy do następnego tematu czyli struktury samego nagrania i zastosowanego formatu zapisu danych. Gra wersji turbo składa się następujących plików:
Loadera (w wersji dla systemów KSO Turbo 2000 lub pozostałych)
Czołówka gry / Into (HEAD 1)
Downhill (PART 1)
Ski Jump (PART 2)
Biathlon (PART 3)
Slalom (PART 4)
Bobsled (PART 5)
ad 1) loader występuje w dwóch wersjach:
#1 wersja która wczytuje dane używając interface dla KSO Turbo 2000 (sygnał oczekiwany na drugim porcie joysticka)
#2 wersja która wczytuje dane używając interface dla systemów Turbo 2000F, AST, ATT, UM, etc. (sygnał oczekiwany na linii SIO DATA IN). Będą działać wszystkie systemy turbo które to aktywuje się albo za pomocą odpowiedniego stanu linii COMMAND (AST, ATT, UM, Turbo 2000CS, Turbo 2000 “Wrocławskie”) lub za pomocą manualnego przełącznika, czyli np. Turbo 2001/2000F, itp.
Loader jest zapisany w postaci standardowego bloku zgodnego z formatem Turbo 2000 (KSO lub 2001/F). Jest to po prostu zwykły plik binarny DOS-u, ładujący się w obszar $1E00-$24FF. Zatem można go nagrać w dowolnym formacie i na dowolnym nośniku.
ad 2) Czołówka gry [plik: “01_head1_(INTRO).cas”] zapisana jest w postaci jednego długiego bloku danych ładującego się w obszar $0600-$85FF.
ad 3) “Downhill” [plik: “02_part1_(DOWNHILL).cas”] składa się z dwóch bloków danych ładowanych przez mini loader “schowany” pod OS-ROM. Blok pierwszy ląduje w lokalizacji $0600-$25FF (potem zostaje przepisany pod OS-ROM w obszar $E000-$FFFF), blok drugi ładowany jest w obszar $0600-$BBFF.
ad 4) “Ski Jump” [plik: “03_part2_(SKI JUMP).cas” ] składa się również z dwóch bloków danych ładowanych przez mini loader “schowany” pod OS-ROM. Blok numer jeden ląduje początkowo w obszarze $0800-$27FF, po czym zostaje przepisany pod OS-ROM w obszar $E000-$FFFF), drugi blok jest ładowany jest w obszar $0800-$907F.
ad 5) “Biathlon” [plik: “04_part3_(BIATHLON).cas”] składa się także z dwóch bloków danych ładowanych przez mini loader “schowany” pod OS-ROM. Pierwszy blok ląduje tym razem w lokalizacji $0700-$26FF, a po załadowaniu jest przemieszczony jak zwykle w obszar $E000-$FFFF, drugi z bloków danych jest ładowany w obszar $0700-$7EFF.
ad 6) “Slalom” [plik: "05_part4_(SLALOM).cas"] składa się jak poprzednio dwóch bloków danych ładowanych przez mini loader “schowany” pod OS-ROM. Pierwszy blok ładowany jest tymczasowo w obszar $0680-$267F, i przemieszczony następnie obszar $E000-$FFFF, a drugi z bloków danych tym razem jest ładowany w obszar $0680-$B57F.
ad 7) “Bobsled” [plik: “06_part5_(BOBSLED).cas"] składa się zwyczajowo z dwóch bloków danych ładowanych przez ten sam mini loader “schowany” pod OS-ROM. Pierwszy blok ładowany jest tymczasowo w obszar $0480-$6F7F, po czym obszar od $6800-$6FFF jest przenoszony w obszar $C000-$C7FF, a drugi z bloków zostaje załadowany w obszar $6858-$BA57.
To tyle jeżeli chodzi o strukturę nagrania i opis plików wchodzących w skład tej wersji Winter Olympiad 88. Teraz pozostało tylko opisać format danych który został użyty do zapisu tychże plików na taśmie.
Pliki “Intro, part1 … part5” są zapisane z wykorzystaniem standardowej modulacji PWM używanej przez systemy z serii Turbo 2000/2001/F/KSO, tzn. długości impulsów oznaczające ton pilotujący oraz kodujące logiczne “0” oraz logiczną “1”, odpowiadają tym użytym w standardowym Turbo 2000. Jedynie układ bitów w blokach danych jest celowo zmieniony tak aby uniemożliwić kopiowanie zwykłymi narzędziami przeznaczonymi dla tych systemów. Format nie jest jakoś specjalnie zagmatwany, powiedziałbym że wręcz dość prymitywny, jednak na tyle skutecznie zmieniony że dostępne wtedy narzędzia na pewno nie radziły sobie z kopiowaniem tego strumienia danych. Co zatem składa się na blok danych zapisanych w formacie loadera?
paru tysięcy impulsów tonu pilotującego (domyślnie w Turbo 2000/F/KSO jest to 4096 impulsów)
7 losowych bitów (7 impulsów kodujących losowe zera i jedynki)
bloku danych (długość bloku danych zaszyta jest na sztywno w kodzie loadera, tzn. loader dokładnie wie ile będzie miał blok wczytywanych danych)
1 bajtu sumy kontrolnej (modulo 256)
paru impulsów (minimalnie 1 imp.) reprezentujący dowolną wartość (0,1)
Całe zabezpieczenie jak widać polegało na tym iż pierwsza porcja danych składała się z 7 a nie ośmiu bitów, zatem większość programów kopiujących czy procedur odczytu gubiła się w tym, bo albo po odczycie tak spreparowanego bloku danych, nie zgadzało się CRC, a dane wyglądały na “sieczkę”, bo były przesunięte o jeden bit w lewo, albo procedura odczytu zgłaszała błąd bo brakowało jej jednego bitu na końcu strumienia danych.
Używając kilku python-owych skryptów “naklepanych” byle jak na kolanie, aby przetworzyć pliki WAV zawierające poszczególne bloki danych, udało się zmusić narzędzie narzędzie a8cas-util od FUJI-ego, do jako takiego przetworzenia strumienia danych (oczywiście z przesunięciem bitowym) … i błędnym CRC na końcu. Napisałem na szybko, tym razem w C program który przesunął cały bit-stream tak aby dane wylądowały ponownie w granicach bajtów miałem już do dyspozycji pliki .HEX które miały poprawnie ułożone dane, które to dane można było edytować i patchować, dzięki temu dało się poprawić wyżej opisane fragmenty kodu.
Oczywiście mógłbym ten strumień zostawić tak jak w przypadku GABI czy KVADRK jako blok danych PWMS, jednak wtedy jego edycja nie byłaby tak łatwa i oczywista, a sprzątanie i porządkowanie segmentów w pliku HEX który potem przetworzyć do postaci CAS nie byłoby możliwe.
Na początku miałem napisać co prawda sobie cały program do konwersji danych w tym formacie, jednak uznałem że to nie ma najmniejszego sensu ponieważ jest to przypadek raczej jednorazowy, a gdyby się trafiło coś innego w przyszłości to i tak bym poddawał to wnikliwej analizie tak czy siak. Więc napisanie uniwersalnego narzędzie tylko dla samego siebie mijało się kompletnie z celem, dlatego też postanowiłem wykorzystać dobrodziejstwa a8cas-util, oraz jakieś szybko sklecone na boku prymitywne programy do przetwarzania i konwersji danych.
Swoją drogą gdyby nagrania udostępnione przez QTZ zachowały się w lepszej jakości zapewne nigdy bym nie zabrał się za analizę i wnikanie w format danych zastosowany przez *AJEK w przypadku tejże wersji taśmowej dwu-dyskietkowej gry jaką był w oryginale Winter Olympiad 88.
W załączniku archiwum zawierające loadery w postaci CAS oraz XEX. A także pliki zawierające dane gry w formacie CAS. Myślę że ich nazwy mówią same za siebie i pozwolą bez problemu zidentyfikować odpowiedni plik gdy gra poprosi o wczytanie konkretnego zbioru danych.
Dla zainteresowanych tym wszystkim o czym pisałem wyżej, do archiwum dołączam również pliki HEX, pozwalające na dokładniejszą analizę budowy i struktury opisywanych tu zbiorów. W plikach które załączam pozwoliłem sobie zamiast losowego 7-bitowego “śmiecia” wysyłać po prostu 7 bitów zer, loader i tak ignoruje ten fragment nagrania. A losowe wartości obecne w oryginalnym nagraniu miały zapewne na celu “zmylenie przeciwnika” ;)
To chyba już wszystko co chciałem napisać na temat “walki” z tą wersją “Winter Olympiad 88”. Dla zainteresowanych archiwum zawierające wspomniane wyżej pliki do pobrania poniżej.
ps1) Trzymajcie się i nie dajcie się tej zwariowanej obecnie rzeczywistości. Niebawem, o ile sytuacja pozwoli - wrócę pewnie znów do analizy sprzętu od Uicr0Bee, który czeka w kolejce już zdecydowanie za długo.
ps2) pewnie zapomniałem napisać masę rzeczy i pewnie zrobiłem masę błędów pisząc ten tekst w pośpiechu (chciałem jak najszybciej to już zakończyć) ... więc jeżeli zauważę jakąś rażącą niezgodność lub błędy to będę edytował ten post. Na razie wrzucam tak jak jest. Wydaje mi się że koniec końców napisałem mniej więcej to o co mi chodziło.
Post's attachmentsQTZ - Winter Olympiad 88 (Tynesoft) [AJEK].zip 282.47 kb, liczba pobrań: 13 (od 2022-03-04)
Tylko zalogowani mogą pobierać załączniki.