|
Wersja XL OS dla 65C816WDC 65C816S, zwany w skrócie 65C816, to wytworzony i sprzedawany przez Western Design Center mikroprocesor, który jest wersją rozwojową mikroprocesora 6502. Różne wersje 6502 zastosowano m.in. w komputerach Apple II, Atari 400/800/XL/XE oraz Commodore C-64, C-128. W odróżnieniu od 6502, który jest układem w pełni ośmiobitowym, układ 65C816, mimo ośmiobitowej magistrali danych, ma strukturę wewnętrzną pozwalającą na szesnastobitowe ich przetwarzanie. Dostępne są szesnastobitowe rejestry, do 64 kB stosu, wiele nowych trybów adresowania i rozkazów (w tym nieznane na 6502 przesłania pamięć-pamięć). Oraz, przede wszystkim, dzięki 24-bitowej szynie adresowej możliwy jest montaż do 16 MB pamięci adresowanej wprost. Mikroprocesor może też pracować z dużo większą niż 6502 częstotliwością - do 14 MHz. Wszystkie te cechy sprawiają, że zamiana 6502 na 65C816 staje się bardzo interesującym rozszerzeniem, jakie można sobie zamontować do małego Atari. Ta strona poświęcona jest niektórym aspektom takiego rozszerzenia.
I. Notki wstępne65C816 ma dwa tryby pracy. Pierwszy z nich, to tryb emulacji 6502, w którym procesor się "budzi" dla zachowania zgodności z systemami operacyjnymi pisanymi dla 6502. Drugi tryb, to tryb natywny, który pozwala na skorzystanie z większości rozszerzeń, tj. np. z 16-bitowych rejestrów. Niestety, żeby użyć trybu natywnego, trzeba zmodyfikować zawartość ROM-u Atari XL/XE, z powodów objaśnionych poniżej. Ta konieczność natchnęła mnie do tego, żeby do sprawy podejść kompleksowo i nie poprzestając na samym tylko umożliwieniu pracy w trybie natywnym, sprezentować istniejącym jeszcze użytkownikom Atari nową wersję systemu operacyjnego. Zawarłem tam pewne rozszerzenia, które wydały mi się niezbędne, albo przynajmniej przydatne. Wszystkie prace nad kodem systemu wykonuję na moim Atari 65XE. Komputer wyposażony jest w mikroprocesor 65C816, wewnętrzną kartę SpartaDOS X, 256 kB bankowanej pamięci RAM, 2,5 calowy twardy dysk Toshiba MK2103MAV o pojemności 2,1 GB (podpięty przez interfejs KMK/JŻ IDE), oraz oczywiście opisywany niniejszym ROM. System pisany jest i kompilowany pod asemblerem MAE 1.2 autorstwa Johna Harrisa. Modyfikacja ROM-u ma na celu:
II. Instrukcja obsługiObsługa systemu praktycznie nie różni się od obsługi XL OS, oba systemy zachowują się podobnie. Jedyna większa różnica występuje w funkcjach klawiszy konsoli:
1) Domyślna stacja dyskówInaczej niż w XL OS, numer napędu, z którego ma przebiegać start systemu (boot) jest ustalany nie po, ale przed zainicjowaniem sterowników urządzeń podłączonych do szyny równoległej. W efekcie sterownik twardego dysku ma możliwość łatwej - bez żadnych, a koniecznych pod XL OS, sztuczek - zmiany numeru tego dysku. Korzysta z tego interfejs KMK/JŻ. 2) MenuMenu, jako się rzekło, służy do wyboru dysku, z którego ma się odbyć start systemu. Wyboru dokonuje się albo klawiszami kursora (strzałki góra/dół), albo wciskając klawisz z jedną z liter widniejących z lewej strony ekranu. Po każdej zmianie komputer próbuje się skomunikować z wybranym napędem i wypisuje krótką informację na jego temat:
Jeśli tryb przyspieszonej transmisji jest z jakichś względów niepożądany, można go wyłączyć wcisnąwszy klawisz "T". Wybór dysku zatwierdza się wciśnieciem klawisza RETURN. Powoduje to opuszczenie menu i kontynuację inicjowania systemu. Menu korzysta w stu procentach z urządzenia "E:", tak więc powinno bez problemu wyświetlać się i działać nawet, jeśliby ktoś podłączył np. kartę graficzną przez interfejs równoległy, a ta zainstalowałaby urządzenie systemowe zgodne z "E:". Starałem się też, żeby menu miało typowy dla produktów Atari, powściągliwy styl - za wzór posłużył "klasyczny" DOS 2.5. 3) Start systemuIstnieje też drobna - ale dość łatwo zauważalna - różnica w dalszym przebiegu startu komputera. Jeśli domyślna stacja dysków (D1:) nie jest podłączona i gotowa do pracy, albo jeśli użytkownik wybrał z menu startowego napęd, który nie jest podłączony (a wolno mu to zrobić, jeśli ma takie życzenie), wtedy zaczyna się procedura poszukiwania pierwszego napędu gotowego do pracy. System próbuje się skomunikować kolejno z wszystkimi stacjami dysków po kolei, od domyślnej (lub wybranej z menu) poczynając, i na niej też, sprawdziwszy wszystkie, kończąc. Powoduje to, że start komputera, do którego nie jest podłączona żadna stacja, i nie jest włożony żaden moduł ROM, który zabroniłby bootowania, trwa dość długo - przeszukanie wszystkich napędów trwa ok. 30 sekund. 4) Klawisze funkcyjne F1-F4XL OS zawiera procedury obsługi klawiszy funkcyjnych F1-F4, których jednak nie ma na konsoli. Istnieją rozwiązania rozszerzające komputery XL/XE o te klawisze, nie biorą one jednak na ogół pod uwagę faktu, że procedura ich obsługi zawarta w XL OS koliduje z rozszerzeniami pamięci takimi jak np. w Atari 130XE. Mówiąc krótko, wciskanie niektórych kombinacji klawiszy F1-F4 powoduje niekontrolowane przełączenia banków pamięci 130XE, co może skutkować niespodziewanym zawieszaniem się systemu, i na ogół właśnie tym skutkuje. Powodem jest to, że komputery 1200XL, 1400XL i 1450XLD mają na konsoli lampki sygnalizujące wybór pewnych funkcji klawiszami F1-F4. Lampki te podłączone są do bitów rejestru PORTB - tego samego, który w 130XE steruje rozszerzeniem pamięci. Procedura przerwania klawiatury wykrywszy fakt wciśnięcia którejś kombinacji klawiszy F1-F4 usiłuje oczywiście sterować tymi lampkami nie zdając sobie sprawy, że nie istnieją. W nowym systemie zostało to poprawione: używanie klawiszy F1-F4 jest zupełnie bezpieczne i nie powoduje żadnych skutków ubocznych na komputerach z rozszerzeniem pamięci. Natomiast na komputerach bez rozszerzenia pamięci wszystko będzie działać po staremu - to znaczy przy braku rozszerzenia pamięci typu 130XE system zakłada, że bity PORTB sterują wymienionymi wyżej lampkami komputera 1200XL. ProgramowanieIII. Uwagi na temat przerwańProcedury obsługi przerwań dla trybu natywnego nie są tak proste do wymyślenia, jakby się to na pierwszy rzut oka wydawało. Przede wszystkim, z powodu niewielkiej ilości miejsca w ROM-ie, nie można sobie pozwolić na zduplikowanie wszystkich procedur obsługi przerwań i przygotowanie oddzielnego ich zestawu dla trybu natywnego. Dlatego rozdzieleniu ulegają jedynie procedury wstępne (czyli istnieją np. dwie oddzielne wersje procedury NMIFIRST, jedna dla trybu emulacji, a druga natywnego), główne procedury obsługi natomiast (np. SYSVBL) pozostają w jednej kopii i obsługują przerwania zarówno w trybie natywnym jak i w trybie emulacji. Ogólne założenia dla systemowych procedur przerwań są następujące:
Wady podsystemu przerwań opracowanego wg. powyższych założeń:
Ma to jednak też pewne zalety:
Z drugiej strony obciążenie przerwań w trybie emulacji jest cokolwiek zredukowane dzięki zastosowaniu nowych rozkazów i trybów adresowania. Na przykład procedura obsługi NMI zajmuje 32 cykle na 6502, ale tylko 26 cykli na 65C816. Podobnie procedura EXITVBL została skrócona z 23 do 19 cykli, a dochodzą do tego też oszczędności wewnątrz samej procedury SYSVBL. To wszystko nie równoważy zwiększonego obciążenia w trybie natywnym, niemniej nieco je redukuje. Uwagi na temat DLIDLI jest szczególnym przypadkiem, bo jest to przerwanie krytyczne czasowo. Jak twierdzą niektóre żrodła, jedna linia obrazu "zawiera" tylko 104 cykle CPU, a wobec tego obciążenie DLI kodem wstępnym o długości 94 cykli - opcja "zapisz wszystko" - nie jest możliwością, jaką można byłoby serio rozważać na dłuższą metę. Z wyżej wyłuszczonego powodu procedura obsługi DLI jest uruchamiana przy nie do końca zdefiniowanym stanie CPU. Rejestry PBR i DBR są ustawione na zero, a rozmiar akumulatora na osiem bitów. Rozmiar rejestrów indeksowych jest niezdefiniowany (8 albo 16 bitów), żaden z rejestrów nie jest też przechowany na stosie. Procedura musi się kończyć przez RTI, system operacyjny bierze przywrócenie zawartości DBR na siebie. Uwaga: akumulator też nie jest przechowany na stosie, programista musi zadbać o to sam przed jego użyciem, i przywrócić pierwotną wartość przed wykonaniem się rozkazu RTI. Trzeba też mieć baczenie na fakt, iż użycie 16-bitowego akumulatora spowoduje, że procedura nie będzie działać w trybie emulacji! Uwaga: rejestry X/Y nie są przechowane na stosie. Co więcej, ich rozmiar nie jest określony. Jeśli programista zamierza ich użyć, powinien najpierw zapisać je na stosie, a potem ustawić pożądany rozmiar. Przykłady: ; Przykład 1 ; Użycie w DLI rejestru X o rozmiarze 8 bitów. ; Uwaga: trzeba zapisać OBYDWA rejestry indeksowe ; nawet jeśli używamy TYLKO JEDNEGO!!! rep #$10 ;ustawienie obu rejestrów na 16 bitów phx ;zapis OBYDWU przed przełączeniem na 8 bitów phy sep #$10 ;przełączenie ... kod ... rep #$10 ;przełączenie z powrotem do pełnego rozmiaru ply plx rti Powód, dla którego należy przełączyć rejestry X/Y najpierw na 16 bitów jest taki, że rozmiar tych rejestrów nie jest określony w momencie wejścia do procedury obsługi przerwania DLI (patrz wyżej). Pominięcie rozkazów REP zaoszczędziłoby 10 cykli, jeśli byłoby pewne, że w momencie wystąpienia przerwania rejestry są ośmiobitowe (2 razy po 3 cykle na rozkazy REP i 4 razy po cyklu na rozkazy PHX/PHY i PLX/PLY); ale jeśli ten warunek NIE jest spełniony, rozkazy PLY/PLX na końcu procedury zdejmą ze stosu niewłaściwą liczbę bajtów, co spowoduje natychmiastowy zwis systemu. ; Przykład 2 ; Użycie rejestru X o rozmiarze 16 bitów. ; W tym wypadku wystarczy zapisać na stos ; tylko te rejestry, których się użyje. ; Uwaga: ten kod nie będzie działał w ; trybie emulacji! rep #$10 phx ... kod ... plx rti Podobnie, jeśli programista ma zamiar użyć rejestrów na stronie zerowej, będzie najprawdopodobniej musiał zapisać na stos i wyzerować rejestr D. To się robi tak: ; Przykład 3 phd ;zapisz rejestr D pea $0000 ;wyzeruj go pld ... kod ... pld rti ; Przykład 4 ; Tu oszczędzamy 5 cykli, jeśli i tak używamy do ; czegoś 16-bitowego akumulatora. rep #$20 pha phd lda #$0000 tcd ... kod ... pld pla rti Niemniej zapisywania i resetowania rejestru D można uniknąć, jeśli:
To ostatnie podejście jest przypuszczalnie najlepsze, przynajmniej tak długo, jak nie mamy systemu z wieloprocesowością. Uwagi na temat VBLW trybie natywnym procedura obsługi VBL jest wykonywana z D=0, DBR=0 i PBR=0. Wszystkie rejestry są zapisane na stosie za wyjątkiem starszego bajtu akumulatora: jeśli programista zamierza użyć 16-bitowego akumulatora albo rozkazu XBA we własnej procedurze obsługi, musi najpierw zachować wartość całego akumulatora na stosie, a potem przywrócić ją przy wyjściu. Szczyt stosu wygląda tak samo w trybie emulacji i natywnym: na samej górze leży ośmiobitowy rejestr Y, potem idąc w głąb stosu znajdują się ośmiobitowy rejestr X oraz ośmiobitowy akumulator, rejestr znaczników P oraz szesnastobitowy adres powrotny. Ale w trybie natywnym to nie jest koniec zgromadzonych na stosie danych, bo pod spodem odłożone są wartości dodatkowych rejestrów (w tym pełne wartości rejestrów X i Y), 24-bitowy adres powrotny itd. Wszystko to jest zdejmowane ze stosu PO wykonaniu się procedury EXITVBL. Uwagi na temat IRQW trybie natywnym procedura obsługi IRQ jest wykonywana z D=0, DBR=0 i PBR=0. Wszystkie rejestry są zapisane na stosie za wyjątkiem starszego bajtu akumulatora: jeśli programista zamierza użyć 16-bitowego akumulatora albo rozkazu XBA we własnej procedurze obsługi, musi najpierw zachować wartość całego akumulatora na stosie, a potem przywrócić ją przy wyjściu. Szczyt stosu wygląda tak samo w trybie emulacji i natywnym: na samej górze leży rejestr znaczników P, a pod nim szesnastobitowy adres powrotny. Ale w trybie natywnym to nie jest koniec zgromadzonych na stosie danych, bo pod spodem odłożone są wartości dodatkowych rejestrów (w tym pełne wartości rejestrów X i Y), 24-bitowy adres powrotny itd. Wszystko to jest zdejmowane ze stosu PO wykonaniu się rozkazu RTI kończącego obsługę przerwania. Czasy odpowiedzi na przerwanieCzasy wykonywania się wstępnych i końcowych procedur przerwań, mierzone w cyklach CPU, w porównaniu do XL OS. Czas dla NMI jest liczony od momentu przyjęcia przerwania przez procesor do chwili wejścia do głównej procedury obsługi (wskazywanej przez wektory DLIV i VVBLKI); oraz od zakończenia rozkazu RTI do rzeczywistego powrotu z przerwania. Czas dla IRQ jest mierzony od momentu przyjęcia przerwania przez procesor do chwili wejścia do procedury rozpoznania źrodła przerwania IRQ (SINRDYI); oraz od zakończenia rozkazu RTI do rzeczywistego powrotu z przerwania.
Zauważmy, że w trybie natywnym zarówno przyjęcie przerwania, jak i RTI zajmują po cykl więcej, i ta różnica jest tu już uwzględniona. Trzeba też pamiętać, że zarówno NMI jak i IRQ mają dodatkowe, "główne" wektory w pamięci RAM, które to wektory wskazują wstępne procedury obsługi przerwania znajdujące się w ROM-ie. Skok przez te wektory dodaje po 6 cykli do początku obsługi przerwania i ten dodatkowy czas jest tu już uwzględniony (gdyby takie wektory istniały w XL OS, czasy dla XL OS wynosiłyby 23, 42 i 19 cykli odpowiednio dla DLI, VBL i IRQ). IV. Nowy mechanizm wywoływania systemuStary mechanizm wywoływania systemu operacyjnego, zaimplementowany w XL OS, który bazuje na tablicy skoków i wywołaniach przez JSR, ma niestety pewnie ograniczenie, które czyni jego użycie problematycznym w programach pisanych dla 65C816, a umieszczających swój kod w pamięci powyżej pierwszych 64k. Mianowicie, rozkaz JSR ma szesnastobitowy argument, w związku z czym skokiem JSR nie można przekroczyć granicy 64k. W efekcie skok JSR $E459 osiągnie pożądany adres, tj. $00E459, tylko wtedy, kiedy rozkaz znajduje się w pierwszych 64 kilobajtach pamięci (a na 6502 ten warunek jest zawsze spełniony). Ale kiedy rozkaz taki znajdzie się w banku nr 1, skok zostanie wykonany pod $01E459, czyli nie tam, gdzie powinien. Z drugiej strony 65C816 oferuje rozkaz JSL, który ma 24-bitowy argument i zapisuje na stosie 24-bitowy adres powrotny. Niestety, procedury znajdujące się w ROM-ie kończą się zwykłym, 16-bitowym rozkazem RTS, i nie można tego zmienić, bo trzeba utrzymywać kompatybilność ze starymi programami. Z tego powodu rozkaz JSL nie nadaje się do wywoływania funkcji systemu. Oczywiście rozwiązaniem mogłaby być alternatywna tablica skoków zgodna z "długimi" skokami JSL. Tyle że szkoda na to miejsca w ROM-ie, a poza tym tablica skoków nie jest w ogóle rozwiązaniem najszczęśliwszym, bo nie da się przejąć wywołań systemu jeśli są wektorowane przez ROM. Nowa metoda wywołańNowa metoda wykorzystuje niemaskowalne przerwanie programowe wywoływane rozkazem COP, który spełnia podobną funkcję, jak rozkaz TRAP na Motoroli 68k. Rozkaz COP przyjmuje jednobajtową stałą jako argument natychmiastowy. Rozkazy o argumentach z zakresu od $80 do $FF są zarezerwowane do przyszłych zastosowań przez producenta procesora, reszta natomiast, tj. argumenty z zakresu $00-$7F, jest dostępna naszej definicji. Nowe wektory systemowe w pamięci RAMHandler przerwania COP znajdujący się w pamięci ROM definiuje pięć nowych wektorów w pamięci, większość z nich jest 24-bitowa. Są to: VCOPE $000251-$000252 WORD Dwa wektory przerwania COP, odpowiednio dla trybu emulacji i natywnego. Pierwszy z nich nie jest na razie używany, wskazuje RTI. Przyczyna tego jest taka, że w trybie emulacji nowy mechanizm wywoływania systemu nie jest potrzebny: programista może używać starego (skoków JSR), bo w trybie emulacji i tak możliwość uruchamiania kodu w nowych obszarach pamięci jest mocno ograniczona. Drugi wektor, VCOPN, wskazuje na handler systemowy. Jeśli programista zmienia wartość tego wektora, to swój kod musi zakończyć albo przez skok JMP pod stary adres, albo przez RTI. VCOP0 $000262-$000264 LONG To są wektory "drugiego stopnia", wywoływane z wnętrza systemowego handlera COP. Kod wskazywany przez nie jest wywoływany długim skokiem JSL i musi się kończyć przez RTL (albo skok JMP/JML pod stary adres). Pierwszy z wektorów jest używany, kiedy wykonuje się rozkaz COP #$00. Rozkaz ten jest zarezerwowany do użycia przez system operacyjny, szczegóły poniżej. Drugi wektor jest używany, kiedy wykonuje się rozkaz COP z argumentem z zakresu od $01 do $7F. Trzeci wektor jest przeznaczony do wywołania, gdy wykonuje się "zarezerwowany" rozkaz COP, czyli z argumentem z zakresu od $80 do $FF. W momencie skoku przez te wektory 24-bitowy wskaźnik znajdujący się pod adresem $000018 wskazuje na argument rozkazu COP (tj., jeśli wykonuje się rozkaz COP #$00, wskaźnik wskazuje jego argument, czyli część oznaczoną mnemonicznie jako "#$00"). Wszystkie wektory drugiego stopnia wywoływane są w trybie natywnym, z D=0, PBR=0, DBR=0 i rejestrami ustawionymi na 16 bitów. Zawartość rejestrów jest przechowywana przez handler i powinna być taka sama, jak w momencie wywołania rozkazu COP (za wyjątkiem VCOP0, gdzie rejestry zawierają wartości umieszczone tam przez XL OS). Handler pierwszego stopnia (wskazywany przez VCOPN) odpowiada za przywrócenie kontekstu CPU do stanu sprzed wykonania się rozkau COP. Specjalne znaczenie rozkazów COP #$00 i COP #$01Rozkaz COP #$00 służy do emulowania funkcji systemowych XL OS. Handler tego przerwania jako parametr przyjmuje 16-bitowy adres procedury wewnątrz pierwszych 64k, wywołuje ten adres przez JSR, a potem zwraca wynik do programu wywołującego. Zarówno zawartość rejestrów A/X/Y, jak i bity rejestru P zawierają wartości umieszczone tam przez wywołaną procedurę. Jedynie bity MX rejestru P są ustawione na wartość jaką miały przed wywołaniem COP #$00. Oto przykład wywołania funkcji systemu tą metodą: sep #$30 ;ustaw rejestry na osiem bitów ldx #$10 ;IOCB #1 lda #$0c ;rozkaz: CLOSE sta >iccmd,x ;zapisz do IOCB pea jciomain ;zapisz na stosie adres funkcji systemu cop #$00 ;wywołanie pla ;zdejmij zbędny już adres ze stosu pla Wywołanie przez wektor CIO: rep #$20 ;akumulator na 16-bitów lda $e400 ;wektor CIO: otwarcie edytora E: inc ;wektor jest zmniejszony o 1, trzeba skorygować pha ;gotowa wartość na stos cop #$00 ;wywołanie pla ;zbędny parametr usuwamy ze stosu Wywołanie procedury PUT przez kanał IOCB #1: rep #$20 ;akumlator na 16 bitów sep #$10 ;X/Y na 8 bitów ldx #$10 ;IOCB #1 lda icputb,x ;pobierz wektor inc ;zwiększ o 1 pha ;na stos sep #$20 ;akumulator na 8 bitów lda data ;dana do wysłania cop #$00 ;wywołanie systemu rep #$20 ;akumulator na 16 bitów pla ;usunięcie zbędnego argumentu To jest jedyna bezpieczna metoda wywoływania funkcji XL OS w trybie natywnym CPU. Tradycyjną metodą można wywoływać funkcje ROM-u *tylko* w trybie emulacji. Nawet jeśli procedury zawarte w ROM-ie powinny działać tak samo w obu trybach, nie mogę jednak zagwarantować tego samego w przypadku zewnętrznych sterowników urządzeń, zwłaszcza DOS-u. Mogą one zawierać kod, który nie będzie kompatybilny z trybem natywnym CPU. Rozkaz COP #$01 służy do wywoływania rezydujących w ROM-ie funkcji, które nie mają odpowiednika w XL OS. W tej chwili przez COP #$01 można wywoływać funkcje zarządzania pamięcią. V. Nowe funkcje SIOIstnienie większości nowych funkcji można sprawdzić w pliku @:SYSDEF. Poleganie przy tym na numerze wersji ROM-u raczej nie jest zalecane - wszelkie uwagi poniższe o tym, że funkcja jest dostępna od tej czy tamtej wersji, mają tylko charakter informacyjny. Począwszy od wersji BB 02.08 SIO jest w stanie zapisywać dane (np. sektory dyskietki) bezpośrednio w dodatkowej pamięci powyżej adresu $00FFFF, oraz odczytywać je bezpośrednio z niej. Blok DCB został rozszerzony do 16 bajtów, najstarszy bajt adresu bufora znajduje się pod adresem $00030E. Jednak, dla utrzymania zgodności z dotychczasowym oprogramowaniem, a już zwłaszcza z dotychczasowymi sterownikami urządzeń podłączanych do szyny równoległej, wpisanie pod $000304/5/E 24-bitowego adresu nie da pożądanego wyniku; jeśliby bowiem urządzenie brało pod uwagę tylko 16 najmłodszych bitów adresu ignorując najstarszy bajt wpisany pod $00030E, wtedy - przy odczycie - dane zostałyby umieszczone nie tam, gdzie trzeba. Musi więc istnieć mechanizm, który zapobiega tego typu nieporozumieniom. W tym celu SIO definiuje trzy nowe urządzenia wirtualne, o kodach jak następuje:
Wywołanie urządzenia z takim kodem w DDEVIC powiadamia sterownik SIO, że adres bufora w DCB jest 24-bitowy i że najstarszy bajt adresu jest pod $00030E (w przeciwnym wypadku SIO zakłada, że najstarszy bajt adresu to 0). Poza tym działanie urządzeń wirtualnych jest identyczne, jak tradycyjnych (odpowiednio $31, $40 i $50), a kod urządzenia jest przed wysłaniem na port szeregowy przekładany na kod rzeczywisty. Przyjmując komendę do wykonania SIO w żaden sposób nie sprawdza, czy dodatkowa pamięć w ogóle istnieje - zakłada się, że program sam stwierdzi jej istnienie (choćby za pomocą funkcji alokacji pamięci) przed próbą odczytu do niej danych. VI. Nowe funkcje CIO1. Począwszy od wersji BB 02.03 CIO akceptuje 0 (zero) jako numer urządzenia, np. nazwa "D0:" zostanie zdekodowana jako "urządzenie D: nr 0". W poprzednich wersjach systemu było to po cichu zmieniane na "D1:". To rozszerzenie pochodzi z ROM-u przygotowanego przez Atari dla komputera Atari 1450XLD. 2. Począwszy od wersji BB 02.05 umieszczony w ROM-ie interfejs CIO ma nową funkcję wyszukiwania pierwszego wolnego (zamkniętego) kanału IOCB. Wywołanie: ldx #-1 jsr jciomain zwraca status w rejestrze Y (1 - sukces lub ujemny kod błędu), a w rejestrze X pomnożony przez 16 numer znalezionego kanału. 3. Począwszy od wersji BB 02.08 umieszczony w ROM-ie sterownik klawiatury rozpoznaje następujące funkcje XIO:
4. Od wersji BB 02.08 zawarty w ROM-ie sterownik klawiatury ma nową funkcję "skanowania" stanu klawiszy. W tym trybie wywołanie funkcji GET dla klawiatury nie powoduje "ugrzęźnięcia" programu w pętli oczekującej na naciśnięcie klawisza, lecz następuje natychmiastowy powrót do miejsca wywołania niezależnie od tego, czy użytkownik nacisnął jakiś klawisz, czy nie. Taki tryb pracy klawiatury włącza się przez otwarcie kanału IOCB z ustawionym bitem 1 bajtu ICAX2; na przykład: OPEN #1,4,1,"K:" Gdy jakiś klawisz był naciśnięty, GET #1 zwraca jego kod ASCII w akumulatorze i status 1 w rejestrze Y. W przeciwnym wypadku, gdy żaden klawisz nie był naciśnięty, w rejestrze Y umieszczany jest kod statusu -78 (178, $B2), a wartość akumulatora jest bez znaczenia. Ustawienie tego trybu dla jednego kanału IOCB nie ma wpływu na inne, ani też na funkcjonowanie edytora ekranowego ("E:"). Niestety, tego trybu nie da się użyć spod BASIC-a, bo -78 w rejestrze Y jest przez interpreter BASIC-a traktowane jako błąd i powoduje przerwanie wykonywania programu. VII. Urządzenie "N:"Od wersji BB 01.93 w pamięci ROM znajduje się sterownik urządzenia "N:" (null). Ma ono następujące cechy:
VIII. Urządzenie "@:"Urządzenie "@:" jest pseudodyskiem zawierającym jeden plik o nazwie "SYSDEF"; plik ten ma długość 128 bajtów. Zawiera garść informacji o systemie na użytek programów, które chciałyby się np. dowiedzieć, czy można używać kodu 65C816 i czy bezpieczne jest używanie trybu natywnego. Zawartość pliku "@:SYSDEF" jest następująca:
W wypadku zupełnego braku tego urządzenia albo tego pliku (błąd 138, 170 albo podobny przy otwieraniu "@:SYSDEF"), wartości bajtów od 10 do 127 trzeba przyjąć jako zera. Pozostałe bajty na razie są zarezerwowane i czytają się jako zera. Odczyt bajtów może być sekwencyjny, można też przesunąć znacznik odczytu funkcją nr 37 działającą tak, jak SEEK (czy też POINT) w SpartaDOS X, i odczytać konkretny bajt. Ustawienie znacznika poza końcem pliku powoduje błąd przy następnym odczycie. Funkcja XIO 37 musi być zawsze dostępna dla tego urządzenia. IX. Funkcje zarządzania pamięciąPocząwszy od wersji 2.04 system definiuje trzy funkcje zarządzania pamięcią. Pierwsza z nich - kpsize - opisana jest w dalszej części dokumentu. Druga - kmalloc - służy do zajmowania (alokowania) bloków pamięci, trzecia - kfree - do ich zwalniania. Prototypy funkcji w C wyglądałyby następująco: unsigned int kpsize(void); int kmalloc(int size, unsigned int mode); int kfree(unsigned int page); Jednostką miary pamięci, którą posługują się te funkcje, nie jest bajt, lecz strona. Rozmiar tej strony podaje funkcja kpsize. W obecnej implementacji jest to 256 bajtów - a to niewiele, zważywszy, że programy zarządzania pamięcią w systemach budowanych dla np. m68k potrafią stronicować pamięć po 8 albo 16 kilobajtów. W związku z taką organizacją funkcja kmalloc nie przyjmuje jako parametru size liczby bajtów do pozyskania z systemu, ale liczbę stron. Zwraca też nie adres początku bloku, ale numer strony, od którego się on zaczyna. Tak samo numer strony przyjmuje jako parametr page funkcja kfree. Przy bieżącej implementacji - gdzie strona to 256 bajtów - "numer strony" są to po prostu dwa najstarsze bajty adresu zaalokowanego bloku pamięci. Jeśli funkcji kmalloc podamy -1 (czyli $FFFF) jako size, to nic nie będzie alokować, a jedynie obliczy i zwróci liczbę aktualnie wolnych, 256-bajtowych stron pamięci. Stronicowanie powoduje niewielkie straty pamięci (do 255 bajtów na zaalokowany blok), ale ma tę zaletę, że adres mieści się na szesnastu bitach, co znakomicie upraszcza przekazywanie parametrów do funkcji, odbieranie od niej wyników oraz jej wewnętrzne działanie, a także wydatnie upraszcza i skraca mapę alokacji pamięci.
Gdy już mowa o mapie, liczy ona w obecnej implementacji 64 sloty (42 w starszych wersjach OS-u). Oznacza to, że system może ogólnie zarządzać sześćdziesięcioma czterema blokami pamięci o dowolnej liczbie stron każdy. Jeśli program będzie chciał zająć 32 kB (128 stron) pamięci wywołując 128 razy funkcję kmalloc, to za 65 razem zwróci ona błąd braku pamięci - mimo że zajęte jest dopiero 16 kilobajtów! Dlatego funkcji kmalloc trzeba używać oszczędnie: w danym przykładzie najlepiej jest zająć całe 32k za jednym zamachem - to jest za jednym wywołaniem kmalloc. Parametr mode funkcji kmalloc modyfikuje jej działanie zależnie od potrzeb. Jest to 16 bitów - znaczników włączających i wyłączających kolejne funkcje. Obecnie zdefiniowane są następujące bity:
Pozostałe bity argumentu mode są zarezerwowane i powinny być skasowane dla kompatybilności. Funkcja kfree przyjmuje jako parametr numer strony zwrócony przez kmalloc. Jeśli od strony o podanym numerze zaczyna się zaalokowany i nierezydentny blok pamięci, to jest zwalniany. Opisane wyżej funkcje wywołuje się przerwaniem COP #$01 przekazując parametry na stosie: rep #$30 pea $0000 ;mode pea $0100 ;size (256 stron = 64k) pea $0001 ;kod funkcji kmalloc cop #$01 plx ;usuń niepotrzebne argumenty plx plx Po powrocie funkcja zwraca status w rejestrze Y. Jeśli rejestr Y zawiera wartość dodatnią, to akumulator zawiera numer strony, od której zaczyna się zaalokowany blok (numer strony, czyli dwa najstarsze bajty adresu bloku). Jeśli rejestr Y zawiera wartość ujemną, oznacza to błąd i zawartość akumulatora nie ma wtedy żadnego znaczenia. Użycie pozostałych funkcji jest podobne, z tym że kpsize nie wymaga żadnych parametrów. Kody funkcji są następujące:
Pozostałe kody są na razie zarezerwowane, ich wywołanie zwraca w rejestrze Y błąd -110 (w starszych wersjach systemu pod numerem $0003 była jeszcze jedna funkcja - kfreeall - ale od wersji 2.12 została usunięta jako niepotrzebna). UWAGA. Wszystkie wymienione funkcje działają (1) tylko w trybie natywnym, (2) tylko na dodatkowej pamięci (adresy powyżej 65535) oraz (3) tylko wtedy, kiedy ta pamięć istnieje. Wywołania w trybie emulacji nie przynoszą żadnego efektu (handler przerwania COP dla trybu emulacji istnieje, ale składa się tylko z rozkazu RTI). W przypadu braku dodatkowej pamięci wszystkie funkcje zwracają ujemny kod błędu w rejestrze Y. X. Zmiany w mapie pamięci
XI. Inne zmianyOd wersji 2.10 CHARSET 2 został zmodyfikowany przez zmianę kształtów trzech ostatnich znaków o kodach ASCII 125, 126 i 127. Są to znaki kontrolne edytora ekranowego, odpowiednio CLR/HOME, DEL oraz TAB. Nowe kształty to:
Po zmianie zachowują one swoją funkcję, to jest działają jak poprzednio, a wyświetlać je można tylko w sekwencji z poprzedzającym znakiem ESC (ASCII 27). Kody ATASCII niestety nie pokrywają się z kodami ASCII tych znaków (lewa klamra - 123, prawa klamra - 125, tylda - 126). Zastosowanie kodów znanych z PC nie było możliwe, gdyż w CHARSET 2 kod ATASCII 123 jest już przypisany do niemieckiej litery "A umlaut". W celu poprawnego przeniesienia pliku tekstowego zawierającego te znaki trzeba dokonać konwersji (co i tak trzeba zrobić ze względu na inny kod końca linii w ASCII oraz w ATASCII). XII. KompatybilnośćSystem będzie działał TYLKO z komputerami serii XL/XE, na maszynie z serii 400/800 nawet nie wystartuje. Z punktu widzenia użytkownika są następujące zmiany:
Jednocześnie zostały zachowane takie rzeczy jak drugi generator znaków (CHARSET2) oraz procedury obsługi modułu 1090XL, bo mogą się jeszcze przydać. Z punktu widzenia oprogramowania powinna zostać zachowana stuprocentowa zgodność z takimi i tylko takimi programami, które używają legalnych wejść do systemu (tablica skoków, tablice wektorów itd.). Programy, które odwołuja się do procedur i tablic systemowych bez pośrednictwa odpowiednich wektorów, będą się zawieszać dokładnie tak samo, jak na "starym" systemie od Atari 400/800. Lekarstwem na to jest nałożenie łatek binarnych na program tak, żeby korzystał z tablicy skoków oraz wektorów w RAM-ie. Częstym przypadkiem - nagminnym w programach JBW - jest odwoływanie się bezpośrednim adresem do tablicy definicji klawiatury. Łatka polega tu na zmianie tego na odwołanie pośrednie przez wektor KEYDEFP ($79). Lista zgodności z niektórymi programami jest tutaj. Miłej zabawy |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|