Budowa plików SpartaDOS X


       Plik sam w sobie jest tylko niewiele wartym zbiorem bajtów. Mnóstwo liczb, które mogą oznaczać wszystko, a zarazem nic, jeśli nie wiadomo jak je zinterpretować. Większość plików wyposaża się z tego powodu w różnorodne nagłówki, w których pamiętane są informacje o tym co plik zawiera, ew. jak go potem traktować przy odczycie. Do takich należą również pliki wykonywalne, binarne, czy po prostu: przeznaczone do załadowania z poziomu DOSu. Wszak DOS to też program i jak każdy inny ma prawo oczekiwać danych o określonej, znanej mu strukturze.

       Tradycyjne pliki binarne, rozpoznawane przez wszystkie DOSy dla komputerów Atari XL/XE, mają budowę blokową, gdzie każdy blok posiada swój nagłówek Istnieją dwa rodzaje nagłówków:

      1. dta a($ffff),a(str_adr),a(end_adr)
      2. dta a(str_adr),a(end_adr)

gdzie:

  str_adr- adres, pod który zostanie załadowany pierwszy bajt danych,
  end_adr- adres, pod który zostanie załadowany ostatni bajt.

       Pierwszy blok w pliku musi mieć nagłówek typu $ffff, pozostałe bloki dowolnie. Za nagłówkiem oczywiście powinny znaleźć się dane w ilości:

(end_adr-str_adr)+1

       Tyle tytułem przypomnienia. Twórcy systemu Sparta DOS X zachowali powyższy standard, dodając jednocześnie kilka nowych typów nagłówków. Ciągle więc mamy do czynienia z plikiem podzielonym na bloki, z tym że rodzajów bloków jest teraz dużo więcej. Oto one:

1. Blok nierelokowalny (ładowany pod stały adres w pamięci):

      dta a($fffa),a(str_adr),a(end_adr)

Jest to to samo co blok $ffff - nie ma znaczenia, który zostanie użyty. $fffa będzie jednak wyraźnie wskazywać, że program jest przeznaczony dla SDX - inny DOS takiego pliku nie odczyta.

2. Blok relokowalny (ładowany pod MEM-LO we wskazany rodzaj pamięci):

      dta a($fffe),b(blk_num),b(blk_id)
      dta a(blk_off),a(blk_len)

blk_num - numer bloku w pliku. Każdy blok relokowalny powinien posiadać swój własny numer. Ponieważ adresy ładowania bloków nie są znane, bloki identyfikowane są właśnie poprzez swoje numery. Mogą one przyjmować wartości z zakresu 0-7, z tym że w praktyce stosuje się zwykle numerację od 1 w górę.
blk_id - bity 1-5 stanowią indeks pamięci, do której blok ma zostać załadowany. Spotkałem się z dwoma wartościami: $00 - pamięć podstawowa, $02 - pamięć rozszerzona. Ustawienie dodatkowo bitu 7 oznacza brak bloku danych. SDX nic wtedy nie ładuje, ale rezerwuje pamięć.
blk_off - tzw. przesunięcie adresów w bloku, czyli po prostu adres, pod który był assemblowany kod. Jest to potrzebne przy uaktualnianiu adresów odwołujących się do zawartości bloku.
blk_len - długość bloku. Tyle danych powinno być za nagłówkiem chyba, że jest to blok rezerwujący pamięć wtedy danych nie ma.

       Pisząc kod relokowalny trzeba mieć na uwadze kilka ograniczeń jakie narzuca idea "przemiaszczalnego" kodu. Wszystkie adresy odwołujące się do obszaru takiego programu muszą zostać uaktualnione podczas ładowania, w związku z tym nie można używać sekwencji takich jak np.:

       lda <coś
       ldx >coś
       ...
   coś equ *
       ...

Zamiast tego, pozostaje np.:
       lda _coś
       ldx _coś+1
       ...
  _coś dta a(coś)
       ...
   coś equ *

3. Blok aktualizacji adresów odnoszących się do bloku relokowalnego:

      dta a($fffd),b(blk_num),a(blk_len)

blk_num - numer bloku, do którego odnoszą się uaktualniane adresy. blk_len - długość bloku aktualizacji (bez nagłówka). Jest ona ignorowana.

       Adresy są uaktualniane poprzez dodanie do adresu istniejącego różnicy pomiędzy adresem, pod który został załadowany wskazany blok relokowalny, a wartością blk_off (adresem asemblacji) tego bloku. Można to przedstawić wzorem:

ADR=ADR+(blk_adr-blk_off)

       "Ciało" bloku aktualizacji stanowią wskaźniki do poprawianych adresów oraz rozkazy specjalne. Wskaźnik jest liczbą z zakresu $00-$fb i oznacza przesunięcie względem miejsca poprzedniej aktualizacji. Miejsce to jest pamiętane przez program ładujący jako bezpośredni adres -nazwijmy go licznikiem aktualizacji. Licznik ten można zainicjować za pomocą funkcji specjalnych, którymi są liczby większe od $fb:

$fc- oznacza koniec bloku aktualizacji,
$fd,a(ADDR)- następuje aktualizacja adresu wskazanego bezpośrednio przez ADDR. Tym samym wartość ADDR jest wpisywana do licznika aktualizacji i od niej będą liczone kolejne przesunięcia,
$fe,b(blk_num)- do licznika aktualizacji wstawiany jest adres bloku wskazanego przez blk_num, czyli kolejne aktualizacje będą się odnosiły do kodu zawartego w tym bloku,
$ff- licznik aktualizacji zwiększany jest o $fa (bez aktualizacji adresu).

4. Blok aktualizacji adresów procedur zdefiniowanych symbolami:

      dta a($fffb),c'SMB_NAME',a(blk_len)

Gdzie:
SMB_NAME - symboliczna nazwa procedury (lub tablicy, rejestru systemowego itp.) Osiem znaków w kodzie ATASCII,
blk_len - jak w bloku $fffd.

       Po nagłówku występuje ciąg wskaźników określających położenie adresów do zaktualizowania - identycznie jak w bloku $fffd. Adresy są zmieniane poprzez dodanie do istniejącego adresu, adresu procedury określonej symbolem. Pozwala to na wykorzystywanie w programach procedur, których adresów nie znamy, np. procedur dodawanych przez inne programy uruchamiane w środowisku SDX. Także procedury systemowe powinny być wykorzystywane w ten sposób, przecież mogą one mieć różne adresy w różnych wersjach Sparty.

5. Blok definicji nowych symboli:

      dta a($fffc),b(blk_num),a(smb_off)
      dta c'SMB_NAME'

blk_num - numer bloku, w którym znajduje się definiowana procedura. Wynika z tego, że procedura musi być załadowana jako blok relokowalny.
smb_off - przesunięcie adresu procedury w bloku, czyli offset procedury względem początku bloku (pierwszy bajt ma numer 0) powiększony o wartość blk_off tego bloku. Inaczej: jest to adres pod jaki procedura została zassemblowana,
SMB_NAME - symboliczna nazwa definiowanej procedury.

       Bloki typu $fffb, $fffc, $fffd nie są na stałe zatrzymywane w pamięci. System wykorzystuje je tylko podczas ładowania programu.

       Wygląda to być może na trochę zagmatwane, lecz w rzeczywistości jest bardzo proste. Proponuję dla lepszego zrozumienia przejrzeć budowę kilku plików napisanych specjalnie dla SDX. Tutaj powinien znajdować się tekst źródłowy (wraz z nagłówkami) programu CLOCK.SYS z carta SDX.

       Jest to dość ciekawy przypadek, ponieważ zawiera wszystkie typy bloków i to w różnych wariantach - polecam, z pewnością ułatwi przyswojenie tematu.

       Przy pisaniu tego artykułu korzystałem ze źródeł Sparta DOS X opracowanych przez Marka M.M. Goderskiego oraz z własnych obserwacji i doświadczeń. Mam nadzieję, iż art ten zaoszczędzi zain teresowanym czasu i nerwów, oraz że przyczyni się do lepszego wykorzysta nia możliwości jakie drzemią w SDX.

       Życzę sukcesów w walce z systemem ;)

Qcyk/Dial