Każdego użytkownika mikrokomputera, jeśli tylko miał możliwość porównania komfortu pracy komputera wyposażonego w stację dysków i komputera z magnetofonem jako zewnętrzną pamięcią masową, nie trzeba przekonywać o zaletach pierwszego rozwiązania. Mikrokomputer szkolny Elwro 800-2 Junior ma możliwość pracy zarówno z magnetofonem, jak i ze stacją dysków elastycznych 5.25" -- dwa napędy (ang. Floppy Disk Drive, w skrócie FDD) po 720kB!
Junior produkowany jest w dwóch wersjach: nauczycielskiej i uczniowskiej. Zarówno pierwsza, jak i druga wersja mają możliwość współpracy ze stacją dysków. Standardowo jednak (ze względu na znaczny koszt stacji) tylko komputer nauczycielski może bezpośrednio z nią współpracować. Komputery uczniowskie natomiast, mogą korzystać ze stacji poprzez sieć komputerową Junet.
Podstawowe parametry pamięci dyskowej mikrokomputera Elwro 800 Junior:
1. Dwie strony dysku: 0 i 1.
2. Każda strona ma 80 ścieżek.
3. Każda ścieżka posiada 9 sektorów.
4. Każdy sektor ma długość 512 bajtów.
5. Tzw. rekord CP/M jest umowną jednostką długości zbioru. Jeden
rekord to 128 bajtów. Jeden sektor zawiera 4 rekordy.
Sektor jest najmniejszą porcją informacji, którą fizycznie można odczytać lub zapisać na dysku. Na jednej ścieżce mieści się więc dokładnie 9×512 = 4608 bajtów, czyli 4.5kB informacji. Na jednej stronie mamy wobec tego 80×9=720 sektorów, czyli 80×4.5kB = 360kB, a na całym dysku 2×720 = 1440 sektorów, czyli 2×360kB = 720kB. Jest to pojemność maksymalna dysku. W rzeczywistości do dyspozycji użytkownika pozostaje mniej ze względu na wykorzystanie niektórych obszarów dysku na informacje systemowe, katalog oraz zaokrąglenia długości plików w górę do wielokrotności 2kB.
Dyskowy system operacyjny Juniora wymienia informacje ze stacją w porcjach zwanych blokami. [Ewentualnie jednostkami alokacji albo klastrami. JA] Jeden blok to 2kB. Blok zajmuje na dysku fizycznie 4 sektory. Na pojedynczej ścieżce mieści się wobec tego 21/4 bloku. Jeden blok może zajmować miejsce w całości na jednej ścieżce, jak również może być "rozrzucony" na dwóch ścieżkach (i na dwóch stronach!) dysku. Odpowiednich przeliczeń, gdzie fizycznie na dysku znajduje się określony blok, dokonuje w sposób niewidoczny dla użytkownika -- system operacyjny w czasie zapisu lub odczytu informacji.
Oczywiście użytkownik komputera nie musi pamiętać, w których blokach zapisany jest jego program czy dane. To także załatwia za niego system operacyjny. Do wczytania lub zapisu programu lub danych wystarcza nazwa (pliku, zbioru).
Dysk podzielony jest na kilka zarezerwowanych obszarów:
1. Na ścieżce 0 (numeracja ścieżek od 0 do 79), na stronach 0
i 1 zapisywany jest system operacyjny CP/J.
2. Na ścieżce 1 na stronie 0 oraz w sektorach od 1 do 7 (numeracja
sektorów na ścieżce od 1 do 9) na ścieżce 1 na stronie 1 (16 sektorów czyli
4 bloki) zapisany jest tzw. katalog dysku (ang. directory). 3. Od
sektora 8 na ścieżce 1 na stronie 1 rozpoczyna się obszar przeznaczony
na dane użytkownika.
Każdy zbiór użytkownika opisany jest w katalogu dysku w tzw. tablicach
FCB (ang. File Control Błock). [W CP/M tablicą FCB nazywamy blok
36 bajtów służący do obsługi otwartego pliku -- ponieważ pierwsze 32 bajty
FCB odpowiadają zapisowi pozycji w katalogu, tutaj dla uproszczenia pozycje
katalogu nazwano również FCB. JA] Struktura FCB opisana jest dokładnie
w instrukcji komputera. Pojedynczy zbiór użytkownika może być opisany przez
jedną lub więcej tablic FCB (zależy to od wielkości danego zbioru). Pojedyncza
tablica FCB składa się z 32 bajtów. W skrócie jej struktura jest następująca:
1. Bajt nr 0 -- numer użytkownika lub #E5, jeśli zbiór jest skasowany.
Umożliwia identyfikację zbiorów poszczególnych użytkowników sieci Junet.
[#E5 jest negatywem kodu #1A (^Z), oznaczającego w CP/M koniec zbioru
tekstowego. Podczas formatowania sektory dysku są wypełniane bajtami #E5,
również katalog, stąd po sformatowaniu wszystkie pozycje katalogu są
uznawane za wolne. Normalnie w CP/M numer użytkownika jest z przedziału
0..15, czasem 0..31. Pliki zapisane przez użytkowników 32..63 Junet mogą
być niewidoczne pod CP/M. JA]
2. Bajty 1..11 -- nazwa zbioru (8 bajtów) z rozszerzeniem (3
bajty) (razem 11 bajtów).
3. Bajt 12 -- numer tablicy FCB opisującej dany zbiór. Pierwsza
tablica FCB zbioru zawiera tutaj nr 0. Jeśli zbiór jest dłuższy niż 16kB,
wówczas opisany jest także w kolejnych tablicach FCB. Bajt 12
w następnych tablicach zawiera wówczas kolejne liczby 1, 2 itd. Zbiór odługości
16..32kB opisany jest w dwóch tablicach FCB, 32..48kB w trzech. Dłuższe
zbiory raczej nie występują ze względu na ograniczenie pamięci operacyjnej
komputera Junior. [Niemniej można je utworzyć np. programem dBase II. JA]
4. Bajty 13..14 są zarezerwowane. [Niekiedy bajt 14 może
zawierać wartość #81..#FF, która informuje ile z bajtów zapisanych
w ostatnim rekordzie należy jeszcze do pliku (odpowiednio 1..127).
Dzięki temu można określić długość pliku z dokładnością do jednego bajtu.
Do długości pliku wyliczonej z ilości rekordów należy dodać zawartość
bajtu 14 traktowanego jako liczba ze znakiem (-127..0). JA]
5. Bajt 15 podaje długość zbioru (lub fragmentu zbioru) opisanego
daną tablicą FCB w rekordach.
6. Bajty 16.. 31 zawierają numery bloków, w których zapisany
jest zbiór (lub fragment zbioru) opisany daną tablicą FCB. Każdy numer
bloku zajmuje dwa bajty w tablicy. Jedna tablica FCB może więc opisywać
zbiór (lub fragment zbioru) o wielkości maksimum 8 bloków, czyli 16kB.
Katalog dysku zajmuje 8kB (4 bloki -- numery od 0 do 3). Może więc pomieścić 256 tablic FCB. Jeżeli każdy zbiór opisany byłby jedną tablicą FCB i miałby długość maksymalnie 2kB, wówczas wykorzystując tylko 256×2kB = 512kB nominalnej pojemności dysku można go całkowicie wypełnić. Najkrótszy nawet zbiór (1 bajt) zajmuje na dysku 1 blok (2kB) i jedną tablicę FCB. Należy mieć to na uwadze i -- w miarę możliwości oczywiście -- nie "zaśmiecać" dysku bardzo krótkimi zbiorami. [Wynika stąd przeciętna wielkość pliku równa 2.74kB. (Pojemność dyskietki 720-9-8-1=702 kB podzielona przez ilość pozycji katalogu.) JA]
Mikrokomputer Junior ma dwa tryby pracy: ZX Spectrum i CP/J. W trybie ZX Spectrum ze stacji dysków może korzystać bezpośrednio jedynie komputer, który wyposażony jest w płytkę tzw. kontrolera (sterownika) stacji dysków (ang. Floppy Disc Controller, w skrócie FDC), i do którego jest ona podłączona (zwykle nauczycielski). Odczyt i zapis zbiorów dokonuje się wówczas przy pomocy poleceń o składni podobnej jak przy współpracy z magnetofonem tzn. LOAD, MERGE, SAVE. Po słowach tych należy jedynie umieścić gwiazdkę *, a nazwa zbioru nie może mieć więcej jak 8 znaków. [Podobnie zresztą jak w bardziej popularnym TOS A.2. JA]
Dodając po nazwie CODE informujemy komputer, że chodzi o zbiór bajtów, DATA -- zmienne i tablice (jak w przypadku magnetofonu). Na podstawie tych informacji system operacyjny w trybie ZX Spectrum dokonuje zapisu lub odczytu zbioru określonego typu (z odpowiednim rozszerzeniem nazwy). W tablicach FCB zbiory typu ZX Spectrum posiadają rozszerzenia nazwy PRG, COD, ARR, STR.
Pierwszy blok zbiorów typu ZX Spectrum zawiera zawsze na początku znane użytkownikom komputera ZX Spectrum nagłówki o identycznej jak w przypadku magnetofonu długości (17 bajtów) i strukturze. [Nie ma typu bloków ani sum kontrolnych, jak to jest w plikach .TAP. W ZXVGS do obsługi plików z takimi nagłówkami przeznaczone jest rezydentne rozszerzenie PRG.RZX, które również automatycznie dodaje odpowiednie rozszerzenia nazw plików. JA]
Jeżeli zapisujemy na dysk w trybie ZX Spectrum zbiór np. bajtów o długości dokładnie 2kB, to zostanie on fizycznie zapisany w dwóch blokach (bo 17 bajtów nagłówka + 2kB danych to już więcej niż 2kB). W pierwszym bloku zostanie zapisany najpierw nagłówek (17 bajtów), a następnie 2048-17=2031 bajtów danych. W drugim bloku umieszczone zostanie pozostałe 17 bajtów danych.
Normalnie użytkownik komputera nie ma możliwości "podglądania" informacji zapisanych np. na ścieżkach systemowych lub w katalogu dysku. Może jedynie zapisywać, czytać lub kasować zbiory o określonej nazwie, lub też czytać nazwy i niektóre parametry zbiorów zapisane w katalogu dysku (polecenia DIR -- w trybie ZX Spectrum i CP/J -- czy XDIR w trybie CP/J). Jednakże pisząc odpowiednie procedury w kodzie maszynowym można czytać lub zapisywać dowolne obszary na dyskach Juniora, a także na dyskach zapisanych w innych formatach (np. 360kB IBM)!
Chcąc wykonywać nietypowe operacje dyskowe należy poznać strukturę pamięci operacyjnej Juniora.
Komputer wyposażony jest w 64kB pamięci RAM oraz 24kB ROM.
Pamięć RAM zajmuje oczywiście pełny obszar przestrzeni adresowej procesora Z80. Pamięć ROM podzielona jest na dwa bloki: 16kB głównej pamięci ROM zajmującej adresy od #0000 do #3FFF, oraz dodatkowy ROM 8kB w obszarze od #0000 do #1FFF.
Jak więc widać w obszarze adresowym #0000..#1FFF egzystują jednocześnie RAM i oba ROMy, a w obszarze #2000..#3FFF -- RAM i ROM podstawowy. Aby uniknąć kolizji jednoczesnego dostępu do różnych pamięci, Junior wyposażony jest w odpowiedni mechanizm dynamicznego przełączania różnych banków (stron) pamięci operacyjnej. Oczywiście normalnie użytkownik nie musi wiedzieć, który z bloków pamięci jest aktywny. Znowu robi to za niego system operacyjny. Dla dalszych rozważań należy jednak wiedzieć kiedy i które obszary pamięci są aktywne.
W trybie ZX Spectrum struktura pamięci jest następująca:
Główna pamięć RAM #4000..#FFFF (jak w ZX Spectrum). Obszar RAM #2000..#3FFF wykorzystywany jest przez system operacyjny (niewidocznie dla użytkownika) przy operacjach ze stacją dysków oraz operacjach sieciowych. Natomiast RAM od #0000 do #1FFF w trybie ZX Spectrum nie jest wykorzystany.
Główny ROM 16kB zawiera zmodyfikowany system operacyjny ZX Spectrum. Zmienione są np. komunikaty błędów, wzorce znaków, procedury obsługi drukarki, procedury obsługi przerwań (całkowicie zmieniono procedurę przerwania niemaskowalnego, rozszerzono procedurę obsługi przerwania maskowalnego). [Przerwanie niemaskowalne może być generowane poprzez odebranie bajtu z Junet. JA] Wykorzystano też ROM w obszarze #386E..#3CFF, który w ZX Spectrum był nie używany. Zasadnicze procedury obsługi magnetofonu są identyczne jak w ZX Spectrum. Jedynie na ich początku system sprawdza, czy chodzi w danym momencie o transmisję w sieci Junet, na dysk czy też na magnetofon. Zawartość głównego ROMu Juniora można odczytywać przez np. PRINT PEEK adres oraz zdekodować korzystając z dowolnego deasemblera ZX Spectrum.
ROM dodatkowy 8kB zawiera przede wszystkim procedury obsługi stacji dysków, procedury obsługi sieci komputerowej, oraz inne jak np. sprawdzanie konfiguracji komputera (ze stacją czy bez), odczyt swojego numeru komputera (każdy Junior ma zakodowany swój numer), wydruk na ekranie komunikatu początkowego po włączeniu zasilania Juniora lub po instrukcji NEW, itd. Normalnie ROM ten jest niedostępny dla użytkownika tzn. nie można go odczytać np. przez PRINT PEEK adres.
W trybie CP/J aktywna jest cała pamięć RAM 64kB. W operacjach dyskowych
system korzysta z procedur zawartych w ROM dodatkowym.
W Juniorze do przełączania bloków pamięci zarezerwowano jeden z możliwych
adresów urządzeń wejścia-wyjścia. Wykonując instrukcję OUT (#F7),A,
dokonywać można przełączania różnych bloków pamięci ROM i RAM. O tym, który
blok pamięci ma zostać uaktywniony decyduje zawartość akumulatora A. Umiejętne
wykorzystanie instrukcji OUT (#F7),A umożliwia także inne "sztuczki"
jak np. możliwość sprawdzenia numeru komputera czy zmiana położenia ekranu
w pamięci. [Według schematu, z bajtu zapisywanego do portu #F7 zapamiętywane
są tylko bity 4..7, a bity 0..3 są ignorowane. JA]
Zawartości akumulatora i odpowiadające im warianty pamięci zawiera tabela
I. [Poszczególne warianty są tworzone przez odpowiednio zaprogramowany
EPROM 256B, stąd nieco niepasujący tryb CP/J. Jedynie bit 5 przełącza ekran
niezależnie od zaprogramowania tego EPROM. JA]
Mechanizm przełączania bloków pamięci
(#F7) | #0000..#1FFF | #2000..#3FFF | #4000..#FFFF | ekran | tryb |
---|---|---|---|---|---|
#08 (8) | ROM podst. | ROM podst. | RAM | ZX Spectrum (#4000) | ZX Spectrum |
#28 (40) | ROM podst. | ROM podst. | CP/J (#E000) | ||
#48 (72) | ROM dodatk. | RAM | ZX Spectrum (#4000) | ||
#68 (104) | ROM dodatk. | RAM | CP/J (#E000) | ||
#88 (136) | ROM podst. | RAM | ZX Spectrum (#4000) | ||
#A8 (168) | RAM | RAM | CP/J (#E000) | CP/J | |
#C8 (200) | ROM dodatk. | ROM podst. | ZX Spectrum (#4000) | ||
#E8 (232) | ROM dodatk. | ROM podst. | CP/J (#E000) | ||
#10 (16) | umożliwia odczyt numeru komputera |
Krótki program w asemblerze Z80 umożliwiający odczytanie numeru komputera
pokazano na wydruku 1. Po zasemblowaniu i umieszczeniu kodu wynikowego
w pamięci, wykonując PRINT USR 60000 otrzymamy na ekranie numer
komputera, na którym pracujemy. [Numer komputera odczytywany jest portem
#FFFE, po ustawieniu bitu 4 w porcie #F7. Stan tego bitu nie wpływa na
działanie pozostałych funkcji komputera. JA]
Wydruk 1. Procedura odczytu numeru komputera 0010 ; 0020 ; ;"Odczyt numeru komputera" 0060 0070 ORG 60000 ;adres wywołania 0080 ; 0090 START DI ;zablokuj przerwania 0100 LD A,10H ;przygotowanie do odczytu 0110 OUT (0F7H),A ; numeru 0120 LD A,0FFH 0130 IN A,(0FEH) ;A:= numer komputera 0140 LD B,0 0150 CPL ;negacja akumulatora 0160 AND 3FH ;weź tylko bity 0..5 0170 LD C,A ;C - numer komputera 0180 LD A,8 ;ROM pod., RAM 16..64kB 0190 OUT (0F7H),A ;przełącz pamięć 0200 EI ;odblokuj przerwania 0210 RET ;powrót - BC nr komp. 0220 END
Niestety nie jest możliwe włączenie pełnej pamięci RAM z obrazem ZX Spectrum tzn. pod adresem #4000. Można natomiast wykonując w ZX Spectrum BASIC OUT 247,40 przełączyć ekran ZX Spectrum na CP/J (oczywiście dotyczy to jedynie wyświetlania obrazu -- wszystkie procedury obsługi ekranu np. PRINT, CLS, itd., będą dalej działać tylko na ekranie ZX Spectrum).
Przełączanie bloków pamięci można oczywiście wykonać także innymi instrukcjami OUT procesora Z80, pamiętając jedynie, aby na mniej znaczącej części adresowej umieścić wartość #F7. Możliwe jest również wykonanie w ZX Spectrum BASIC instrukcji OUT 247,argument, jednakże należy w tym przypadku zwrócić baczną uwagę na argument operacji OUT! W zasadzie możliwe jest jedynie wykonanie OUT 247,40 (zmiana ekranu) i OUT 247,168 (pełny RAM), przy czym uprzednio należy umieścić w odpowiednim miejscu RAM procedurę, która na końcu będzie posiadała instrukcję (oczywiście już w kodzie wewnętrznym Z80) OUT 247,8. Po jej wykonaniu nastąpi powrót do sytuacji wyjściowej (ROM podstawowy, RAM #4000..#FFFF). W wydruku 2 przedstawiono krótki program w asemblerze Z80, który umożliwia kopiowanie pamięci RAM #2000..#3FFF do RAM #8000..#9FFF w niecodzienny sposób przez OUT 247,168. Program po asemblacji należy uruchomić instrukcją (np.) RANDOMIZE USR 60000. Po uruchomieniu nastąpi wpisanie do pamięci RAM od adresu #1E7A odpowiedniego kodu. Procedura OUT w ZX Spectrum BASIC znajduje się dokładnie pod adresem #1E7F i w tym właśnie miejscu w pamięci RAM znajdzie się początek procedury kopiującej.
Program tam umieszczony nie ulega zniszczeniu nawet po wykonaniu sprzętowego kasowania!
Uwaga!
Nieostrożne wykonanie OUT 247 (szczególnie w ZX Spectrum BASIC, lecz również w kodzie wewnętrznym) z reguły powoduje unieruchomienie komputera!
Wydruk 2. Procedura kopiowania RAM przez OUT 247,168 0010 ; 0020 ; ;"kopiowanie RAM 2000 3FFF do RAM 0030 ; ;" 8000..9FFF" 0040 ; ;"kopiowanie przez OUT 247,168 w 0050 ; ; ZX Spectrum BASIC" 0060 ; 0070 ORG 60000 ;adres wywołania 60000 0080 ; 0090 DLUG EQU 20H ;długość bloku kodu 0100 KOPY3 EQU 1E7AH ;adres przeznaczenia bloku kodu 0110 ; 0120 KOPY1 DI ;zablokuj przerwania 0130 LD HL.KOPY2 ;HL:=adres źródła danych 0140 LD DE,KOPY3 ;DE:=adres przeznaczenia danych 0150 LD BC,DLUG ;BC:=długość bloku 0160 LD A,0A8H ;włącz pełny RAM 0170 OUT (0F7H),A ; 0180 LDIR ;przeładuj pamięć 0190 LD A 0C9H ;A:=kod RET i wpisz do 0200 LD (38H),A ; adresu INT oraz 0210 LD (66H),A ; NMI 0220 LD A,8 ;ROM pod., RAM 16..64kB 0230 OUT (0F7H),A ;przełącz pamięć 0240 EI ;odblokuj przerwania 0250 RET ;powrót do ZX Spectrum BASIC 0260 ; 0270 KOPY2 LD A,8 ;A - przygotow. do przełącz. 0280 EI ;odblokuj przerwania 0290 OUT (0F7H),A ;wróć do BASIC (ROM pod adres 1E7F) 0300 ; 0310 S1E7F DI ;tu wejście po OUT 247,168 (BASIC) 0320 PUSH HL ;zabezpiecz rejestry 0330 PUSH DE ; 0340 PUSH BC ; 0350 LD BC,2000H ;BC:=dł. bloku 0360 LD HL,2000H ;HL:=adres bloku 0370 LD DE,8000H ;DE:=adres przeznaczenia 0380 LDIR ;przeładuj RAM 2000..3FFFh do ; 8000..9FFF hex 0390 POP BC ;odtwórz rejestry 0400 POP DE ; 0410 POP HL ; 0420 JR KOPY2 ;skok do wyjścia 0430 END
Korzystając z mechanizmu przełączania bloków pamięci można przepisać odpowiednią procedurą w kodzie maszynowym zawartość ROMu dodatkowego lub też RAMu z obszarów #0000..#3FFF do RAMu w innym miejscu i następnie np. analizować procedury zawarte w ROMie dodatkowym.
Procedura w asemblerze Z80 pokazana na wydruku 3 przepisuje ROM dodatkowy do wolnej pamięci RAM.
Wydruk 3. Procedura kopiowania ROM dod. - RAM 8000..9FFFh 0000 ORG 60000 ;adres proc. 60000 dec. 0010 ; 0020 ADR0 EQU 32768 ;adres przeznacz danych 0030 ADR1 EQU 0 ;adres źródła danych 0040 ; 0050 COPY DI ;zablokuj przerwania 0060 LD A 48H ;akumulator :=48 hex 0070 OUT (OF7H),A ;włącz ROM dodatk. 0080 LD HL,ADR1 ;HL:= adres źródła danych 0090 LD DE,ADR0 ;DE:= adres przeznaczenia 0100 LD BC,2000H ;BC:= długość bloku danych 0110 LDIR ;przepisz blok dł.8192 dec 0120 LD A,8 ;akumulator :=8 0130 OUT (0F7H),A ;ROM podst.,RAM 16..64kB 0140 EI ;odblokuj przerwania 0150 RET ;powrót 0160 ; 0170 END
Po wpisaniu powyższego programu za pomocą dowolnego asemblera dla ZX Spectrum, po wykonaniu asemblacji i umieszczeniu kodu wynikowego pod adresem 60000 uruchomić go można przez (np.) RANDOMIZE USR 60000. W obszarze 32768..40960 (#8000..#9FFF) znajdzie się kopia ROMu dodatkowego, którego zawartość można teraz analizować. Oczywiście program można umieścić w innym miejscu pamięci (inny argument dyrektywy ORG). Podobnie kopia ROMu także może być umieszczona w innym miejscu (ADR0). Podstawiając za ADR1 zamiast #0000 wartość #2000 możemy w ten sam sposób skopiować RAM z obszaru #2000..#3FFF.
W obszarze #2000..#3FFF pamięci RAM w trybie ZX Spectrum znajdują się bufory oraz zmienne systemowe używane przy operacjach dyskowych i sieciowych. Niewykorzystany (w trybie ZX Spectrum) obszar RAM #0000.. #1FFF można wykorzystać jako ramdysk. Także obszar #2000..#3FFF można wykorzystać jako ramdysk, jeśli nie używa się pamięci dyskowej i sieci komputerowej. Można do tego wykorzystać analogiczne procedury jak powyżej, jedynie w linii 60 należy zmienić argument instrukcji LD A,#A8 (pełny RAM), a także ustawić odpowiednie adresy źródła i przeznaczenia danych oraz potrzebną długość bloku. Można w ten sposób np. zapamiętywać i wywoływać ekran nie zajmując przy tym głównej pamięci RAM.
Wszystkie systemowe operacje dyskowe Juniora w trybie ZX Spectrum wykorzystują obszar RAM #2000..#3FFF. Wykaz niektórych zmiennych i bloków tego obszaru zawiera tabela II. Ponadto w zmiennej systemowej niewykorzystanej w ZX Spectrum pod adresem 23678 (#5CB0) bit 0 ustawiony informuje interpreter Junior BASIC o operacji dyskowej, a bit 1 o operacji sieciowej.
Adres(y) | Opis |
---|---|
#2007 | Adres odczytu lub zapisu jednego sektora. |
#2009..#2011 | Kody instrukcji i dane dla układu scalonego sterownika stacji NEC µPD 765. |
#2012..#201A | Kody błędów sterownika dysków. |
#2080..#28FF | Bufor, do którego wczytywane są bloki katalogu dysku (bloki 0..3). W danym momencie wpisany tam może być oczywiście tylko jeden blok (2kB). |
#29EC..#29FC | Nagłówek zbioru typu ZX Spectrum. |
#29FD..#32FC | Bufor, do którego wczytywane są z dysku (lub z którego zapisywane są na dysk) poszczególne bloki danych pliku. W pierwszych blokach plików typu ZX Spectrum pierwsze 17 bajtów zawiera nagłówek zbioru. |
#3209 | Numer aktywnej stacji dysków. |
#3800..#3EAF | Bufor, w którym system umieszcza przygotowany do wydruku na ekranie katalog dysku po wykonaniu polecenia DIR (w trybie ZX Spectrum). |
Niektóre z wielu procedur zawartych w ROMie dodatkowym (8kB), które mogą być wykorzystane przez użytkowników we własnych programach w kodzie wewnętrznym Z80 zamieszczone są w tabeli III.
Adres | Opis |
---|---|
#01ED | Włączenie stacji. Numer napędu w rej. C (#01EE - numer w akumulatorze). Numer napędu zapamiętywany jest w rej. IY. |
#01F8 | Wyłączenie napędu. Nie wymaga parametrów, gdyż numer stacji pamiętany jest w rejestrze IY. W czasie od włączenia (proc. #01ED) do wyłączenia stacji (proc. #01F8) nie wolno używać procedury #01ED. |
#099A | Elementarna procedura komunikacji systemu ze scalo nym sterownikiem stacji NEC µPD 765. Po umieszczeniu w odpowiednim miejscu RAM kodu instrukcji oraz danych dla sterownika stacji (normalnie pod adresem #2009), wpisaniu w dwóch poprzednich komórkach (normalnie #2007) adresu zapisu lub odczytu sektora, należy w parze rejestrów BC podać adres (standardowo #2007) ww. parametrów i wywołać procedurę przez CALL #099A. W komórkach pamięci od #2011..#201A wpisywane są kody dotyczące statusu sterownika (najważniejsza jest zawartość #201A). |
#0ACD | Podstawowa procedura zapisu-odczytu jednego bloku (2kB). Przed jej użyciem należy umieścić na stosie procesora kod operacji np. ładowania bloku -- LD BC,0004: PUSH BC (zapis bloku -- LD BC,0006: PUSH BC), następnie w parze rejestrów BC należy umieścić numer bloku, a w parze DE adres zapisu-odczytu bloku. |
"Pośrednikiem" pomiędzy mikrokomputerem Junior a pamięcią dyskową jest układ scalonego sterownika stacji dysków elastycznych NEC µPD 765 (odpowiednik INTEL 8272) -- układ ten jest również stosowany w komputerach IBM PC XT/AT. Opis tego układu został zamieszczony w numerze 1/1988 czasopisma Mikroklan. Układ µPD 765 może pracować w dwóch trybach -- tzw. DMA (bezpośredni zapis-odczyt pamięci z pominięciem procesora komputera) oraz NON-DMA (procesor zapisuje i odczytuje dane ze sterownika). W Juniorze wybrano drugi tryb. [Bo tryb DMA wymaga użycia dodatkowych układów scalonych, albo co najmniej zmiany działania przerwań. JA]
Procesor Z80 komunikuje się ze sterownikiem za pośrednictwem trzech portów: #EF, #EE oraz #F1.
Przez OUT (#F1),A (A musi posiadać odpowiednią zawartość), procesor włącza i wyłącza jeden z dwóch napędów stacji (stacja Juniora jest podwójna). [W zasadzie dotyczy to silników, gdyż wybóru napędu dokonuje się programując kontroler. Zapamiętywane są bity 0..3, a 4..7 ignorowane. Bity 0 i 1 włączają silniki napędów, bit 2 jest podłączony do wejścia TC kontrolera, a bit 3 po zanegowaniu do wejścia RESET. JA]
Przez port #EF procesor wysyła do sterownika (OUT) kody poleceń i dane oraz odbiera dane odczytane z dysku (IN) i bajty statusu.
Przez port #EE procesor odczytuje (IN) ze sterownika jego główny rejestr stanu. W rejestrze stanu najważniejszy jest stan bitu 7, który informuje (po uaktywnieniu jednego z dwóch napędów przez OUT (#F1),A o gotowości sterownika i stacji do działania.
Wydruki 4 i 5 przedstawiają dwa przykłady procedur zapisu-odczytu pamięci dyskowej Juniora. Pierwsza z nich (wydruk 4) pozwala na odczytanie lub zapisanie dowolnego bloku na dysku (umożliwia np. bezpośredni odczyt katalogu dysku, odczyt pierwszych bloków typu ZX Spectrum, w których -- pierwsze 17 bajtów -- zawarty jest nagłówek zbioru), a także czytanie w trybie ZX Spectrum zawartości zbiorów typu "nie-Spectrum" (CP/J).
Wydruk 4. Procedura odczytu-zapisu jednego bloku 0010 ; 0020 ; 0030 ORG 60000 ;adres wywoł.procedury 0040 ; 0050 BLOK EQU 0ACDH ;adres proc.zapisu-odczytu 0060 DYSNR EQU 3209H ;adres zmien. - nr FDD 0070 ; 0080 RWBLK DI ;zablokuj przerwania 0090 PUSH IY ;przechowaj IY na stosie 0100 LD A,48H ;A:=48 hex 0110 OUT (0F7H),A ;włącz ROM dod. i RAM 8..64kB 0120 LD A,(NRDYS) ;A:=numer FDD 0130 LD (DYSNR),A ;i wpisz do 3209h 0140 LD BC (KODOP) ;BC:= kod op.4-odcz.,6-zapis 0150 PUSH BC ;i umieść na stosie 0160 LD BC,(NRBLK) ;BC:=numer bloku 0170 LD DE,(ADRES) ;DE:=ad.zapisu-odczytu bloku 0180 CALL BLOK ;czytaj-zapisz blok 0190 LD B,0 ;BC:=kod błędu 255 dobrze 0200 LD C,A ; 0 - źle 0210 LD A,8 ;ROM podst.,RAM 16..64kB 0220 OUT (0F7H).A ; 0230 POP IY ;odtwórz rej. IY 0240 EI ;odblokuj przerwania 0250 RET ;wróć do BASIC ZX Spectrum 0260 ; 0270 NRDYS DEFB 0 ;nr FDD (0 lub 1) 0280 KODOP DEFW 4 ;kod oper. (4-load, 6-save) 0290 NRBLK DEFW 0 ;numer bloku 0300 ADRES DEFW 8000H ;adres początku bloku w pamięci 0310 ; 0320 END
Druga (por. wydruk 5) umożliwia odczyt i zapis dowolnego sektora. Za jej pomocą można odczytywać normalnie ukryte dla użytkownika ścieżki systemowe (ścieżka 0 na stronach 0 i 1)! Ponadto pozwala na odczyt (i zapis) dysków zapisanych w innych formatach niż Junior!
Wydruk 5. Procedura odczytu/zapisu jednego sektora 0010 ; 0020 ORG 60000 ;adres wywołania 0030 ; 0040 RWSEK DI ;zablokuj przerwania 0050 PUSH IY ;IY na stos 0060 LD A,48H ;ROM dod., RAM 8..16kB 0070 OUT (0F7H),A ;przełącz pamięć 0080 LD DE,2009H ;DE:=adr. kodów ster. 0090 LD HL,USTAW ;uPD 765 - tu ustaw.głow. 0100 LD BC,3 ;na ścieżkę 0110 LDIR ;przepisz kody 0120 LD A,(NRDYS) ;A:=numer FDD 0130 CALL 01EEH ;włącz FDD 0140 WAIT IN A,(0EEH) ;odcz.rej. stat. sterów. 0150 BIT 7,A ;czy stacja gotowa ? 0160 JR Z,WAIT ;skok jeśli nie gotowa 0170 CALL OPOZN ;opóźnienie 6180 LD BC,2007H ;BC:=adr. kodów sterown. 0190 CALL 99AH ;ustaw głowicę na ścieżkę 0200 LD DE,2007H ;wpisz 2007..2010h kody dla 0210 LD HL,RDWR ; sterownika 0220 LD BC,0BH ;BC:=dług.bloku kodów 0230 LDIR ;przepisz 0240 CALL OPOZN ;opóźnienie 0250 LD BC,2007H ;BC:=adres kodów sterownika 0260 CALL 99AH ;zapisz/odczytaj sektor 0270 CALL OPOZN ;opóźnienie 0280 CALL 1F8H ;wyłącz FDD 0290 LD A,(201AH) ;kod błędu do BC 0300 LD C,A ; 0310 POP IY ;odtwórz IY 0320 ID A,8 ;ROM podst., RAM 16..64kB 0330 OUT (0F7H),A ;przełącz pamięć 0340 EI ;odblokuj przerwania 0350 KET ;wróć do BASIC ZX Spectrum 0360 ; 0370 OPOZN LD BC,80H ;procedura opóźniająca 0380 LOOP DJNZ LOOP ; 0390 DEC C ; 0400 JR NZ,LOOP ; 0410 RET ;powrót do głównej prac. 0420 ; 0430 USTAW DEFB 0FH ;kod ster. - ustaw głowicę 0440 STDY1 DEFB 0 ;strona dysku, nr FDD 0450 SCIE1 DEFB 0 ;numer ścieżki (0..79) 0460 ; 0470 RDWR DEFW 8000H ;adres zapisu-odczytu 0480 CODE DEFB 46H ;kod ster.-tu odczyt sekt. 0490 STDY2 DEFB 0 ;strona dysku, nr FDD 0500 SCIE2 DEFB 0 ;nr ścieżki (0..79) 0510 STR DEFB 0 ;strona (0..1) 0520 SEKT DEFB 1 ;nr sektora (1..9) 0530 DEFB 2 ;512 bajtów/sektor 0540 DEFB 9 ;9 sektorów/ścieżkę 0550 DEFB 12H ;odstęp między sektorami 0560 DEFB 0FFH ;stała 255 0570 NRDYS DEFB 0 ;nr FDD (0 lub 1) 0580 END
W procedurze odczytu-zapisu bloku (wydruk 4) w komórce NRDYS (60040) należy umieścić numer napędu stacji (0 lub 1). W komórce KODOP (60041) należy wpisać 4, jeśli chcemy odczytać blok, lub też 6, jeśli chcemy zapisać blok. Dwie komórki NRBLK (60043) powinny zawierać numer bloku, który zamierzamy odczytać lub zapisać.
W komórkach ADRES wpisujemy adres początku obszaru pamięci, do którego zostaną wpisane dane odczytane z dysku przy odczycie bloku (lub z którego zostaną pobrane dane do zapisania na dysku przy zapisie bloku). W przykładzie podano adres #8000 (32768), a więc odczyt-zapis będzie dotyczył obszaru od 32768 do 34815.
Procedurę wywołuje się przez np. PRINT USR 60000.
Przy prawidłowym odczycie lub zapisie na ekranie powinniśmy otrzymać 255. Jeśli odczyt lub zapis nie był prawidłowy (np. dysk w innym formacie) na ekranie pojawi się 0.
Procedura z wydruku 5 umożliwia odczyt lub zapis dowolnego sektora na dysku formatu 720kB, jak również w innych formatach np. 360kB IBM. Wywołana z takimi jak podano w wydruku parametrami odczytuje pierwszy sektor ścieżki 0 na stronie 0 dysku umieszczonego w stacji 0 (czyli A) -- w formatach 720kB, 360kB i 180kB (jednostronne). Dane odczytane z dysku wpisuje do RAM od 32768 do 33279 (#8000..#81FF).
W celu odczytania innych sektorów należy zmienić poszczególne parametry dla sterownika µPD 765.
W komórce NRDYS można umieścić 0 lub 1 (napęd A lub B).
W komórkach STDY1 i STDY2 należy podać stronę i numer napędu: bity 0 i 1 -- nr napędu od 0 do 3 (w Juniorze 0 lub 1), bit 2 -- strona 0 lub 1.
W komórkach SCIE1 i SCIE2 należy wpisać numer ścieżki (od 0 do 79), przy czym nie muszą to być te same wartości. Jeśli do stacji włożymy dysk np. 360kB (każda strona zawiera tu po 40 ścieżek, a więc dwa razy mniej niż Junior) to chcąc odczytać jakiś sektor ze ścieżki np. 10, należy wpisać do SCIE1 wartość 20, a do SCIE2 wartość 10. Inaczej mówiąc należy ustawić głowicę stacji na odczyt ścieżki 20, a odczytać 10.
W komórce STR należy jeszcze raz podać numer strony dysku (0..1), a w komórce SEKT umieścić numer sektora 1..9.
Od adresu USTAW (#EAB6 = 60086) umieszczone są dane dla sterownika µPD 765: kod instrukcji "ustaw głowicę napędu na ścieżkę" (1 komórka -- #0F), strona i nr napędu (1 komórka), numer ścieżki (1 komórka).
Od adresu RDWR umieszczone są dane dla właściwej operacji zapisu lub odczytu sektora: adres odczytu (zapisu) sektora (2 komórki), kod operacji "odczytaj sektor" (46) (lub "zapisz sektor" -- 45), strona i nr napędu (1 komórka), numer ścieżki (1 komórka), strona (1 kom.), numer sektora (1 kom.). Dalej ilość 256-bajtowych bloków danych w jednym sektorze, liczba sektorów na ścieżkę, długość przerwy między sektorami, liczba 255, gdy sektor zawiera więcej niż 256 bajtów danych.
Dane od adresu SCIE2 do bajtu zawierającego #FF muszą być przy odczycie lub zapisie sektora identyczne z tzw. identyfikatorem sektora, który umieszczany jest na początku każdego sektora podczas formatowania dysku. Jeżeli dysk jest inaczej sformatowany np. jedna ścieżka zawiera 8 sektorów, to chcąc go odczytać należy zmienić niektóre dane dotyczące identyfikatora sektora (w tym przypadku liczbę sektorów na ścieżkę, a możliwe, że także i inne np. odstęp między sektorami, długość sektora).
Aby ułatwić posługiwanie się przedstawioną procedurą przy odczycie-zapisie dysków w dwóch formatach 720kB i 360kB można napisać dodatkowo program, który po określeniu numeru sektora (od 0 do 1439 dla dysku 720kB, lub od 0 do 719 dla 360kB) wyliczy numer strony, numer ścieżki i numer sektora na ścieżce. Dla łatwiejszego zrozumienia program napisany jest w ZX Spectrum BASIC (por. wydruk 6).
Wydruk 6. Program czytania/zapisu sektorów w formatach 720 i 360 kB. 10 LOAD *"CSEKTOR"CODE 60000,101 20 CLS 30 INPUT "DYSK 1/0";D: IF D<>0 AND D<>1 THEN GO TO 30 40 INPUT "OPERACJA L/S";K$: IF K$<>"L" AND K$<>"S" THEN GO TO 40 50 IF K$="L" THEN POKE L+91,70 60 IF K$="S" THEN POKE L+91,69 70 INPUT "FORMAT 720/360 kB" (1/2)";FORM: IF FORM<>l AND FORM< >2 THEN GO TO 70 80 INPUT "SEKTOR 0..1439/0..719";NRSE: IF NRSE*FORM>1439 THEN GO TO 80 90 REM *** numer sektora na ścieżce (0..8) 100 LET SEK=NRSE-9*INT (NRSE/9) 110 REM *** numer ścieżki 120 LET SCI=INT ((NRSE-SEK)/18) 130 REM *** strona 140 LET STR=(NRSE-SEK)/9-SCI*2 150 REM *** sektor 1..9 160 LET SEK=SEK+1 170 REM *** 180 LET L=60000 190 REM *** strona i numer dysku 200 POKE L+87,D+4*STR: POKE L+92,PEEK (L+87) 210 REM *** strona 220 POKE L+94,STR 230 REM *** ścieżka (*2 dla 360kB) 240 POKE L+88.SCI*FORM: POKE L+93,SCI 250 REM *** sektor 260 POKE L+95,SEK 270 REM *** numer dysku 280 POKE L+100,D 290 REM *** 300 LET M=USR L: CLS : IF M<>0 THEN PRINT "BŁĄD ZAPISU-ODCZYTU": GO TO 30 310 CLS : PRINT "SEKTOR ";NRSE,"FORMAT ";F0RM: PRINT 320 LET ADRES=32768: FOR F=ADRES TO ADRES+511 330 PRINT F;" ";PEEK F,CHR$ (PEEK F AND PEEK F>31) 340 NEXT F 350 GOTO 20 Uwaga: w linii 10 zbiór "CSEKTOR" to kod wynikowy uzyskany po zasemblowaniu procedury z wydruku 5.
Po uruchomieniu programu należy podać nr napędu, rodzaj operacji (Load--Save), format dysku oraz numer sektora.
W liniach 100..160 program przelicza numer sektora (0..1439 lub 0..719) na potrzebne dane tzn.: numer sektora na ścieżce, numer ścieżki i stronę. Następnie od linii 200 do 280 wpisuje wyliczone dane do odpowiednich komórek pamięci, gdzie stanowią one dane dla sterownika dysków. Po pomyślnym zakończeniu procedury maszynowej (linia 300) zmienna M = 0 i następuje wydruk na ekranie odczytanych (zapisanych) danych. W przeciwnym wypadku sygnalizowany jest błąd.
Program na wydruku 6 jest bardzo uproszczony. Można go rozbudować o wiele różnych funkcji, przede wszystkim, jeśli chodzi o wydruk (np. szesnastkowo). Można także przenieść np. przeliczenia sektorów do procedury maszynowej, itd.
Powyższy tekst został w całości napisany na mikrokomputerze Junior pracującym w trybie CP/J za pomocą edytora tekstów EDJ znajdującego się na dysku firmowym.
Procedury maszynowe napisane zostały przy użyciu asemblera EDITAS firmy Picturesque komputera ZX Spectrum (asembler przystosowano do współpracy ze stacją dysków Juniora). Następnie przy użyciu programu kopiującego napisanego w całości w asemblerze (znowu EDITAS) plik z niniejszym tekstem został przeniesiony na dysk w formacie IBM 360kB.
Po zamianie kodów polskich znaków diakrytycznych Juniora na kody "odpowiednie" dla IBM (patrz INFORMIK nr 2/1988 str. 11) -- to już wykonał krótki program w Pascalu na IBM AT -- tekst został "uformowany" pod kontrolą edytora WORDSTAR v.4.00 (na komputerze IBM AT) i wydrukowany na drukarce STAR NL 10.
Od redakcji: Ze względów poglądowych w tekście artykułu przyjęto konwencję zapisu liczb szesnastkowych (heksadecymalnych) jako ciągu znaków poprzedzonych znakiem #. W treści procedur zastosowany jest format zapisu żądany przez asembler, tzn. liczba heksadecymalna przedstawiana jest jako ciąg znaków zaczynający się od cyfry i kończący literą H. Pozostałe liczby są liczbami w systemie dziesiętnym.
Jarek AdamskiDnia 2005-10-22 komentarze zostały rozszerzone o wnioski wynikające z analizy schematów.