Niniejszy cykl artykułów jest przezna­czony dla Czytelników dobrze znają­cych język maszynowy. Objaśni on w jaki sposób wykorzystywać system dys­kowy TOS z poziomu kodu maszynowe­go. Pokaże również nowe możliwości, jakie niesie ze sobą posługiwanie się pamięcią RAM interfejsu i stacji dysków.

TOS bez tajemnic

TOS bez tajemnic cz. 1

Większość zawartych tu informacji została zdobyta empirycznie poprzez wielogodzinne analizowanie kodu ma­szynowego. Dlatego też część opisa­nych procedur i zmiennych systemo­wych nie ma nazw. Jeśli je już wyko­rzystywałeś i stworzyłeś w tym celu własne nazewnictwo, możesz uzupeł­nić celowo pozostawione puste miejs­ca w tabelkach.

Z uwagi na nikłą przydatność BASIC-a wymagana jest dobra znajo­mość obsługi programów monitora i asemblera, zaś wszystkie adresy po­dawane są heksadecymalnie.

Trzy słowa o systemie

Dyskowy system operacyjny TOS (Timex Operatng System) służy do ob­sługi komputera ZX Spectrum lub Timex, połączonego za pomocą interfej­su ze stacją dysków Timex FDD 3000. W sktad stacji dysków wchodzi kontroler, zasilacz i napędy dyskietek. [Są dwa typy obudowy - jeden składa się z trzech modułów, drugi to jedna obudowa z miejscem na dwa napędy 3". JA] Kontroler zawiera procesor Z80A, ROM, 64 kB pamięci RAM, sterownik dysku i ukła­dy wejścia-wyjścia. Jest to właściwie oddzielny komputer. Interfejs składa się z 4 kB ROM, 1 kB RAM, oraz ukła­du elektronicznego odpowiedzialnego za "adresy i kontakty".

Większa część kodu systemu TOS ładowana jest podczas startu systemu z dyskietki i zajmuje pierwsze 16 kB pamięci RAM stacji dysków. [W zasadzie to kod stały zajmuje 10kB, jedna z nakładek 2kB, a reszta przeznaczona jest na bufory. JA] Obsługu­je ona złącza RS232C oraz napędy dyskowe. Pozostałe 48 kB jest wolne. Część odpowiadająca za istnienie no­wych instrukcji w BASIC-u znajduje się w pamięci ROM interfejsu.

Jak działa interfejs?

Wspomniany już, zawarty w interfej­sie układ elektroniczny reaguje na po­jawienie się na szynie adresowej trzech szczególnych adresów. W mo­mencie wykrycia wykonywania pro­gramu o adresie #0000 lub #0008, odłącza on standardowy ROM Spec­trum i podłącza w jego miejsce ROM i RAM interfejsu. Proces ten nazywany jest dalej uaktywnieniem się interfejsu. Po wykryciu adresu #0604 zachodzi zjawisko odwrotne.

TOS A.2. Mapa pamięci komputera przed i po uaktywnieniu interfejsu.
Rys. 1 - Mapa pamięci komputera przed i po uaktywnieniu interfejsu.

Dzięki takiej konstrukcji TOS może kontrolować komputer podczas jego restartu (RST 0; wczytanie programu o nazwie "START"), lub w trakcie ob­sługi błędu składni (RST 8; gwiazdka, czyli nowe instrukcje).

Do obsługi pamięci interfejsu stoso­wane jest niepełne adresowanie, skut­kiem czego jest ona widoczna na raz w kilku miejscach. [Z wyjątkiem TI-of-TTL, który ma pełne adresowanie i odpowiednio dużą ilość pamięci. Interfejs z kwadratowym układem logiki bardzo łatwo jest przerobić na 2kB RAM. JA] Przy programowaniu trzeba pamiętać, że pamięć ekranu styka się fizycznie z obszarem RAM interfejsu.

TOS A.2. Ogólny algorytm obsługi wywołania RST 8 przez interfejs.

Rys. 2 - Ogólny algorytm obsługi wywołania RST 8 przez interfejs.

Pierwsze kroki

Twórcy systemu TOS napisali go bardzo przyjaźnie i zostawili kilka fur­tek dla programistów. Jest to dobrze widoczne na zamieszczonym algoryt­mie (Rys. 2.). Nie jest sytuacją normal­ną, że podczas wywołania RST 8 w rejestrze IY jest zero - w BASIC-u nie jest to możliwe - zatem reakcja na to jest specjalna, czyli rozkaz RET. [Normalnie IY wskazuje na obszar zmiennych BASIC. JA] Dzię­ki takiej konstrukcji można łatwo uak­tywnić interfejs wywołując następujący podprogram:

DR_ON	PUSH	IY	;przechowanie zawartości rejestru IY
	LD	IY,0	;załadowanie znacznika
	RST	8	;uaktywnienie interfejsu
	POP	IY	;odtworzenie zawartości rejestru IY
	RET		;powrót

Procedura DR_ON nie zmienia za­wartości rejestrów i jedynym wynikiem jej działania jest zamiana pamięci ROM komputera na pamięć interfejsu, oraz wyłączenie przerwań maskowalnych. Jest ona podstawowym składni­kiem większości programów i jej naz­wa wielokrotnie się jeszcze powtórzy.

ROM komputera jest teraz niewido­czny i niemożliwe jest bezpośrednie używanie jego procedur. Struktura pa­mięci jest widoczna po prawej stronie rysunku 1, zaś bardziej dokładny opis znajdziesz w tabelach.

Ponowne uaktywnienie ROM-u ZX Spectrum realizowane jest, jak już wiadomo, poprzez wykonanie rozkazu spod adresu #0604. Jego sąsiedztwo wygląda następująco:

#0603	EI		;włączenie przerwań maskowalnych
#0604	RET		;powrót i uaktywnienie ROM kompute­ra

Widać więc, że standardowy ROM można włączyć na dwa sposoby: po­przez skok pod adres #0603 z włącze­niem przerwań, albo pod adres #0604 bez włączenia przerwań niemaskowal-nych.

RAM interfejsu (tabela 1)

Pierwsze 256 bajtów pamięci RAM in­terfejsu używane jest jako bufor. Wszyst­kie dane transmitowane do i ze stacji dy­sków wędrują przez ten obszar.

Następne 82 bajty to zmienne sy­stemowe. Z punktu widzenia progra­misty ważne są właściwie te, które opatrzone są w tabeli etykietami. Oprócz tego na wyróżnienie zasługuje obszar od #210D do #212C, gdzie przechowywany jest komunikat błędu, oraz adres #213A zawierający znacz­niki stanu systemu. Te ostatnie są ustawione tylko w trakcie wykonywa­nia instrukcji TOS-u, w pozostałym czasie mają wartość zero i większość z nich nie ma dla nas praktycznego znaczenia. Jedynie bit 0 można wyko­rzystać: jego ustawienie powoduje, że najbliższe wywołanie RST 8, zadziała tak jak procedura DR_ON.

Pozostałe 684 bajty są wolne i moż­na tam umieścić własny program. In­strukcja dołączona do stacji dysków podaje wprawdzie, że pamięć wolna zaczyna się od adresu #2156, jednak praktyka wykazuje, iż ostatni używany bajt zmiennych systemowych to #2153.

TABELA 1. RAM (#2000-#23FF) oraz (#2400-#27FF), (#2800-#2BFF), ...
adresnazwadł.opis
#2000-#20FFbufdat256Bufor danych.
#2100-#215384Zmienne systemowe TOS-u
 #2100mod1Numer operacji do wykonania.
#2101-#210C12Zawartości rejestrów procesora przy przesyłaniu komendy, kolejno: AF, BC, DE, HL, IX, IY.
#210D-#212C32Tekst komunikatu błędu.
#212D1Ilość bajtów nagłówka przy operacjach SAVE lub LOAD.
#212Echan1Numer kanału.
#212F-#2131typ3Nagłówek przy komunikacji komputera ze stacją dysków.
 #212F1rodzaj bloku: #CO-konenda, #DO-bufor.
#21301długosc przesyłanego bloku.
#21311znacznik pcprawnosci przesłania: #BO-OK, #EO-błąd.
#21321Ilość prób przesłania bloku.
#21331Typ zapisywanego lub odczytywanego pliku (DATA, CODE itp. ).
#2134-#21396Obszar zmiennych roboczych; mają one różne funkcje w zależności od wykonywanego polecenia.
#213A1Znaczniki stanu systemu; ustawienie odpowiedniego bitu oznacza:
0-system wykona rozkaz RET przy RST 8,
1-analizowane polecenie jest poprawne,
2-analiza składni,
3-podano długość rekordu,
5-pobieranie liczb ze stosu
#213BfInlt2Adres procedury wywołania obsługi błędu, gdy analizowany błąd nie jest rozkazem TOS-u. Standardowo #0082. Podając adres własnej procedurt, możemy rozszerzyć listę rozkazów.
#213D2Adres procedury powrotu do BASIC-u po wykonaniu rozkazu TOS-u. Standardowo #06E3 (nie mylić z #0603).
#213F2Podczas analizy składni przechowuje początkową wartość zmiennej systemowej CH_ADD.
#21412Chwilowe przechowanie wartości DE podczas wywołania procedury CBAS.
#21432Nie używane.
#2145prolen2Długość odczytywanego lub zapisywanego bloku.
#2147prostr2Adres odczytywanego lub zapisywanego bloku.
#21492Adres zmiennej tekstowej.
#214B2Długość lub numer rekordu.
#214Dflletyp1Typ bloku przeznaczonego do zapisu.
#214Efllelen2Długość tego bloku.
#2150start2Adres początkowy tego bloku.
#21522Przy LOAD - długość programu w języku BASIC.
#2154-#23FF684PAMIĘĆ WOLNA

ROM interfejsu (tabela 2)

Aby móc pooglądać ROM, należy użyć wybiegu i przenieść jego zawartość do pamięci operacyjnej komputera. Tam można już użyć programu moni­tora. Najprościej jest napisać SAVE *"ROM"CODE 0,4096: LOAD *"ROM" CODE 32768. Bardziej eleganckim roz­wiązaniem jest krótki program maszy­nowy:

	CALL	DR_ON		;uaktywnienie interfejsu
	LD	HL,#0000	;z
	LD	DE,#8000	;do
	LD	BC,#1000	;ile
	LDIR			;przeniesienie zawartości ROM-u pod adres #8000
	CALL	#0603		;uaktywnienie standardowego ROM-u
	RET			;powrót
;zamiast dwóch ostatnich rozkazów można napisać JP #0603

Dokładna znajomość ROM-u nie jest konieczna, aby móc go wykorzy­stywać, jednak myślę, że warto zaj­rzeć w kilka miejsc. Trzeba przekonać się samemu jak właściwie wygląda ob­sługa RST 8. Pouczające jest również rozszyfrowanie sposobu działania pro­cedury spod adresu #031D (szukać pod #831D !!). Przede wszystkim jed­nak trzeba zobaczyć co znajduje się w obszarze #0605-#0628 (teraz #8605-#8628). Wystarczy dobrze go poznać i można wtedy zrobić w systemie TOS właściwie wszystko - od nagrywania programów po dostęp do pamięci sta­cji. Już za miesiąc.

TABELA 2. ROM (#0000-#0FFF) oraz (#1000-#1FFF)
#0000-#0007Skok do procedury startu systemu.
#0008-#031CObsługa wywołania EST 8, tabele oraz podprogramy analizy składni.
#031D-#0363Procedura wywoływania programów z ROM komputera.
#0364-#03D7Podprogramy komunikacji wyższego poziomu; przesyłanie bufora lub komendy do i ze stacji dysków.
#03D8-#0494Podprogramy obsługi błędów; wydruk komunikatów, testowanie klawisza BREAK, powrót do BASIC-a.
#0495-#05BDPodprogramy komunikacji niższego poziomu; przesyłanie bloków i pojedynczych bajtów.
#05BE-#0602Nazwa pliku wczytywanego przy starcie systemu - "START".
#0603-#0604Odłączanie ROM interfejsu, bez lub z włączeniem przerwań.
#0605-#0628Tablica skoków do ważniejszych podprogramów.
#0629-#0EE0Podprogramy wykonujące poszczególne rozkazy TOS-u.
#0EE1-#0FFFProcedura startu oraz tekst "© TIMEX - TOS A.2".


Wojciech Jabłoński

TOS bez tajemnic cz. 2

W drugiej i trzeciej części cyklu zajmować się bę­dziemy znajdującą się w ROM-ie interfejsu tablicą skoków. Zaczyna się ona od adresu #0605 i zawiera kolejno dwanaście sko­ków do praktycznie wszystkich użytecznych procedur systemu operacyjnego.

Odwoływanie się do tablicy skoków, zamiast bezpośrednio do adresów wy­woływanych procedur, ma pewne uza­sadnienie. Zapewnia mianowicie kom­patybilność napisanego programu z nowymi wersjami systemu operacyj­nego. Ewentualny nowy ROM interfej­su musi zawierać analogiczne proce­dury, ale mogą być w zupełnie innych miejscach. [Np. kod TOS został zmodyfikowany przez Zebra Systems, aby współdziałał z komputrami Timex Sinclair 2068. JA] Odpowiednio zmodyfiko­wana tablica skoków umożliwi, mimo tych zmian, poprawne działanie na­szych programów. Pojawienie się no-wej konstrukcji interfejsu iest co praw­da mało prawdopodobne, ale korzy­stanie z tego typu struktur należy do dobrych zwyczajów programisty.

Główne procedury systemu

Spis procedur zawartych w tablicy skoków, ich rzeczywiste adresy, naz­wy, zadania oraz sposób wywołania, zawiera tabela 3. Główną część całe­go systemu stanowią trzy pierwsze podprogramy: putdat, putcom i getblock. Ich znaczenie jest tak duże, a zasób informacji tak szeroki, że im właśnie zostanie poświęcona cała trzecia część tego cyklu. Z nich korzy­stają wszystkie funkcje wyższego po­ziomu, jak wrtmem, rdblock, konw, a nawet savep i loadp. Schemat prze­kazywania danych między tymi pod-programami przedstawia rys. 3.

Procedury niższego poziomu to sendbl i getbl, które już bezpośred­nio, za pomocą nieistotnych dla nas podprogramów przesyłania poszcze­gólnych bajtów, komunikują się ze sta­cją dysków.

TOS A.2. Ogólny algorytm obsługi wywołania RST 8 przez interfejs.

Rys. 3. Graf przepływu da­nych między procedurami systemu TOS interfejsu w komunikacji ze stacją dys­ków. Linia łącząca dwa pro­stokąty na grafie oznacza, że przy kontaktowaniu się ze stacją dana procedura wyż­szego poziomu korzysta z odpowiedniej procedury po­ziomu niższego. Strzałki in­formują o kierunku przesyła­nia danych: do lub ze stacji dysków. Procedury savep i loadp korzystają z wielu procedur niższego poziomu, lecz aby niepotrzebnie nie komplikować rysunku, zo­stało to jedynie zasygnalizo­wane krótkimi strzałkami. Jak widać procedury putdat, putcom oraz getblock są najczęściej wywoływane i stanowią jak gdyby oś całe­go systemu.

 

TABELA 3. Procedury zawarte w tablicy skoków (#0605-#0628)
adresnazwaopis
#0605
#0395
putdatPrzesłanie danych do stacji dysków.
WE: dane w buforze (#2000-#20FF)
A - ilość bajtów do wysłania.
#0608
#0364
putcomWysłanie komendy do stacji dysków.
WE:(mod) - numer komendy; AF, BC, DE, HL, IX, IY - wymagane przy danej komendzie dane wejściowe.
#060B
#03AC
Odebranie komendy lub bufora ze stacji dysków.
WE: bez znaczenia.
WY: (#2130) - długość przesyłanego bloku; NC - zostaly przystanę dane i znajdują się w buforze, C - została przysłana komenda, wtedy: (mod) - numer komendy, w rejestrach są wartości przesłane przez system FDD. W rejestrze A kod błędu, jesli różny od zera, to pod adre­sem #210D-#212C jest komunikat błędu.
#060E
#0495
Wysłanie bloku danych do stacji dysków.
WE: HL - adres początku bloku; (typ), (len) - typ i długość tego bloku.
WY: Z - OK, NZ - bląd przesłania; przechowane wartości rejestrów BC, DE i HL.
#0611
#04D6
Odebranie bloku danych ze stacji dysków.
WE: bez znaczenia.
WY: Z - OK, NZ - bląd przesłania; dane w buforze (gdy dane), lub pod adresem #2100 (gdy komenda); (typ), (len) - typ i długość przysłanego bloku; przechowane wartości rejestrów BC, DE i HL.
#0614
#0D94
Czytanie rekordu z pliku do bufora interfejsu (najwyżej 256 bajtów).
WE: (chan) - numer kanatu, DE - ilość bajtów do załadowania.
WY: Z - OK, NZ-bląd; A - kod błędu, HL - adres danych, BC - ilość załadowanych bajtów, DE - przechowane.
#0617
#0DBF
rdmemZaładowanie danych z pliku do pamięci. Plik musi być otwarty.
WE: (prolen) - ilosć bajtów do załadowania, (prostr) - adres docelowy danych, (chan) - numer używanego kanału.
WY: Z - OK, NZ-błąd; A - kod błędu; przechowane wartości rejestrów BC, DE i HL.
#061A
#0BS4
wrtmemZapisanie danych z pamięci do pliku. Plik musi być otwarty.
WE: (prolon) - ilośc bajtów do wysłania, (prostr) - adres danych, (chan) - numer używanego kanału.
WY: Z - OK, NZ - bląd; A - kod błędu; przechowane wartości rejestrów BC, DE i HL.
#061D
#031D
cbasWywołanie podprogramu z ROM-u ZX Spectrum.
WE: adres procedury do wywołania, w rejestrach potrzebne wartości. Sposób użycia:
	CALL	cbas
	DEFW	zx_add	;adres procedury
#0620
#0A61
savepZapisanie programu lub danych na dysku.
WE: nazwa w buforze (zakończona CHR$(0)); A' - długość nazwy plus jeden; A - typ bloku (0 - BASIC; 1, 2 - DATA; 3 - CODE); BC - długosć; DE - adres początku; HL - numer linii startowej, jeśli jest to program. Gdy HL=0, program nie uruchamia się.
WY: (#2102) - kod błędu, 0 - OK; przechowane wartości HL, DE, BC i AF.
#0623
#0CC1
loadpOdczytanie programu lub danych z dysku.
WE: nazwa w buforze (zakończona CHR$(0)); B - długość nazwy plus jeden; (filetyp) - typ odczytywanego pliku; (filelen) - jego dlugość, (start) - adres docelowy.
WY: Z - 0K, NZ - błąd; A - kod błędu.
#0626
#0688
konwTryb pracy konwersacyjnej. W trybie tym stacja dysków steruje wydrukiem komunikatów na ekranie, na przykład wydrukiem katalogu dyskietki. Wywołuje się po uprzednim wysłaniu komendy do stacji dysków.
Inne przydatne procedury zawarte w ROM-ie interfejsu
#0015Test klawiatury.
WY: A - kod wciśniętego klawisza (zawsze duża litera).
#0033Wydruk znaku o kodzie podanym w rejestrze A. To samo co RST 16.
#03D8pr_errWydruk ciągu znaków na ekranie. Używany jest kanał "S" i wyłączone pytanie "scroll?".
WE: HL - adres tekstu; B - długość tekstu, jeśli H parzyste; H nieparzyste, to drukowane są 33 znaki. Niezależnie od zawartości rejestru B, procedura kończy wydruk po napotkaniu kodu CHR$(0).
#0603Uaktywnienie standardowego ROM-u ZX Spectrum wraz z włączeniem przerwań maskowalnych INT.
#0604To samo, ale bez włączania przerwań.
#066DPrzeniesienie tekstu do bufora i zakończenie znacznikiem końca CHR$(0).
WE: DE - adres tekstu (najczęściej nazwy pliku}, BC - jego długość.
WY: A, B - długość nazwy ze znacznikiem, HL - adres następnego znaku po znaczniku, DE - adres następnego bajtu po tekście.

Procedury dyskowe

Najprostszymi w użyciu i najbardziej chyba użytecznymi procedurami ob­sługi dysku są savep i loadp. Są one dokładnymi odpowiednikami instrukcji SAVE i LOAD znanych z BASIC-a. Potrzebne dane wejściowe opisano w odpowiednich rubrykach tabeli 1. Naj­ważniejszym parametrem jest nazwa pliku: powinna ona znajdować się w buforze interfejsu (adres #2000) i być zakończona kodem CHR$(0). Znacz­nik ten jest ważny, gdyż określa dłu­gość nazwy pliku. Rejestr A' powinien zawierać długość nazwy wraz z koń­cowym zerem, ale jest to jedynie infor­macja, jaką część bufora należy prze­słać do stacji dysków. Wartość ta może być z powodzeniem większa - po prostu razem z nazwą przesłana zostanie jeszcze część bufora nie za­wierająca żadnej użytecznej informa­cji. Najczęstszym zastosowaniem pro­cedury savep jest zapisanie bloku typu CODE na dyskietce. Oto przykładowy podprogram wykonujący sekwencję SAVE *"dane.cod"CODE 50000,100:

PRZKD1	LD	DE,NAZWA	;adres nazwy pliku
	LD	BC,KON-NAZWA	;jej długość
	CALL	#066D		;przeniesienie nazwy do	bufora	
	EX	AF,AF'		;długość nazwy +1 do A'	
	LD	A,3		;typ bloku; CODE	
	LD	DE,50000	;adres bloku	
	LD	BC,100		;jego długość.	
	CALL	SAVEP		;zapis na dyskietce	
	RET
NAZWA	DEFM	"DANE.COD"	;nazwa pliku
KON				;etykieta potrzebna do obliczenia długości nazwy

Nazwę najprościej umieszcza się w buforze za pomocą gotowego podprogramu, znajdującego się w ROM-ie in­terfejsu pod adresem #066D. Opis jego działania znajduje się w tabeli 2. W przypadku napotkania na dyskietce pliku o takiej samej nazwie co zapisy­wany, procedura savep testuje zawar­tość zmiennej systemowej TOS-u o adresie #2134. Jeśli zawiera ona zero, użytkownik pytany jest o zgodę na zapisanie nowego pliku w miejsce starego. W przeciwnym przypadku zo­stanie to wykonane bez pytania.

Zarówno przy zapisie jak i odczycie danych z dyskietki wyróżniane są (do­kładnie jak w przypadku taśmy) cztery typy bloków, oznaczane kolejnymi cyf­rami:
0 - program w BASIC-u,
1 - tablica liczb,
2 - tablica znaków,
3 - blok binarny.

Typ bloku jest ważny nie tylko jako dana wejściowa opisywanej procedu­ry, ale znajduje swoje odzwierciedle­nie również w zapisie na dyskietce, co zostanie dokładniej opisane w jednej z dalszych części cyklu. O ile zapisywa­nie programu w języku BASIC z pozio­mu asemblera jest trochę bez sensu (w dodatku trzeba samodzielnie po­brać i przeliczyć zawartości zmien­nych PRÓG i E_LINE), o tyle czyn­ność odwrotna jest czasem przydat­na i może być wykonana przy pomocy loadp:

PRZKD2	LD	DE,NAZWA
	LD	BC,KON-NAZWA
	CALL	#066D		;nazwa do bufora
	LD	HL,FILETYP
	LD	A,0
	LD	(FILETYP),A	;typ bloku - BASIC
	CALL	LOADP		;nagranie do pamięci
	LD	HL,#210D	;adres komunikatu błędu
	CALL	NZ,PR_ERR	;gdy błąd - komunikat
NAZWA	DEFM	"PROGRAM.BAS"	;nazwa pliku (programu)
KON

Procedura loadp sama zadba o ustawienie odpowiednich zmiennych systemowych, do tego stopnia, że pro­gram samostartujący sam się urucho­mi po powrocie do BASIC-a. Jeśli zmienna systemowa TOS-u o adresie #2138 będzie miała wartość różną od zera, to nagrywany w powyższy spo­sób program zostanie dołączony do istniejącego w pamięci, w taki sposób, w jaki robi to instrukcja BASIC-a MERGE. Uwaga: twórcy systemu zupełnie zapomnieli o zmiennej systemowej RAMTOP, w wyniku czego dłuższe programy bez przeszkód ładują się poza przeznaczony do siebie obszar i niszczą stos, jeśli jest on ustawiony zbyt nisko - z łatwym do przewidze­nia skutkiem. Jest to jedno z poważ­niejszych niedociągnięć TOS-u.

Przy pomocy procedury loadp moż­na nagrywać również bloki kodu. Oto podprogram odczytujący plik utworzo­ny w przykładzie pierwszym.

PRZKD3	LD	DE,NAZWA
	LD	BC,KON-NAZWA
	CALL	#066D		;nazwa do bufora
	LD	HL,FILETYP	;patrz tabela 3
	LD	(HL),3		;typ bloku, CODE 
	LD	HL,100		;jego długość
	LD	(FILELEN),HL
	LD	HL,50000	;adres docelowy bloku
	LD	(START),HL
	CALL	LOADP		;nagranie bloku
	LD	HL,#2100	;dalej jak poprzednio
	CALL	NZ,PR_ERR
	RET
NAZWA	DEFM	"DANE.COD"
KON

Rezygnując z użycia tablicy skoków można powyższy podprogram trochę skrócić. Wykorzystuje się fakt, że loadp odwołuje się do danych wejściowych (czyli zmiennych systemowych FILE­TYP, FILELEN i START - patrz tabe­la 1) używając rejestru indekso­wego IX, ustawiwszy go wpierw na ad­res zmiennej FILETYP. Możemy więc wstawić do IX dowolny inny adres (pod którym będą umieszczone po­trzebne informacje) i wskoczyć do pro­cedury w odpowiednim miejscu. Po­przedni przykład po modyfikacji:

PRZKD4	LD	DE,NAZWA	;adres nazwy pliku
	LD	BC,KON-NAZWA	;jej długość
	CALL	#066D		;nazwa do bufora,
	LD	IX,DANE		;w IX adres opisu bloku
	CALL	#0CC5		;nagranie bloku,
	OR	A		;czy był błąd ?
	LD	HL,#210D	;adres komunikatu błędu
	CALL	NZ,PR_ERR	;gdy błąd - komunikat
	RET
DANE	DEFB 3			;typ bloku, CODE,
	DEFW	100,50000	;długośc i adres bloku,
NAZWA	DEFM	"DANE.COD"	;nazwa pliku
KON

W przypadku, gdy podana przez nas długość bloku jest mniejsza od rzeczywistej, do pamięci zostanie wczytane tylko tyle bajtów, ile sobie życzymy. Chcąc wczytać cały plik, nie znając jego rozmiarów, wystarczy ustawić największą możliwą długość, czyli 0 (równoznaczne w tym wypadku 65536). Adres równy 0 powoduje zała­dowanie bloku w to miejsce, z które­go był zapisany. Nawet z poziomu BA­SIC-a, o czym mało kto wie, instrukcja LOAD *"dane.cod"CODE 0,50 spowo-duje wczytanie połowy naszego dyżur­nego bloku pod adres 50000, czyli tam skąd był wysłany. Jeśli więc chcemy wykonać LOAD*"dane.cod"CODE, na­leży w powyższym podprogramie zmienić wartość adresu i samą dłu­gość na zera. Tabela 1 podaje wpraw­dzie, że ustawiony znacznik zera ozna­cza poprawne wykonanie procedury loadp, ale jest wyjątek od tej reguły - błąd typu nagrywanego pliku. Bezpiecz­niej jest więc dodatkowo sprawdzić roz­kazem OR A, czy w rejestrze A jest zero, które na pewno oznacza brak błędu.

Uwaga: tych wszystkich, którzy nie czytali pierwszej części cyklu, a nie­cierpliwie spróbowali uruchomić jeden z powyższych przykładów informuję, że komputer "zresetował" się, ponie­waż należy najpierw uaktywnić pa­mięć interfejsu. Dowolny z podanych podprogramów można wywołać na­stępująco:

FILETYP EQU	#214D	;patrz tabela 1
FILELEN	EQU	#214E
START	EQU	#2150
SAVEP	EQU	#0620	;patrz tabela 2
LOADP	EQU	#0623
PR_ERR	EQU	#03D8
	ORG	60000	
	ENT	60000
	CALL	DR_ON	;uaktywnienie interfejsu
	CALL	PRZKD1	;wywołanie przykładu
	JP	#0603	;uaktywnienie standardowego ROM-u i powrót
DR_ON	PUSH	IY	;patrz cz. 1
	LD	IY,0
	RST	8
	POP	IY
	RET
PRZKD1	...		;tutaj jeden z podanych przykładów

Na koniec mały podprogram ładują­cy do samodzielnego przeanalizowa­nia. Nagrywa on dwa bloki kodu i pro­gram w BASIC-u:

PRZKD5	LD	DE,TABELA		
PĘTLA	LD	A,(DE)		
	CP	255		
	RET	Z		
	LD	(FILETYP),A		
	LD	HL,0		
	ID	(FILELEN),HL		
	LD	(START),HL		
	INC	DE		
	LD	BC,12		
	CALL	#066D		
	PUSH	DE		
	CALL	LOADP		
	LD	HL,#210D		
	OR	A		
	CALL	NZ,PR_ERR		
	POP	DE		
	JR	PĘTLA		
TABELA	DEFB	3		
	DEFM	"NAZWA1  .COD"	; 12 bajtów !!	
	DEFB	3		
	DEFM	"NAZWA2  .COD"	i 12 bajtów !!	
	DEFB	0
	DEFM	"NAZWA   .BAS"	; 12 bajtów !!	
	DEFB	255

Za miesiąc trzecia część cyklu, a w niej: dość duża tabela z opisem ko­mend systemu TOS, dokładny opis spo­sobu ich użycia, oraz prawie wszystko o komunikacji interfejsu ze stacją FDD. Po jej przeczytaniu będziesz umiał wywołać z poziomu kodu maszynowego wszystkie instrukcje TOS-u dostępne w BASIC-u, a nawet trochę więcej.



WOJCIECH JABŁOŃSKI

TOS od środka cz. 3

Komunikacja komputer - FDD

W systemie TOS komputer wraz z inter­fejsem tworzą jednostkę nadrzędną. Wy­daje ona polecenia, które są następnie wy­konywane przez stację. Komunikacja opie­ra się na schemacie "pytanie - odpo­wiedź" lub też "polecenie - (wykonanie) - potwierdzenie". Trzeba pamiętać, że niezależnie od zleconego stacji zadania, komputer powinien czekać na potwierdze­nie jego wykonania.

Jednostka nadrzędna komunikuje się ze stacją za pomocą systemu komend, zaś dane przekazuje za pośrednictwem bufora. Bufor danych, analogiczny do istniejącego w interfejsie, znajduje się również w stacji dysków. Gdy wykonywana jest komenda wymagającą danych wejściowych (np. na­zwy pliku), to muszą się one znajdować właśnie w buforze stacji. Jeśli czytałeś dru­gą część cyklu, to wiesz, jak je tam prze­nieść: należy umieścić nazwę w buforze in­terfejsu i przesłać ją procedurą putcom. Następnym krokiem jest wysłanie komen­dy. Po jej wykonaniu stacja dysków przysy­ła z powrotem dane do bufora, ale tylko wtedy, kiedy są one potrzebne. Na koniec przysyłana jest ze stacji komenda (nazy­wana w przeze mnie komendą powrotną) zawierająca szereg informacji, między in­nymi o poprawności wykonania polecenia. Lepsze zrozumienie opisanego wyżej me­chanizmu komunikowania się komputera i FDD umożliwi widoczny poniżej algorytm (o przedstawionym w nim trybie pracy kon-wersacyjnej - trochę dalej).

Spis komend systemu oraz ich parame­trów wejściowych i wyjściowych zawiera tabela 4. Dzięki niej można łatwo zrealizo­wać każde polecenie TOS-u korzystając z następującego schematu:

  1. Znajdujący się w pierwszej kolumnie tabeli numer rozkazu wpisujemy do zmien­ nej systemowej mod.
  2. Jeśli dana komenda wymaga prze­słania jakiś danych, to umieszczamy je w buforze i wysyłamy procedurą putdat. Przypomina nam o tym wyraz "tak" umiesz­ czony w trzeciej kolumnie tabeli.
  3. Przed posłaniem komendy należy umieszczamy w rejestrach odpowiednie dane wejściowe wyszczególnione w kolu­ mnie czwartej.
  4. Wysyłamy komendę CALL PUTCOM. Pobieramy komendę powrotną CALL GETBLOCK lub CALL KONW. Kolumna piąta tabeli informuje, gdzie zastosować pracę konwersacyjną i kiedy należy spo­ dziewać się przysłania danych do bufora.
  5. Jeśli wszystko przebiegło poprawnie, w rejestrach lub w buforze znajdują się po­dane w kolumnie szóstej dane powrotne.

Przykłady

Najprostsza sesja komunikacyjna składa się z wysłania komendy (putcom), a nastę­pnie odebrania komendy powrotnej (get-block). W ten sposób realizuje się na przy­kład CLOSE#* lub DRAW*:

DRAW	LD	A,9		;numer komendy
	LD	(MOD),A		;umieszczamy w zmiennej MOD
	CALL	PUTCOM		;wysłanie komendy
	CALL	GETBLOCK	;odebranie komendy powrotnej
	RET

Etykieta MOD ma wartość #2100 - patrz opis zmiennych systemowych interfejsu w pierwszej części cyklu.

Gdy zachodzi potrzeba przesłania doda­tkowych danych, umieszczamy je w bufo­rze i wysyłamy (putdat) przed komendą. Przykładem takich poleceń może być OPEN#*, GOTO* lub zapisanie sektora na dysku. Oto GOTO*:

GOTO	LD	DE,NAZWA	;adres nazwy podkatalogu
	LD	BC,KON-NAZWA	;długość nazwy
	CALL	#066D		;przeniesienie do bufora
	CALL	PUTDAT		;wysłanie bufora do FDD
	LD	A,7		;numer komendy GOTO*
	LD	(MOD),A		;
	XOR	A		;A=0 - nazwa to podkatalog
	CALL	PUTCOM		;wysłanie komendy
	CALL	GETBLOCK	;odebranie komendy powrotnej
	RET			;powrót z podprogramu
NAZWA	DEFM	"katalog"	;nazwa podkatalogu
KON				;to tylko etykieta

Podprogram ten może być również wy­korzystany do zmiany napędu: należy jedy­nie zamienić rozkaz XOR A na LD A,1 (dla­czego - patrz tabela 4) i zamienić nazwę podkatalogu na nazwę napędu.

Po wykonaniu komend takich jak odczyt sektora, pliku lub pobranie wykazu infor­macji o otwartym kanale, przed przysła­niem komendy powrotnej stacja transmitu­je wymagane dane. Odbioru zarówno za­wartości bufora jak i komendy powrotnej dokonujemy przy pomocy procedury get-block. Oto przykładowy program odczytu­jący zerowy sektor z czwartej ścieżki dys­kietki:

SEKTOR	LD	A,27		;numer komendy	
	LD	(MOD),A		;w zmiennej MOD	
	LD	C,0		;napęd A	
	LD	D,4		;numer ścieżki	
	LD	E,0		;numer sektora	
	CALL	PUTCOM		;wyslanie komendy	
DWA	CALL	GETBLOCK	;odebranie bufora	
	JR	NC,DWA		;i komendy powrotnej	
	RET

Zwróć uwagę na pętlę JR NC,DWA zapew­niającą odebranie kolejno bufora i komen­dy powrotnej (jeśli nie wiesz jak - patrz ta­bela 4, opis procedury getblock). Taka konstrukcja ma podstawową zaletę: nieza­leżnie od tego, czy zostanie przysłany bu­for, czy nie (a nie zostanie on przysłany, je­śli wystąpi błąd w odczycie dyskietki), cały podprogram zostanie wykonany prawidło­wo. Ponadto działa ona poprawnie przy wykonywaniu komend prostych typu DRAW*, co jest ułatwieniem przy pisaniu uniwersalnej procedury komunikacyjnej.

Jeśli chcemy wykonać komendę wyma­gającą podania dwóch nazw (czyli LET, MOVE lub FORMAT), wysyłany bufor po­winien je zawierać. Należy je umieścić w takiej kolejności, jak w składni BASIC-a, oddzielając i kończąc kodem CHRS(0).

Praca konwersacyjna

Praca konwersacyjną polega na tym, że stacja przysyła szereg komunikatów do wydrukowania (nie chodzi tu o komunikaty błędów) lub oczekuje wciśnięcia jakiegoś klawisza. Wykonywane są w ten sposób takie instrukcje jak CAT*, LIST* czy FORMAT*. Dzięki istnieniu specjalnej procedu­ry konw obsługa trybu pracy konwersacyj-nej jest bardzo prosta. Poniższy podpro­gram wykonuje dokładnie to samo, co wy­wołane z poziomu BASIC-a polecenie CAT*:

CAT	LD	A,11		;jak poprzednio
	LD	(MOD),A		;
	CALL	PUTCOM		;wysłanie komendy
	CALL	KONW		;wywołanie procedury pracy konwersacyjnej
	RET			;i powrót

Taka konstrukcja w większości zastoso­wań wystarcza, jednak czasem potrzebna jest wiedza o sposobie organizacji pracy konwersacyjnej. Ujmując rzecz skrótowo: komenda powrotna zawiera w zmiennej mod swój kod. Jest to jedna z czterech możliwych liczb od 128 do 131, których znaczenie opisane jest w tabeli 5. W przy­padku opisanych wcześniej komend pros­tych jest to zawsze kod 128 wskazujący, że stacja wykonała polecenie (niekoniecz­nie poprawnie). Gdy liczba zawarta w zmiennej mod jest większa, oznacza to żą­danie wykonania jednej z opisanych w ta­beli 5 czynności. Po ich zrealizowaniu (lub nie) należy wysłać komendę potwierdzają­cą (w tym miejscu warto jeszcze raz spoj­rzeć na algorytm) o specjalnym kodzie 145 i można odebrać znowu bufor i komendę powrotną. I tak aż do skutku, czyli przysła­nia przez stację kodu 128. Jako przykład warto przeanalizować podprogram usta­wiający parametry transmisji kanału B in­terfejsu szeregowego.

FORMAT	LD	DE,CH_TXT	;adres nazwy kanału
	LD	BC,5		;jej długość
	CALL	#066D		;umieszczenie w buforze
	CALL	PUTDAT		;wysłanie do stacji
	LD	A,21		;kod komendy FORMAT*
	LD	(MOD),A		;
	LD	HL,DANE		;adres opisu parametrów formatowania interfejsu
KONWER	PUSH	HL		;przechowanie na stosie
	CALL	PUTCOM		;wysłanie komendy
DWA	CALL	GETBLOCK	;odebranie bufora
	JR	NC,dwa		;i komendy powrotnej
	POP	HL		;odtworzenie adresu danych,
	LD	A,(MOD)		;
	CP	128		;koniec pracy konwersacyjnej?
	RET	Z		;
	LD	A,145		;kod potwierdzenia
	LD	(MOD),A		;
	LD	A,(HL)		;pobranie parametru
	INC	HL		;zwiekazenie adresu danych
	JR	KONWER		;powtórzenie
				;
CH_TXT	DEFM	":CH_B"		;nazwa kanału
DANE	DEFB	0,"B"		;Text or bytes? B
	DEFB	0,"N"		;XON/XOFF? N
	DEFB	0,"Y"		;Input with wait? Y
	DEFB	0,"O"		;Baud rate? O
	DEFB	0,"N"		;parity? N
	DEFB	0,"A"		;Stop bits? A
	DEFB	0,"D"		;Bita/char? D

Podczas pracy konwersacyjnej stacja dysków może dowolnie długo czekać na potwierdzenie — nie ma limitów czasowych. Widoczną na algorytmie pętlę pracy konwersacyjnej można też w każdej chwili przerwać, czyli zrezygnować np. z końcówki przysyłanego katalogu dyskietki. W tym celu zamiast kodu potwierdzenia 145 wystarczy podać jakikolwiek kod komendy z tabeli 4. Stacja zinterpretuje to jako chęć zaniechania wykonywania poprzedniej instrukcji TOS-u i zacznie wykonywanie nowej.

Należy również dodać, że procedura konw jest napisana w sposób umożliwiający zastosowanie jej zamiast procedury getblock. W miejsce sekwencji:

DWA	CALL	GETBLOCK
	JR	NC,DWA
można z powodzeniem napisać CALL KONW.
TOS A.2. Algorytm wykonania jednej z instrukcji TOS.

Rys. 4. Algorytm przedstawia schemat konstrukcji podprogramu wykonującego jedną z poda­nych w tabeli 4 instrukcję TOS-u.

Obsługa błędów

Wysłanie komendy polega na przesłaniu 13 bajtów zaczynających się od adresu #2100. Jest tam jej numer oraz kolejno wartości wszystkich rejestrów. Tak samo jest zbudowana komenda powrotna. Jednak w przypadku wystąpienia błędu, jest ona o 32 bajty dłuższa — stacja przysyła dodatkowo komunikat o napotkanych nieprawidłowościach. Rejestr A, który w przypadku prawidłowego wykonania polecenia ma wartość 0, zawiera teraz kod błędu (w przypadku wywołania procedury konw zawartość rejestru A jest niszczona i kod błędu znajduje się jedynie pod adresem #2102). Oto uniwersalny podprogram drukujący na ekranie treść komunikatu błędu w przypadku jego wystąpienia:

BLAD	LD	A,(12102)	;kod błędu
	OR	A		;O.K.?
	RET	Z		;powrót jeśli nie ma błędu
	LD	HL,#21OD	;adres przysłanego komunikatu
	CALL	PR_ERR		;jego wydruk
	RET

Można go wywołać każdorazowo po wykonaniu przez stację polecenia, czyli zarówno po pobraniu komendy zwrotnej jak i po wykonaniu procedury konw.

Tradycyjnie już przypominam o konieczności uaktywnienia ROM-u interfejsu, przed próbą uruchomienia podanych programów przykładowych. O tym jak to się robi, możesz przeczytać w którejkolwiek z poprzednich części cyklu.

TABELA 4. Komendy powrotne
kodkomendadane wyjściowekoddane wejściowe
128Koniec wykonywania komendy.Opisane w tabeli 5.
129Żądanie wydruku komunikatu.Tekst komunikatu znajduje się w bufo­rze (adres #2000) i jest zakończony kodem chr(O).145brak Kod 145 Jest potwier­dzaniem chęci konty­nuacji wykonywania komendy.
130Żądanie wydruku komunikatu i ocze­kiwania na naciś­nięcie ENTER.145A=13 - kod klawisza ENTER.
131Żądanie wydruku komunikatu i ocze­kiwania na naciś­nięcie klawisza.145A - kod naciśniętego klawisza.

 

TABELA 5. Opis komend systemu
kodkomendabuf.dane wejścioweodb.dane powrotne
0Otwarcie
kanału
OPEN#*nr;...
takA - nr kanału (1-16):
1-4 kanały szybkie
5-16 kanały wolne
D - tryb pracy kanału:
D=0 - append
D=1 - input
D=2 - output
D=3 - random
E - tryb dostępu danych:
E=0 - rekordowy, w IX dł. rekordu
E=1 - dostęp swobodny
norm(#2102) lub A - kod błędu.
A=0 - OK,
A>0 - pod adresem (#210D-#212C) komunikat błędu.
1CLOSE#*nrnieA - numer kanałunorm
2Tworzenie
pliku lub
katalogu:
DIM*"nazwa"
takA=0 nazwa oznacza plik lub podkatalog,
A=1 tylko plik (używa­ne przy SAVE).
norm
3Wydruk stosu
podkatalogów
LIST*
niebrakkonw(#2102) - kod błędu
(#2104) lub B - liczba elementów na stosie podprogramów (1-8)
(#2107) lub L - numer bieżącego napędu.
(#2108) lub H - numer bieżącego podkatalogu
4Usunięcie pliku
lub pokatalogu:
ERASE*"nzw"
takA=0 - pytanie, czy na pewno usunąć.
A=1 - usuwa bez pytania
konw(#2102) - kod błędu. Jeśli błąd, to pod adresem (#210D-#212C) komunikat błędu.
5Zmiana nazwy
LET*"nl" TO "n2"
tak!Przed wysłaniem bufora powinny się w nim znajdować kolejno stara i nowa nazwa, oddzielone i zakończo­ne kodem CHRS(0).norm(#2102) lub A - kod błędu.
A=0 - OK,
A>0 - pod adresem (#210D-#212C) komunikat błędu.
6MOVE*"nl" TO "n2"tak!norm
7Zmiana pod-katalogu lub napedu: GOTO*"nazwa"takA - informacja, czego dotyczy podana nazwa:
A=0 - podkatalogu,
A=1 - nazwy napędu.
8Wydruk bieżącego podkatalogu.niebrakkonw(#2102) - kod błędu.
(#2107) lub L - numer bieżącego napędu.
(#2108) lub H - numer bieżącego podkatalogu.
9DBAW*niebraknormJak dla komendy nr 0.
10Odłożenie bieżącego podkatalogu na stos.nieUWAGA: Wykonanie tego polecenia nie jest równoznaczne GOSUB*. Trzeba jeszcze wykonać komendę nr 7 (GOTO*).norm
11CAT*niebrakkonwJak dla komendy nr 4.
12CAT*"nazwa"takbrakkonw
13LIST*#nrnieB - numer kanału.konw
14LIST"*niebrakkonw
15Zapis do pliku.takB - numer kanału.
W trybie rekordowym:
DE - numer rekordu (1-65536)
DE=0 i C=0 - kolejny.
Przy dostępie swobodnym:
DE - ilość bajtów do zapisania (1-256).
norm(#2102) lub A - kod błędu.
A=0 - OK,
A>0 - pod adresem (#210D-#212C) komunikat błędu.
16Odczyt z pliku.nieJak wyżej, oraz przy dostępie swobodnym:
DE=0 i C=255 odczyty­wane są kolejne sło­wa tekstu z pliku.
buf.(#2102) lub A - kod błędu.
A=0 - wczytany rekord jest w buforze, DE - długość rekordu.
A>0 - pod adresem (#210D-#212C) komunikat błędu.
17Formatowanie dyskietki.tak!A=0 - 40 ścieżek,
A=1 - 80 ścieżek.
Dane w buforze tak jak dla LET* (komenda 5).
konw(#2102) - kod błędu. Jeśli błąd to pod adresem (#210D-#212C) komunikat błędu.
18Przysłanie informacji o kanałach.niebraknormB - nr wolnego kanału.
19Przysłanle informacji o otwartym kanale.nieA - numer kanału.buf.(#2002) - tryb pracy:
0 - append
1 - input
2 - output
3 - random
(#2004) - tryb dostępu:
0 - rekordowy
1 - dostęp swobodny.
(#2005) - nr kanału.
(#2006-8) - długość pliku (3 bajty!).
(#2009-A) - nr następnego rekordu (elementu).
(#200C) - dl. rekordu.
(#200D-F) - nr bajtu w pliku (liczony od 0).
20Zabezpiecza-nie i ukry-wanie plików ATTR*"nazwa"takA=0 - odbezpieczanie (U)
A=1 - zabezpieczanie (P)
A=2 - uwidacznianie (V)
A=3 - ukrywanie (I)
normJak dla komendy nr 0.
21Formatowanie RS232C.takbrakkonwJak dla komendy nr 4.
22RESTORE#nrnieA - numer kanałunormJak dla komendy nr 0.
23Przysłanie numeru wersji TOS-u.niebrakDla wersji A.2: H=%00010001
- starsze 4 bity - "A"
- młodsze 4 bity - "2"
24Uruchomienie podprogramu w pamięci stacji Timex FDD 3000.nieIY - adres podprogramu do uruchomienia.
A, BC, DE, HL - przekazane do podprogramu.
Wartości rejestrów po wykonaniu podprogramu.
25Przesłanie bloku danych z pamięci stacji do bufora interfejsu.nieA - dl. przysyłanego bloku.
DE - adres bloku w pamięci stacji.
buf.(#2102) lub A - kod błędu.
A=0 - przesłany blok jest w buforze.
A>0 - (#210D-#212C) komunikat błędu.
26Przestanie bloku danych z bufora interfejsu do pamięci stacji.takZ powodu błędu TOS-u trzeba własnoręcznie skonstruować komendę o długości takiej jak przesyłany blok.
(#2105) - adres docelowy w pamięci stacji.
normDE -adres końca przesłanego bloku + 1.
27Wczytanie sektora z dyskietki.nieC - numer napędu,
C=0 napęd A, 1-B itd.
D - numer ścieżki,
E - numer sektora.
Kolejno E=0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9.
buf.(#2102) lub A - kod błędu.
A=0 - wczytany sektor jest w buforze.
A>0 - pod adresem (#210D-#212C) komunikat błędu.
28Nagranie sektora na dyskietcetaknormJak dla komendy nr 0.
29CLOSE*niebraknormJak dla komendy nr 0.
30Żądanie podania adresu funkcji usługowej w stacji dysków.nieA - numer funkcji pomocniczej.normHL - adres funkcji pomocniczej.
31?nie
32?tak
33Komenda równoważna GOSUB*"path'takJak dla komendy nr 7.normJak dla komendy nr 0.

Co dalej?

W następnej części cyklu przedstawię sposób wykorzystania pamięci stacji dys­ków i wykonywania w niej programów. Znajdzie się tam również opis kilku cieka­wych zastosowań interfejsu, w tym sposób prostego rozszerzenia listy instrukcji inter­pretera BASIC-a i samouruchamiające się programy typu CODE. Niecierpliwych infor­muję, że wszystkie niezbędne do zrealizo­wania tych pomysłów informacje zostały już podane i znajdują się w tabelkach, za­mieszczonych w tej części cyklu lub po­przednich.



Wojciech Jabłoński

TOS od środka cz. 4

Cała czwarta część cyklu "Tos bez tajemnic" jest poświęcona dwóm zmiennym systemowym in­terfejsu: jump i finit, dającym programiście bardzo duże możliwości. Lektura tego artykułu da odpo­wiedź na szereg pytań, dotyczących kilku często spotykanych sztuczek programowych, które na pierwszy rzut oka nie powinny udać się na ZX Spec-trum.

W pierwszej części cyklu napisałem, że twórcy TOS-u zosta­wili szereg furtek dla programistów. Zamieszczony tam algo­rytm był z założenia ogólny, nie mógł więc pokazać, jak z nich skorzystać. Na rys. 1 pokazana jest nowa jego wersja, uwzglę­dniająca dwa miejsca, w których możemy zmienić przebieg za­pisanej w ROM-ie interfejsu obsługi polecenia dyskowego.

TOS A.2. Algorytm obsługi RST 8.

Rys. 5. Algorytm pokazujący sposób, w jaki interfejs obsługuje RST 8.

Wśród zmiennych systemowych interfejsu (patrz tabela 1) znajdują się dwie zmienne jump i finit, zawierające kolejno adres procedury powrotu do BASIC-a po wykonaniu polecenia TOS-u i adres procedury obsługi błędu składni. Jak pokazuje to algorytm, obsługę każdego polecenia TOS-u kończy sekwencja: LD HL,(JUMP) : JP (HL) co umożliwia nam, poprzez zmianę zawartości zmiennej syste­mowej jump, uruchomienie innego (własnego) programu przed powrotem, a nawet zamiast powrotu do BASIC-a. Analogiczna sytuacja występuje w przypadku napotkania błędu składni: za­zwyczaj wykonywana jest procedura spod adresu #0082, gdyż taką ma pierwotnie wartość zmienna finit. Jednak poprzez zmianę zawartego w niej adresu można wykonać własny pro­gram rozpoznający i wykonujący nowe, własnoręcznie zdefi­niowane instrukcje języka BASIC.

Programy samostartujące

Jako przykład użycia zmiennej jump warto przeanalizować i uruchomić poniższy programik:

10:	;Programik: ZROBIONE!
20:		ORG	60000
30:		ENT	60000
40:	JUMP	EQU	#213D
50:	CBAS	EQU	#061D
60:	BEEP	EQU	#03B5
70:	PR_ERR	EQU	#03D8
80:	;Instalacja programu:
90:		PUSH	IY		;uaktywnienie interfejsu
100:		LD	IY,0
110:		RST	8
120:		POP	IY
130:	;Nowy adres do zmiennej JUMP:
140:		LD	HL,RUN
150:		LD	(JUMP),HL
160:		JP	#0603		;Koniec instalacji.
170:	;--------------------------------------------	
171:	;Program zasadniczy piszący tekst ZROBIONE!:
180:	RUN	LD	HL,NAPIS	;adres tekstu
190:		CALL	#PR_ERR		;pisz tekst
200:		JP	#06E3		;skok do standardowej procedury powrotu
210:	NAPIS	DEFM	"ZROBIONE!"	;tekst
220:		DEFB	0

Składa się on z dwóch części: instalującej i zasadniczej. Na­leży go skompilować, a następnie uruchomić (w przypadku GENS-a dyrektywą R). Spowoduje to zainstalowanie progra­mu, czyli zmianę wartości zmiennej jump na adres etykiety RUN. Teraz należy wrócić do BASIC-a i sprawdzić jego działa­nie: po wykonaniu każdego polecenia TOS-u komputer napi­sze "ZROBIONE!". Rzecz ta jest co prawda mało efektowna i nieprzydatna, ale to ważny krok w zrozumieniu metod i nauce umiejętności oprogramowywania stacji. Zastosowanie tego mechanizmu umożliwia, w sposób który można śmiało nazwać sztuczką, tworzenie samouruchamiających się programów typu CODE.

Podstawową rzeczą, z której należy sobie zdać sprawę jest fakt, że podczas operacji TOS-u, więc również w czasie zapisu i odczytu z dyskietki interfejs jest aktywny. Polecenie SAVE *"ROM" CODE 0,16384 wcale nie zapisze na dyskietce ROM-u ZX Spectrum, ale widoczny w tej przestrzeni adresowej ROM i RAM interfejsu! Analogicznie wczytanie danych pod ad­res #2100 spowoduje zmodyfikowanie zawartości zmiennych systemowych interfejsu. Łatwo przewidzieć, że takie działanie skończy się zazwyczaj zawieszeniem pracy systemu. Można jednak stworzyć specjalnie spreparowany plik, który po wczy­taniu pod adres #213D spowoduje jedynie zmianę wartości zmiennej jump i kilkunastu pozostałych, które nie mają w trak­cie nagrywania (przypadkowo i po spełnieniu pewnych warun­ków!) żadnego znaczenia. Jeśli założymy przykładowo, że wczytywane jest 100 bajtów, to pierwsze 24 znajdzie się w ob­szarze zmiennych systemowych, a pozostałe 76 (zawierające program do uruchomienia) znajdzie się w wolnym obszarze pa­mięci RAM interfejsu. Teraz zmienna jump zawiera adres tego programu i dzięki opisanemu na początku mechanizmowi zo­stanie on uruchomiony. Oto program, który po wpisaniu i uru­chomieniu stworzy na dysku samostartujący plik o nazwie "START.COD":

10:	;Program tworzący na dyskietce plik
11:	;samostartujący typu CODE.
20:		ORG	60000
30:		ENT	60000
40:	FINIT	EQU	#213B
50:	JUMP	EQU	#213D
60:	RAM	EQU	#2154
70:	SAVEP	EQU	#0620
80:	PR_ERR	EQU	#03D8
90:	;Uaktywnienie interfejsu:
100:		PUSH	IY		;uaktywnienie interfejsu
110:		LD	IY,0
120:		RST	8
130:		POP	IY
140:		;Ustawienie zmiennej jump na adres autostartu
141:		;i przeniesienie w to miejsce programu jego
142:		;obsługi:
150:		LD	HL,#0082
160:		LD	(FINIT),HŁ
170:		LD	HL,RAM
180:		LD	(JUMP),HL
190:		EX	DE,HL
200:		LD	HL,START
210:		LD	BC,KON-START
220:		LDIR
230:		;SAVE*"START.COD" CODE JUMP,KON-START+24
240:		LD	DE,NAZWA
250:		LD	BC,END-NAZWA
260:		CALL	#66D
270:		EX	AF,AF'
280:		LD	A,3
290:		LD	DE,JUMP
300:		LD	BC,KON-START+24
310:		CALL	SAVEP
320:		JP	#603
330:	NAZWA	DEFM	"START.COD"
340:	END
350:	;--------------------------------------------	
351:	;Kod programu samostartujacego.
360:	START	LD	HL,#06E3		;w zmiennej JUMP należy
370:		LD	(JUMP),HL		;umieścić poprzedni adres
380:		LD	HL,NAPIS-START+RAM	;adres tekstu
490:		CALL	PR_ERR			;pisz komunikat
400:		JP	#06E3			;powrot do BASIC-a
410	NAPIS	DEFM	"TU AUTOSTART. WITAJ!"
420	DEFB	0				;tekst
430	KON					;etykieta końca

Większość instrukcji powyższego programu ma jedynie za zadanie zainstalować procedurę i zapisać ją na dysku. Część właściwa znajduje się na jego końcu i tylko ona znajdzie sie w pliku. Po wpisaniu z poziomu BASiC-a polecenia LOAD *"START.COD" CODE, na ekranie pojawi się napis "TU AU­TOSTART! WITAJ!". Nie jest to chwyt w stylu "ZROBIONE!", o czym można łatwo upewnić się, wyłączając przedtem na chwi­lę komputer. Chcąc tworzyć pliki samostartujące powyższą metodą należy pamiętać, że kod w nich zawarty musi być relo-kowalny. Należy również bezwzględnie pamiętać o ustawieniu wartości zmiennej jump na standardową wartość (linie 360 - 370). Aby usunąć wszelkie niejasności dodam, że mimo iż pro­gram "START.COD" uruchomi się sam po nagraniu, to jest to nadal program typu CODE i w żadnym wypadku nie zostanie on samoczynnie uruchomiony przy włączeniu komputera, czyli starcie systemu, nawet gdvby nadać mu nazwę "START".

Zastosowanie powyższej metody pozwala otrzymywać zu­pełnie nowe i nietypowe efekty. Jeden z czytelników nadesłał nam bardzo ładnie zrobiony program do kompresji plików na dysku. Spakowany plik zawiera w swoim wnętrzu procedurę do dekompresji, która uruchamiając się w powyższy sposób wczy­tuje dane do pamięci, jednocześnie je rozpakowując. Jeśli otrzymamy zgodę autora, dołączymy ten program do organizo­wanego ZX-SHAREWARE.

Nowe instrukcje

Podprogram obsługujący nowe instrukcje BASIC-a wygod­nie jest umieścić w pamięci RAM interfejsu, gdyż jest to obszar dość dobrze zabezpieczony przed zmianą zawartości, a nawet niedostępny dla polecenia NEW. Napisanie takiego programu nie jest rzeczą prostą i nawet średnio doświadczonym progra­mistom sprawia trudności. Musi się on składać z dwóch części: analizującej składnię i wykonującej poszczególne polecenia. Ta pierwsza sprawia zazwyczaj najwięcej problemów. Nie dość, że trzeba rozpoznawać, w jakim trybie pracy znajduje się komputer (analizy składni czy wykonywania programu), to jesz­cze stos jest "zaśmiecony" przez pewne adresy, których liczba jest zależna od kodu komendy. ROM interfejsu zawiera dość dobre i dające się wykorzystać mechanizmy służące do anali­zowania składni, za których pomocą można, tworząc specjalną tabelę i niewielki programik obsługujący, zaimplemęntować szereg nowych poleceń o dość nawet skomplikowanej składni. Opis tej metody byłby adresowany do wąskiego grona ludzi, zbyt długi i trudny, aby zamieścić go w Bajtku. Osobom zainte­resowanym tym problemem mogę udzielić informacji kores­pondencyjnie.

Najprostszą metodą dołączenia nowego rozkazu jest wyko­rzystanie nieużywanej instrukcji CAT. Jej zaletą jest fakt, że jej składnia jest sprawdzana i akceptowana przez interpreter, więc nie trzeba się o nią troszczyć. Fakt ten upraszcza znacz­nie program obsługi, co można zobaczyć na poniższym przy­kładzie. Część analizująca składnię to jedynie linie 180 do 220. Po wpisaniu należy go poddać kompilacji, a następnie urucho­mić za pomocą dyrektywy asemblera R.

10:	;Instalacja nowej instrukcji BASIC-a.
20:		ORG	60000
30:		ENT	60000
40:	FINIT	EQU	#213B
50:	MOD	EQU	#2100
60:	PUTCOM	EQU	#0608
70:	GETBLCK	EQU	#060B
80:	;Czesc instalująca:
90:		PUSH	IY
100:		LD	IY,0
110:		RST	8
120:		POP	IY
130:	;W zmiennej FINIT nowy adres:
140:		LD	HL,RUN
150:		LD	(FINIT),HL
160:		JP	#0603		;koniec instalacji.
170:	;--------------------------------------------	
171:	;Program obsługi nowej instrukcji CAT:
180:	RUN	LD	HL,(23645)	;adres interpretowanego rozkazu,
190:		DEC	HL
200:		LD	A,(HL)		;kod tego rozkazu
210:		CP	207		;czy to jest CAT?
220:		JP	NZ,#0082	;jeśli nie - powrót
230:		POP	HL		;"czyszczenie" stosu
240:		LD	A,11		;kod komendy CAT*
250:		LD	(MOD),A
260:	PETLA0	CALL	PUTCOM		;wysłanie komendy.
270:	;Obsługa trybu pracy konwersacyjnej:
280:	PETLA1	CALL	GETBLCK		;odebranie bufora 
290:		JR	NC,PETLA1	;i komendy zwrotnej 
300:		LD	A,(MOD)		;kod komendy zwrotnej 
310:		CP	#80		;koniec? 
320:		JP	Z,#0603		;tak - powrót 
330:		XOR	A		;skrócenie tekstu do 
340:		LD	(#2014),A	;14 znaków 
350:		CALL	#06D5		;pisz tekst z bufora 
360:		LD	A,#91		;kod kontynuacji
370:		LD	(MOD),A
380:		JR	PETLA0		;zamkniecie pętli

Część instalująca umieszcza w zmiennej finit adres równy wartości etykiety RUN. Po powrocie do BASIC-a można wpi­sać polecenie CAT i zamiast zazwyczaj spotykanego komuni­katu "lnvalid stream" będzie widoczny katalog dyskietki. Dla odróżnienia od tradycyjnego, jest on troszeczkę zmodyfikowa­ny. Powyższy program jest umieszczony pod adresem 60000, co jest dowodem, że może się on znajdować w dowolnym miej­scu pamięci. Jednak gdy umieści się go w pamięci interfejsu, można wtedy zapisać na dyskietce (jako jeden blok) fragment pamięci od adresu #213B (adres zmiennej finit), aż po koniec programu. By powtórnie zainstalować tę nową instrukcję wy­starczy wczytać powstały plik do komputera. Na analogicznej zasadzie działa zamieszczony w Bajtku 2/92 program EXX.COD. Ciekawscy mogą na jego przykładzie obejrzeć jak można w prosty sposób napisać analizę składni dla trzech no­wych, zupełnie nietypowych rozkazów.

Za miesiąc ostatnia część cyklu, a w niej zapowiadane infor­macje o zapisie na dyskietce, które w tym artykule w żaden sposób nie mogły się zmieścić.



Wojciech Jabłoński

TOS od środka cz. 5

Artykuł ten kończy cykl poświęcony systemowi Timex FDD 3000, w którym staraliśmy się opisać, w sposób możliwie najbardziej przystępny i nie przeładowując tekstów zbędnymi informacjami, wszystkie najprzydatniejsze mechanizmy programowe. W tej części znajdziesz wzmiankę o strukturze dyskietek TOS-u, oraz obiecane wcześniej procedury do obsługi pamięci stacji.

Na dyskietce

Na początek - garść informacji na temat sposobu zapamiętywania danych na dys­kietce. Standardowy dysk składa się z dwóch stron, zwanych A i B. Na obudowach dyskietek 3-calowych widnieją odpowiednie literki i zmiana strony polega na wyjęciu dys­ku z napędu i włożeniu go odwrotnie. W na­pędach 5,25" z dwiema głowicami sprawa jest równie prosta - wystarczy użyć przełą­cznika, w który powinna być zaopatrzona stacja. W napędach 80-ścieżkowych nie trzeba nic przełączać, gdyż TOS umożliwia formatowanie na 640 kB używając obu stron.

Powierzchnia każdej strony dyskietki jest podzielona na ścieżki (ang. track), których jest w zależności od rodzaju napędu, 40 lub 80. Na każdej z nich umieszczone jest szes­naście sektorów. Łatwo obliczyć, że ścieżka zawiera 4 kB, a sektor - 256 B. Sektory są pogrupowane czwórkami w tzw. jednostki alokacyjne, ponumerowane od zera. Na każ­dej ścieżce jest ich cztery. W formacie 640 kB jednostka alokacyjna zawiera 4 kB, czyli dokładnie całą ścieżkę. Z prostego wyli­czenia otrzymujemy pojemność zwykłej dys­kietki: 2 strony * 40 ścieżek * 4 kB = 2 * 160 kB = 320 kB, a gęstej: 2 strony * 80 ścieżek * 4 kB = 640 kB. Wszystkie ścieżki i sektory są numerowane od zera.

Ścieżki o numerach od 0 do 3 zawierają system operacyjny (16 kB), ładujący się au­tomatycznie do pamięci stacji po jej włącze­niu lub zresetowaniu. Na ścieżce nr 4 zapisa­ny jest katalog dysku i jest ona najciekawsza z punktu widzenia programisty. Obszar ten podzielony jest na 128 pól (rekordów) po 32 bajty. Każde pole opisuje cały plik lub czasa­mi tylko jego część. Znaczenie poszczegól­nych bajtów jest wyjaśnione na rysunku 6a. Ponieważ pojedynczy rekord katalogu opisu­je maksimum 16 jednostek alokacyjnych, dla plików dłuższych niż 16 kB (lub 64 kB w for­macie gęstym) tworzona jest większa licz­ba takich rekordów. Katalog jest zawarty w jednostkach alokacji o numerach od 0 ao 3 (w formacie gęstym - tylko nr 0). Struktura katalogu narzuca maksymalną liczbę plików, jakie mogą się znajdować na dyskietce, do 127.

Jeśli stworzymy na dysku podkatalog, in­formacja o tym zostanie również umieszczo­na w katalogu dysku. Opis rekordu podkata­logu widoczny jest na rys. 6b. Na początku ścieżki katalogowej znajduje się zawsze na­zwa dysku, zapisana w ten sam sposób jak rekord podkatalogu.

Rysunek 7 przedstawia sposób numeracji sektorów i bloków alokacji. Blokiem alokacji nazywamy podstawowy obszar rozliczenio­wy pamięci dyskietki. Jego długość definiuje najmniejszą przestrzeń jaką może zajmować plik. Jeśli zapiszemy na zwykłym napędzie 100 bajtów, to i tak zostanie dla nich zare­zerwowany obszar 1 kB. W napędzie gę­stym, gdzie jednostka alokacyjna ma 4 kB, marnotrawstwo z tego wynikające jest jesz­cze większe. Na rzadkiej dyskietce każda strona numerowana jest oddzielnie. Napęd gęsty numeruje naprzemiennie obie strony dyskietki. Zerowy blok alokacji znajduje się zawsze na początku ścieżki katalogowej.

W katalogu nie ma żadnej informacji o ty­pach istniejących na dyskietce plików. Sy­stem TOS, tak samo jak w przypadku zapisu na taśmie, rozróżnia cztery ich rodzaje. O tym, czy to jest program, czy też rysunek, decyduje nagłówek umieszczany na począt­ku pliku. Rysunek 3 pokazuje jego strukturę we wszystkich czterech przypadkach. Oczy­wiste jest więc, że obrazek zapisany na dys­kietce zajmuje nie 6912, a 6917 bajtów.

[Sposób organizacji dyskietki jest w zasadzie identyczny z systemem CP/M 2.2. Dyskietki rzadkie można bez większego problemu odczytywać pod CP/M, po odpowiednim skonfigurowaniu parametrów i przeplotu. Pliki z podkatalogów dyskietki TOS pojawią się w obszarach USER CP/M (tylko 15 podkatalogów można utworzyć pod TOS). Zapis plików pod CP/M jest też możliwy, ale nieprawidłowo zapisze sie dokładna długość pliku (w zakresie ostatnich 256 bajtów), która została inaczej rozwiązana w TOS i CP/M. W każdym bądź razie, korzystając z pośrednictwa rzadkiej dyskietki, przenieślismy dużą ilość plików z TOS na dyskietki 820 kB, z których można odczytywać programy używając uproszczonej wersji TOS - programu TOSQ1.COM pod CP/M. JA]



01 . . . . . . 89 . BCDEF10 . . . . . . . . . . . . . .1F
KNEOLRRA
K - numer podkatalogu, w jakim jest plik;
N - 8 bajtów nazwy (wielkie litery);
E - 3 bajty rozszerzenia; dodatkowo:
bit 7 El - plik ukryty
bit 7 E2 - plik zabezpieczony przed kasowanien;
O - numer kolejnego rekordu przy opisie długiego pliku;
L - liczba bajtów w ostatnim sektorze pliku;
R - liczba 128-bajtgwych rekordów zajętych przez plik;
A - 16 bajtów opisujących przypisanie jednostek
alokacyjnych.
Rys. 6a. Rekord pliku.


01 . . . . . . 89 A BCDEF10 . . . . . . . . . . . . . .1F
KNE000000D00
K - numer podkatalogu, w jakim jest ten podkatalog (FF dla nazwy dysku);
N - 8 bajtów nazwy (wielkie litery);
E - 3 bajty rozszerzenia (DIR); dodatkowo:
bit 7 El - katalog ukryty
bit 7 E2 - katalog zabezpieczony przed kasowanien;
D - bajt określający numer przypisany podkatalogowi (0 dla nazwy dysku).
Rys. 6b. Rekord podkatalogu.
TOS A.2. Numeracja ścieżek dla zwykiego i gęstego dysku.

Rys. 7. Numeracja ścieżek dla a) zwykiego dysku (320 kB), b) dysku gęstego (640 kB).


TOS A.2. Struktura nagłówków plików.

Rys. 8. Struktura nagłówków plików: a) program w języku BASIC, b) tablica liczbowa, c) tablica znakowa, d) typ CODE.

Pamięć stacji

W spisie komend systemu, zamieszczo­nym w trzeciej części cyklu, znajdują się trzy komendy (o kodach 24, 25 i 26) pomocne przy obsłudze pamięci stacji Timex FDD 3000. Pierwsza z nich uruchamia program w stacji dysków, zaś dwie następne odpowiedzialne są za przesyłanie danych między nią a kom­puterem. Niestety transmitowanie do pamię­ci stacji nie działa z powodu błędu programi­stów TOS-u. W tabeli zamieszczona była wskazówka, jak można sobie z tym poradzić, zbyt oględna jednak, by można ją było łatwo wykorzystać. Cieszymy się jednak, że nie zajęliśmy się wcześniej tym tematem, gdyż dosłownie wczoraj pojawił się zupełnie nowy pomysł obejścia tego błędu.

Nowa metoda jest efektywniejsza i dwa razy szybsza od dotychczas stosowanej. W maksymalnym skrócie wygląda następująco: blok danych należy przesłać do bufora stacji za pomocą procedury putdat, a następnie uruchomić podprogram:

	LDIR
	RET
znajdujący się szczęśliwym trafem w pamię­ci stacji pod adresem #1879. Umożliwia on przeniesienie danych z bufora stacji w dowol­ne miejsce jej pamięci. W widocznej obok ramce zamieszczone są trzy w pełni reloko-walne procedury, które ułatwią Wam dostęp do tych 48 ukrytych kilobajtów. Zastosowa­nie podprogramów jest oczywiste, zaś spo­sób użycia pokazuje poniższy prosty przy­kład:
; Przykładowy program pokazujacy sposób użycia
; procedur ZX_FDD i FDD_ZX.
	ORG	60000
; Zapamiętanie ekranu w pamięci stacji dysków.
ZAPAM	CALL	DR_ON
	LD	HL,16384
	LD	DE,20000
	LD	BC,6912
	CALL	ZX_FDD
	JP	#0603
; Odtworzenie zawartości ekranu.
ODTW	CALL	DR_ON
	LD	HL,20000
	LD	DE,16384
	LD	BC,6912
	CALL	FDD_ZX
	JP	#0603
DR_ON	PUSH	IY
	LD	IY,0
	RST	8
	POP	IY
	RET
; Tu należy umieścić procedury FDD_ZX i ZX_FDD.
PUTCOM	EQU	#0608
KONW	EQU	#0688
MOD	EQU	#2100
PUTDAT	EQU	#0605
GETBLCK	EQU	#060B
BUFDAT	EQU	#2000
FDDBUF	EQU	#3E22

; FDD3000 --> ZX SPECTRUM
; WE : JAK W LDIR
FDD_ZX	LD	A,B
	OR	C
	RET	Z
	PUSH	HL
	PUSH	BC
	PUSH	DE
	EX	DE,HL
	LD	A,#19
	LD	(MOD),A
	XOR	A
	CALL	PUTCOM
Pl	CALL	GETBLCK
	JR	NZ,P1
	POP	DE
	POP	HL
	LD	BC,256
	XOR	A
	SBC	HL,BC
	JR	NC,P2
	INC	H
	LD	B,H
	LD	C,L
	LD	L,0
P2	PUSH	HL
	LD	HL,BUFDAT
	LDIR
	POP	BC		
	POP	HL
	INC	H
	JR	FDD_ZX

; SPECTRUM --> FDD3000
; WE: JAK W LDIR
ZX_FDD	LD	A,B	
	OR	C	
	RET	Z	
	PUSH	HL	
	LD	H,B	
	LD	L,C
	LD	BC,256	
	XOR	A	
	SBC	HL,BC	
	JR	NC,P3	
	INC	H	
	LD	B,H	
	LD	C,L	
	LD	HL,0	
P3	EX	(SP),HL	
	PUSH	DE	
	PUSH	BC	
	LD	DE,BUFDAT	
	LDIR
	PUSH	HL	
	CALL	PUTDAT	
	POP	HL	
	POP	BC	
	POP	DE	
	PUSH	HL	
	LD	HL,FDDBUF	
	PUSH	IY	
	LD	IY,#1879	
	LD	A,24	
	LD	(#2100),A	
	CALL	PUTCOM	
	POP	IY	
	INC	D	
	POP	HL	
	POP	BC	
	JR	ZX_FDD
	
;URUCHOMIENIE PROGRAMU W STACJI DYSKÓW	
; WE: IY-ADRES STARTU	
RUNFDD	LD	A,24	
	LD	(#2100),A
	CALL	PUTCOM	
	CALL	KONW	
	RET

Po skompilowaniu powstają w pamięci dwa programy: USR 60000 zapamiętuje w pamięci stacji dysków wygląd ekranu kom­putera, zaś USR 60018 odtwarza go. Jak na RAM-dysk jest to zbyt wolne, ale do prezen­tacji rysunków już się nadaje.

I to by było na tyle

W kończącym się właśnie pięcioczęścio-wym cyklu artykułów została zawarta prakty­cznie cała wiedza potrzebna programiście chcącemu wykorzystywać TOS z poziomu kodu maszynowego. Może on napisać włas­ny loader w języku maszynowym, a także przerobić grę na wersję pracującą z dys­kiem. Wszystko jest kwestią wprawy i do­świadczenia. Można (cóż za trywialny po­mysł) wykorzystać stację jako inteligentny bufor do drukarki. Albo urządzić wojny rdze­niowe. Właściwie nic nie stoi na przeszko­dzie, aby napisać program zmieniający stac­ję w programowy koprocesor matematyczny do Spectruma. Warto umieć programować i jest to naprawdę wielka przygoda. Spróbuj i ty, a nie tylko gry, gry i gry...

Wojciech Jabłoński, Jacek Trojański


Oryginalny tekst ukazał się w czasopiśmie Bajtek. Został zeskanowany w listopadzie 2001 i w takiej postaci oczekiwał na lepsze czasy. Konwersja do postaci tekstowej (HTML) została wykonana w kwietniu 2010. Wszystkie odcinki zostały umieszczone w jednym pliku HTML. Zostały dodane komentarze. Dla większej przejrzystości została zmieniona numeracja tablic i rysunków. Treść programów została sprawdzona, wszystkie adresy szesnstastkowe zapisane są za pomocą czterech cyfr (w wyjątkiem rysunków). Ponieważ otrzymałem kilka próśb o przetłumaczenie na angielski, prawdopodobnie powstanie również wersja anglojęzyczna, po zakończeniu prac edycyjnych.

Tekst publikuję w dobrej wierze, w celu archiwizacji i edukacji, bez zgody, wiedzy i znajomości woli autorów oraz wydawcy Bajtka.

Jarek Adamski


Odniesienie do ZXVGS

Pliki utworzone w systemie TOS A.2 można używać również pod ZXVGS. Minimalna zgodność składni BASIC (w postaci obsługi LOAD* i SAVE*) jest w rozszerzeniu BZX.RZX - jeśli programy nie używają innych instrukcji BASIC, nazwa programu powinna mieć rozszerzenie BZX. Obsługę szerszej składni ma zapewnić rozszerzenie BA2.RZX, nie będzie ono jednak realizować operacji dyskowych niskiego poziomu (z uaktywnieniem interfejsu). Dla plików CODE zalecane jest rozszerzenie CZX, a dla tablic DZX.

Przy przegrywaniu plików TOS na inny system w celu korzystania z nich pod ZXVGS (również TOSQ1.COM pod CP/M), należy zwracać uwagę na konwersję nagłówków plików z 5 i 7-bajtowych na 9-bajtowe.



Jarek Adamski
See also TOS A.2 on http://8bit.yarek.pl.