Serwis Edukacyjny w I-LO w Tarnowie ![]() Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej
Autor artykułu: mgr Jerzy Wałaszek |
©2023 mgr Jerzy Wałaszek
|
Każdy komputer domowy ATARI wyposażony jest w 10 KB kartridż z systemem operacyjnym. Waga tego kartridża jest często niedostrzegana. Bez niego masz sprzęt z dużym potencjałem, lecz absolutnie nic więcej! Taka sytuacja nie jest unikalna tylko dla systemu komputerowego ATARI; spotyka się ją we wszystkich komputerach. Komputer jest przecież tylko zbiorem różnych modułów sprzętowych. Użytkownik musi zarządzać tymi zasobami, aby wykonać jakiekolwiek zadanie. Gdyby wszyscy programiści musieli zawsze rozpoczynać każdy program od początku, mielibyśmy o wiele mniej oprogramowania niż mamy dzisiaj. Rozwiązaniem, które ewoluowało przez lata, jest wbudowanie w komputer programu zarządzającego zasobami dostępnymi dla systemu i czyniącego brzemię zaprogramowania sterowania nimi lżejszym. Program ten jest znany pod różnymi nazwami: system operacyjny (ang. Operating System), główny program zarządzający (ang. Master Control Program), system wykonawczy (ang. System Executive), monitor systemu (ang. System Monitor), itp. W komputerze domowym ATARI program ten nazwany został systemem operacyjnym (ang. Operating System) lub w skrócie OS.
Pierwszym zadaniem, z którym styka się student systemu operacyjnego, jest dokładne skatalogowanie zasobów dostępnych dla OS. Są to:
Wykorzystując te zasoby, OS potrafi współpracować i sterować szerokim wachlarzem zewnętrznych urządzeń, łącznie z odbiornikiem telewizyjnym lub monitorem, klawiaturą, głośnikiem konsoli, przełącznikami konsoli, dżojstikami, wiosełkami, magnetofonem kasetowym, stacją dysków, drukarkami, interfejsem RS-232 i modemem.
Reszta tego podrozdziału krótko wymienia główne elementy OS. Elementy te są szczegółowo opisane w kolejnych podrozdziałach.
Monitor OS jest tą częścią systemu operacyjnego w ROM, która obsługuje obie sekwencje włączania i RESETU SYSTEMU. Sekwencje te pozwalają OS przejąć wstępną kontrolę nad komputerem i zapewnić, że wszystko zostanie poprawnie zainicjowane przed przekazaniem częściowej kontroli do programu aplikacji. Obie sekwencje są podobne w działaniu i faktycznie współdzielą dużą część tego samego kodu.
Procedura zimnego startu (ang. Coldstart) jest wywoływana albo przez włączenie komputera, albo przez skok pod wektor systemowy COLDSV ($E477). Oto kilka ważnych zagadnień do zapamiętania, które dotyczą sekwencji startowej:
Naciśnięcie klawisza [SYSTEM RESET] powoduje reset systemu, zwany również ciepłym startem (ang. Warmstart). Powinieneś zapamiętać poniższe kluczowe fakty na temat resetu systemu:
Poniżej znajduje się kilka szczegółowych schematów blokowych sekwencji zimnego (ang. Power-up) i ciepłego startu (ang. Reset).
Rys.8-1.1 Inicjalizacja systemu
Rys.8-1.2 Inicjalizacja systemu
Rys.8-1.3 Inicjalizacja systemu
Rys.8-1.4 Inicjalizacja systemu
To, iż system operacyjny napisano dla mikroprocesora 6502, dyktuje kilka ogólnych rozwiązań w zarządzaniu pamięcią. 6502 posiada trzy specjalne obszary w przestrzeni adresowej. Kluczowe znaczenie ma strona zerowa (komórki o adresach od $00 do $FF), ponieważ używanie danych przechowywanych na stronie zerowej daje w wyniku bardziej zwarty i szybszy kod. W rzeczywistości istnieją nawet instrukcje, które bezwzględnie wymagają do swojej pracy komórek ze strony zerowej. Strona pierwsza (komórki o adresach od $100 do $1FF) jest również specjalna, ponieważ mikroprocesor 6502 wykorzystuje ją na swój stos. Adresy $FFFA - $FFFF są też specjalne, ponieważ zarezerwowane zostały na wektory sprzętowego resetu i przerwań.
Dlatego pierwszym zadaniem zarządzania pamięcią jest przydzielenie obszaru pamięci ROM systemu operacyjnego w górnej części przestrzeni adresowej. OS znajduje się w komórkach ROM o adresach od $D800 do $FFFF. Tuż pod tym obszarem jest przestrzeń zarezerwowana na rejestry sprzętowe w układach ANTIC, CTIA/GTIA i POKEY. Ich adresy obejmują zakres od $D000 do $DFFF.
Na drugim końcu przestrzeni adresowej OS rezerwuje połowę strony zerowej do własnego użytku. Strony dwa, trzy, cztery i pięć są również zarezerwowane na potrzeby OS. Z punktu widzenia programisty obszar użytecznej pamięci rozciąga się od $0600 do $BFFF.
Gdy system zostanie włączony, jednym z pierwszych działań podejmowanych przez OS jest określenie ilości dostępnej pamięci RAM. Wykonuje się to przez sprawdzanie pierwszego bajtu każdego 4 KB bloku pamięci poczynając od adresu $1000. Zawartość tego bajtu zostaje odczytana, zanegowana i następuje próba zapisu tej zanegowanej wartość z powrotem do pierwszego bajtu. Jeśli ta próba się powiedzie, to tymczasowy licznik rozmiaru pamięci jest zwiększany o 4 K. Proces jest kontynuowany aż do znalezienia komórki, której nie da się zmienić. Dwie zmienne, RAMTOP i RAMSIZ zawierają liczbę obecnych stron pamięci RAM. Obrócz tych komórek procedury zarządzania pamięcią w OS utrzymują wskaźniki MEMLO, MEMTOP i APPMHI. Związek pomiędzy nimi pokazuje rys.8-2.
MEMLO jest 2-bajtowym wskaźnikiem używanym przez OS do wskazywania w pamięci początku obszaru, w którym może rozpocząć się program aplikacji. Możesz modyfikować MEMLO, aby stworzyć zarezerwowane obszary na procedury w języku maszynowym, które mogą być wywoływane z poziomu języka BASIC. Język BASIC wykorzystuje MEMLO do określenia początku programu (zobacz do rozdziału "Basic ATARI", gdzie przedyskutowano strukturę programów w języku BASIC). Jeśli wartość MEMLO jest zmieniana na wyższy adres, to musi to być zrobione przed oddaniem kontroli kartridżowi BASIC. Jest to dosyć kłopotliwe zadanie, ponieważ wartość MEMLO jest resetowana przez zimny i gorący start.
Jeśli program aplikacji pracuje w środowisku ze stacją dyskietek, to narzędzie AUTORUN.SYS może zostać użyte do zmiany MEMLO w celu rezerwacji miejsca. Jednakże DOS jest również inicjowany w czasie resetu systemu poprzez wektor DOSINI ($000C), który zawiera adres kodu inicjujacego dyskowy system operacyjny jako część inicjalizacji systemu monitora. DOSINI jest również jedynym miejscem, w którym możesz "przechwycić" sekwencję resetu systemowego. Ponieważ inicjalizacja DOS musi wystąpić bez względu na to, co jest robione ze wskaźnikiem MEMLO, musisz pozwolić na wykonanie normalnej inicjalizacji przed "wykradzeniem" wektora DOSINI. Można tego dokonać przez przeniesienie zawartości DOSINI do 2-bajtowego argumentu instrukcji JSR w AUTORUN.SYS. Tuż po tej instrukcji wstaw kod ustawiający nową wartość w MEMLO. Zakończ kod instrukcją RTS. Następnie w wektorze DOSINI należy umieścić adres tej instrukcji JSR. Gdy wystąpi reset systemu, zostanie wykonana nowa sekwencja kodu i pierwsza instrukcja JSR STARE_DOSINI zainicjuje DOS. Następnie będzie wykonana reszta kodu, która ustawi MEMLO na jego nową wartość i instrukcja RTS połączy ten nowy kod z resztą sekwencji inicjalizacji. Rys.8-3 przedstawia przykład pokazujący, jak to zrobić.
Powyższą technikę można również zastosować z MEMTOP, wskaźnikiem góry pamięci użytkownika. Wskaźnik ten zawiera najwyższy adres w pamięci RAM dostępny dla programu aplikacji. Adres ten różni się od maksymalnego adresu fizycznej pamięci RAM, ponieważ OS przydziela nieco pamięci RAM na samym jej szczycie dla swojej listy wyświetlania i danych ekranowych. Osobne miejsce na moduły w języku asemblera można ustawić przez obniżenie MEMTOP z wartości ustawianej przez zimny i ciepły start. Wykorzystanie MEMTOP zamiast MEMLO do rezerwacji miejsca stwarza jednak jeden problem. Wartość MEMTOP zależy zarówno od ilości RAM w systemie jak i od trybu graficznego obrazu. Trudno jest przewidzieć jego wartość przed rzeczywistym sprawdzeniem tego wskaźnika, chyba że zakładasz określoną konfigurację systemu. Ta niepewność co do ostatecznego położenia kodu maszynowego zmusza programistę do używania tylko kodu przemieszczalnego.
APPMHI wskazuje najniższy adres, do którego może rozciągać się pamięć RAM ekranu. Właściwe ustawienie APPMHI zapewnia, iż sterownik ekranu nie nadpisze części twojego programu lub danych.
RAMSIZ, podobnie jak MEMTOP, może również być wykorzystane do rezerwacji miejsca na procedury lub dane użytkownika. Ponieważ RAMSIZ jest wartością 1-bajtową zawierającą liczbę dostępnych stron RAM (tj, grup 256 bajtów), obniżenie jej o 1 zarezerwuje 256 komórek. Zaletą używania RAMSIZ zamiast MEMTOP jest to, iż obszar zarezerwowany przez obniżenie RAMSIZ znajduje się ponad pamięcią ekranu, natomiast obszar zarezerwowany przez obniżenie wartości MEMTOP pozostaje poniżej pamięci ekranu.
Rys.8-2. Wskaźniki OS i BASIC (DOS obecny)
10 ; RESET WSKAŹNIKA MEMLO 20 ; 30 START = $600 40 DOSINI = $0C 50 MEMLO = $2E7 60 NEWMEM = $3000 ;TO JEST NOWA WARTOŚĆ DLA MEMLO 65 ; 70 ;TA PROCEDURA REZERWUJE MIEJSCE NA PROCEDURY ASEMBLEROWE 90 ;PRZEZ RESETOWANIE WSKAŹNIKA MEMLO. URUCHAMIANA JEST JAKO 0100 ;PLIK AUTORUN.SYS. RESETUJE RÓWNIEŻ MEMLO PO CIEPŁYM STARCIE. 0120 ;MEMLO JEST USTAWIANE NA WARTOŚĆ NEWMEM. 0130 ; 0140 ; TA CZĘŚĆ JEST STAŁA, TZN. MUSI BYĆ REZYDENTNA. 0150 ; WEKTOR SYSTEMOWY ZOSTAJE SKRADZIONY 0160 ; I UMIESZCZONY W CZĘŚCI ADRESOWEJ INSTRUKCJI JSR TROJAN 0170 ; GDY ZOSTANIE NACIŚNIĘTY PRZYCISK [RESET] IS VEKTOR DOSINI WSKAZUJE 0180 ; NA INITDOS, NASTĘPNIE JSR TROJAN WYWOŁUJE INICJALIZACJĘ DOS, 0185 ; RESETUJE MEMLO INA NOWĄ WARTOŚĆ I ZWRACA STEROWANIE 0190 ; DO MONITORA SYSTEMU. 0200 *= START 0210 INITDOS 0220 JSR TROJAN ; WYKONAJ INICJALIZACJĘ DOS 0230 SETMEMLO 0240 LDA #NEWMEM&255 0250 STA MEMLO 0260 LDA #NEWMEM/256 0270 STA MEMLO+1 0280 TROJAN 0290 RTS 0300 ; TA CZĘŚĆ JEST WYKONYWANA TYLKO PRZY ZIMNYM STARCIE, 0310 ; PO CZYM MOŻNA JĄ WYKASOWAĆ. 0320 ; PROCEDURA UMIESZCZA ZAWARTOŚĆ WEKTORA DOSINI W INSTRUKCJI 0330 ; JSR TROJAN. NASTĘPNIE ZASTĘPUJE WEKTOR DOSINI WSKAZANIEM 0340 ; NA ADRES INITDOS. 0350 GRABDOSI 0400 LDA DOSINI ; ZAPAMIĘTAJ DOSINI 0410 STA INITDOS+1 0420 LDA DOSINI+1 0430 STA INITDOS+2 0440 LDA #INITDOS&255 ; USTAW DOSINI 0450 STA DOSINI 0460 LDA #INITDOS/256 0470 STA DOSINI+1 0480 JMP SETMEMLO ; USTAW MEMLO 0530 *= $2E2 0540 .WORD GRABDOSI ; USTAW ADRES STARTOWY 0550 .END |
Rys.8-3. Resetowanie MEMLO
Możliwość wybiórczej odpowiedzi na specjalne zdarzenia sprzętowe i programowe (tj. przerwania) dostarcza olbrzymiej elastyczności każdemu systemowi komputerowemu. Jak w każdym systemie opartym na mikroprocesorze 6502 istnieją dwa rodzaje żądań przerwań na poziomie procesora: przerwania maskowane (IRQ) i niemaskowane (NMI). Wyższy poziom kontroli nad przerwaniami udostępniają układy ANTIC, POKEY i PIA. Każdy z tych układów odpowiada za obsługę pewnej liczby zdarzeń, które mogą spowodować przerwanie. Jeśli określone przerwanie zostało włączone na poziomie tych trzech układów nadzorczych, to pozwalają one następnie na przejście żądania przerwania do mikroprocesora 6502. ANTIC zajmuje się żądaniami przerwań niemaskowanych NMI, a POKEY i PIA obsługują żądania przerwań maskowanych IRQ.
Dostępne są następujące funkcje przerwań:
Nazwa (wektor) | Typ | Funkcja | Używane przez |
---|---|---|---|
LISTA WYŚWIETLANIA (VDSLST) RESET SYSTEMU (brak) WYGASZANIE PIONOWE (VVBLKI,VVBLKD) GOTOWOŚĆ WEJŚCIA SZEREGOWEGO (VSERIN) GOTOWOŚĆ WYJŚCIA SZEREGOWEGO (VSEROR) ZAKOŃCZENIE PRZESYŁANIA SZEREGOWEGO (VSEROC) TIMER 1 POKEY (VTIMR1) TIMER 2 POKEY (VTIMR2) TIMER 4 POKEY (VTIMR4)(*) KLAWIATURA (VKEYBD) KLAWISZ BREAK (BRKKY)(*) DALSZA TRANSMISJA PO MAGISTRALI SZEREGOWEJ (VPRCED) PRZERWANIE Z MAGISTRALI SZEREGOWEJ (VINTER) |
NMI NMI NMI IRQ IRQ IRQ IRQ IRQ IRQ IRQ IRQ IRQ IRQ |
Taktowanie grafiki Inicjalizacja systemu Wyświetlanie grafiki Wejście szeregowe Wyjście szeregowe Wyjście szeregowe Timer sprzętowy Timer sprzętowy Timer sprzętowy Naciśnięcie klawisza Klawisz [BREAK] Kontynuacja pracy urządzenia Przerwanie z urządzenia |
Użytkownika OS OS, użytkownika OS OS OS Użytkownika Użytkownika Użytkownika OS OS Nieużywane Nieużywane |
* To żądanie przerwania IRQ posiada swój wektor tylko wersji B systemu operacyjnego ATARI OS
Rozdział 6 instrukcji systemu operacyjnego zawiera bardziej szczegółowe informacje na temat przerwań. Należy podejmować ekstremalne środki ostrożności przy pracy z przerwaniami. Na przykład, jeśli przypadkowo zablokujesz przerwania IRQ klawiatury, to komputer będzie ignorował wszystkie klawisze za wyjątkiem klawisza [BREAK]. Chociaż może to być czasami użyteczne, to jednak utrudnia debugowanie twojego programu!
System operacyjny posiada sterownik przerwań IRQ, który przetwarza ich różne rodzaje. Sterownik ma wektory w RAM dla wszystkich przerwań IRQ (Zauważ, iż przerwanie IRQ od klawisza [BREAK] nie ma wektora w oryginalnej wersji OS). Wektory są ustawiane na swoje wartości początkowe zarówno przez zimny jak i ciepły start. Adresy tych wektorów podaje następny podrozdział.
Funkcje wektorów IRQ są następujące:
VSEROR – Wektor IRQ Żądania Danych Dla Wyjścia Szeregowego POKEY (ang. Pokey Serial Output Needed IRQ vector). Normalnie wskazuje na kod dostarczający następny bajt z bufora do szeregowego portu wyjściowego.
VSERIN – Wektor IRQ Gotowości Odczytu z Wejścia Szeregowego POKEY (ang. Pokey Serial Input Ready IRQ vector). Wskazuje na kod, który umieszcza w buforze bajt z wejścia portu szeregowego.
VSEROC – Wektor IRQ Zakończenia Transmisji Szeregowej POKEY (ang. Pokey Serial Output Complete IRQ vector). Normalnie wektor ten wskazuje kod, który ustawia znacznik zakończenia transmisji po wysłaniu bajtu z sumą kontrolną.
VTIMR1 – Wektor IRQ Timera 1 POKEY (ang. Pokey Timer 1 IRQ vector). Inicjowany na wskazywanie sekwencji instrukcji PLA, RTI.
VTIMR2 – Wektor IRQ Timera 2 POKEY (ang. Pokey Timer 2 IRQ vector). Inicjowany na wskazywanie sekwencji instrukcji PLA, RTI.
VTIMR4 – Wektor IRQ Timera 4 POKEY (ang. Pokey Timer 4 IRQ vector). Inicjowany na wskazywanie sekwencji instrukcji PLA, RTI.
VKEYBD – Wektor IRQ Klawiatury (ang. Keyboard IRQ vector). Przerwanie to jest powodowane przez naciśnięcie dowolnego klawisza za wyjątkiem [BREAK]. VKEYBD można wykorzystywać do wczesnego przetwarzania kodów klawiszy zanim zostaną zamienione na ATASCII przez OS. VKEYBD normalnie wskazuje na procedurę obsługi klawiaturowego IRQ w OS.
BRKKY – Wektor klawisza [BREAK] (ang. [BREAK] key vector). W wersji B systemu operacyjnego to przerwanie IRQ posiada własny wektor. Inicjowany na wskazywanie sekwencji instrukcji PLA, RTI.
VPRCED – Wektor przerwania IRQ do rozpoczęcia transmisji przez urządzenie peryferyjne (ang. Peripheral Proceed IRQ vector). Linia rozpoczęcia dostępna jest dla urządzeń peryferyjnych na magistrali szeregowej. Przerwanie nie jest obecnie wykorzystywane i normalnie wektor ten wskazuje sekwencję instrukcji PLA, RTI.
VINTER – Wektor przerwania IRQ z urządzenia peryferyjnego (ang. Peripheral interrupt IRQ vector). Linia przerwania jest również dostępna na magistrali szeregowej. VINTER normalnie wskazuje sekwencję instrukcji PLA, RTI.
VBREAK – Wektor iIRQ nstrukcji BRK mikroprocesora 6502 (ang. 6502 BRK instruction IRQ vector). Przerwanie to występuje zawsze po napotkaniu przez mikroprocesor instrukcji BRK (przerwanie programowe). VBREAK może być wykorzystany do ustawiania punktów przerwań dla debuggera, chociaż normalnie wskazuje sekwencję instrukcji PLA, RTI.
Przerwania IRQ są włączane i wytłaczane grupowo odpowiednio przez instrukcje CLI i SEI mikroprocesora 6502. Przerwania posiadają również indywidualne bity włączania/wyłączania w układzie POKEY.
Rejestr IRQEN zawiera większość bitów sterujących włączaniem/wyłączaniem przerwań IRQ i jest rejestrem tylko do zapisu.
OS utrzymuje kopię rejestru IRQEN w pamięci RAM w POKMSK ($0010), lecz IRQEN nie jest uaktualniany z POKMSK podczas wygaszania pionowego. Każde przerwanie jest włączane przez ustawienie na jeden odpowiedniego bitu w IRQEN. Zero jest umieszczane w bicie w IRQEN w celu wyczyszczenia stanu przerwania w odpowiednim bicie w IRQST. Możesz zauważyć, iż bit 3 w IRQST (zakończenie transmisji szeregowej) nie jest zerowany przez ten proces. Ten bit jest po prostu bitem stanu, który odzwierciedla bieżący stan rejestru transmisji szeregowej.
Rejestry PACTL i PBCTL są wykorzystywane do włączania przerwań IRQ obsługiwanych przez układ PIA i do testowania ich stanu. Bit 0 każdego z tych rejestrów włącza przerwanie z danego portu. Bit 7 reprezentuje stan przerwania. Bit ten jest zerowany po odczycie rejestru PACTL lub PBCTL.
Dostępność wektorów IRQ oznacza, iż możesz przystosować dużą część systemowych operacji wejścia/wyjścia do swoich potrzeb. Bieżąco system operacyjny nie wspiera wykonywania operacji we/wy współbieżnie z innym przetwarzaniem. Jednakże przez zmianę trzech wektorów przerwań z szeregowego we/wy jest możliwe ponowne napisanie części podsystemu we/wy, aby możliwe było przetwarzanie współbieżne.
Trzy przerwania timerów mogą być użyte w każdej operacji wymagającej precyzyjnej kontroli czasu. Timery te normalnie są używane w sytuacji, gdy 60-hercowe timery programowe są zbyt wolne. Więcej informacji na ten temat znajdziesz w podrozdziale "Przetwarzanie w czasie rzeczywistym".
Wiele aplikacji wymaga, aby programy były zabezpieczone przed błędami wejściowymi użytkownika. Kilka wektorów IRQ można użyć do zapewnienia takiej poszerzonej ochrony. Poniższy przykład programu używa wektora IRQ VKEYBD do wyłączenia klawisza [CONTROL]. Procedura również maskuje klawisz [BREAK] przez podmianę wektora VIMIRQ i ignorowanie przerwania z klawisza [BREAK]. Chociaż procedurę napisano dla oryginalnej wersji OS, to będzie działała również z wersją B.
Dwa przerwania IRQ są obsługiwane przez układ PIA, VPRCED i VINTER. System operacyjny ich nie używa i można je zagospodarować w celu uzyskania większej kontroli nad urządzeniami zewnętrznymi.
10 POKMSK = 0010 20 KBCODE = $D209 30 VKEYBD = $0208 40 IRQEN = $D20E 45 IRQST = IRQEN 46 VMIRQ = $0216 60 *= $600 80 START SEI ; WYŁĄCZ PRZERWANIA IRQ 90 LDA VMIRQ ;PODMIEŃ WEKTORY IRQ 0100 STA NBRK+1 ;NASZYMI WŁASNYMI 0110 LDA VMIRQ+1 ;WSZYSTKIE IRQS 0120 STA NBRK+2 ;PRZEJDĄ DO NBRK 0130 LDA #IRQ&255 0140 STA VMIRQ 0150 LDA #IRQ/256 0160 STA VMIRQ+1 0170 CLI ;WŁĄCZ PRZERWANIA IRQ 0200 LDA VKEYBD ;USTAW IRQ KLAWISZA 0210 STA JUMP+1 ;NA REP 0220 LDA VKEYBD+1 0230 STA JUMP+2 0240 LDA #REP&255 ;USTAW WEKTOR IRQ KLAWISZA 0250 STA VKEYBD ;DOLNY BAJT WEKTORA 0260 LDA #REP/256 0270 STA VKEYBD+1 0280 RTS 0290 *=$639 0300 REP LDA KBCODE ;WSZYSTKIE PRZERWANIA IRQ KLAWISZY IDĄ TUTAJ 0310 AND #$80 ;SPRAWDŹ, CZY NACIŚNIĘTO KLAWISZ CONTROL 0320 BEQ JUMP ;JEŚLI NIE, IDŹ DALEJ 0330 PLA ;INACZEJ IGNORUJ KLAWISZ CONTROL 0340 RTI 0360 JUMP JMP ;TO WYWOŁA STARE IRQ KLAWISZA 0375 IRQ PHA ;WSZYSTKIE IRQ PRZYCHODZĄ TUTAJ 0380 LDA IRQST ; SPRAWDŹ KLAWISZ [BREAK] 0390 BPL BREAK ; JEŚLI [BREAK] NACIŚNIETY, PRZEJDŹ DALEJ 0405 PLA ; INACZEJ WYWOŁAJ STARY WEKTOR IRQ 0410 NBRK JMP NBRK ; WYWOŁAJ STARY WEKTOR IRQ 0430 BREAK LDA #$7F ; TUTAJ PO [BREAK] 0440 STA IRQST ; KASUJ [BREAK] 0450 LDA POKMSK 0460 STA IRQEN 0462 PLA 0464 RTI ; WRÓĆ JAKBY NIE BYŁO [BREAK] 0470 *= $02E2 0480 .WORD START |
Rys.8-4. Ochrona programów przed błędami wejściowymi użytkownika
System operacyjny posiada sterownik przerwań NMI do obsługi przerwań niemaskowanych. W przeciwieństwie do przerwań IRQ przerwania NMI nie mogą być "maskowane" (wyłączane) na poziomie mikroprocesora 6502. Wszystkie przerwania NMI z wyjątkiem resetu systemu mogą zostać zablokowane przez układ ANTIC.
Dwa przerwania NMI, przerwanie z listy wyświetlania (DLI) oraz przerwanie przy wygaszaniu pionowym (VBLANK), posiadają wektory w pamięci RAM i można je wykorzystać. W rzeczywistości VBLANK można przechwycić w dwóch miejscach jako natychmiastowe i końcowe VBLANK. Wektory NMI są następujące:
Nazwa | Wektor |
---|---|
RESET SYSTEMU PRZERWANIE Z LISTY WYŚWIETLANIA WYGASZANIE PIONOWE POCZĄTKOWE KOŃCOWE |
brak VDSLST ($0200) VVBLKI ($0222) VVBLKD ($0224) |
Przerwanie NMI przy resecie systemu nie posiada wektora w pamięci RAM. Reset systemu zawsze skutkuje skokiem do procedury ciepłego startu w monitorze. Jednakże podczas procesu ciepłego startu wykorzystywany jest wektor w RAM DOSINI, co pozwala przechwycić reset systemu (zobacz do podrozdziału "Monitor").
Wektor DLI nie jest używany przez OS. Zobacz do rozdziału 5, "Przerwania z listy wyświetlania".
Funkcja przerwań przy wygaszaniu pionowym jest bardzo cennym zasobem dla programisty. Przerwania te są niemaskowane i występują w regularnych odstępach czasu zależnych od używanego standardu telewizyjnego (co 1/60 sekundy w systemie NTSC i co 1/50 sekundy w systemie PAL). Ważne jest również to, iż przerwania występują podczas okresu czasu, gdy ekran został wygaszony, zatem zmiany wykonane w tym okresie nie będą natychmiast widoczne na ekranie. To prowadzi do szerokiego wachlarza zastosowań.
Gdy system operacyjny rozpozna przerwanie od wygaszania pionowego, umieszcza on zawartość rejestrów A, X i Y na stosie. Następnie system wykonuje skok poprzez natychmiastowy wektor wygaszania pionowego (VVBLKI) umieszczony pod adresem $0222. Wektor ten normalnie prowadzi do systemowej procedury obsługi przerwania od wygaszania pionowego pod adresem ROM $E45F. OS używa tej procedury do zwiększania stanu zegara czasu rzeczywistego, zmniejszania timerów systemowych, do wykonania zmiany kolorów w trybie przyciągania uwagi (oszczędzanie monitora), do skopiowania rejestrów w RAM i do uaktualnienia wartości z kontrolerów gier. Procedura kończy się skokiem poprzez wektor końcowego wygaszania pionowego (VVBLKD) umieszczony pod adresem $0224. Wektor ten jest inicjowany na wskazywanie adresu w ROM $E462, gdzie znajduje się procedura kończenia przerwania przy wygaszaniu pionowym. Rys.8-5 ilustruje ten proces.
Rys.8-5. Wykonanie przerwania od
wygaszania pionowego
Te dwa wektory zostały umieszczone w pamięci RAM, aby umożliwić programistom przechwycenie procedury obsługi przerwania od wygaszania pionowego i użycie tego przerwania 60Hz do własnych celów. Procedura użycia ich jest prosta. Najpierw zdecyduj, czy twoja procedura obsługi przerwania VBI ma być początkowa lub końcowa. W wielu przypadkach nie ma to znaczenia. Jednakże czasem ma znaczenie. Pierwszy taki przypadek występuje, gdy twoja procedura VBI czyta lub zapisuje do rejestrów, które mają kopie w RAM obsługiwane przez procedurę VBI w OS. Może być konieczny zapis do rejestrów sprzętowych po tym, jak procedura VBI w OS wykonała swój zapis do nich. Ten, który zapisuje ostatni, zapisuje najlepiej!
Drugi przypadek występuje, gdy twoja procedura VBI pochłania zbyt wiele czasu przetwarzania. Wtedy procedura VBI w OS może zostać opóźniona poza koniec okresu wygaszania pionowego. To z kolei może spowodować zmianę niektórych rejestrów graficznych, gdy strumień elektronów przebiega po powierzchni ekranu. Wynik może być nieprzewidywalny. Jeśli tak jest, to twoja procedura VBI powinna być umieszczona przy końcu VBI. Ograniczeniem dla początkowej procedury VBI jest około 2000 taktów maszynowych, natomiast dla końcowej procedury VBI granica ta wynosi około 20.000 taktów. Jednakże wiele z tych 20,000 taktów maszynowych jest wykonywane, gdy strumień elektronu rysuje już obraz po ekranie, zatem operacje graficzne nie powinny być wykonywane w bardzo długich procedurach końcowych VBI. Co więcej wykonywanie przerwań z listy wyświetlania opóźnia się w czasie. Pamiętaj, przetwarzanie VBI obetnie czas przeznaczony na wykonywanie głównego kodu.
Trzeci przypadek powstaje, gdy twoje własne VBI musi mieszać się z krytycznymi czasowo operacjami we/wy, takimi jak dostęp do kasety lub do dysku. Początkowa procedura VBI posiada dwa etapy: krytyczny i niekrytyczny. Podczas operacji we/wy krytycznych czasowo początkowa procedura VBI w OS kończy się po etapie pierwszym. Jeśli chcesz, aby twoja procedura VBI była wykonywana przy każdym okresie wygaszania pionowego, to musi być zdefiniowana jako początkowe VBI. Bądź jednak czujny w tej sytuacji, ponieważ może to stworzyć problemy interferencji z krytycznymi czasowo operacjami we/wy.
Gdy już zdecydujesz, czy twoja procedura VBI ma być początkową lub końcową, musisz ją umieścić w pamięci (strona szósta jest dobrym miejscem), połączyć ją z właściwą procedurą VBI i zmodyfikować odpowiedni wektor w RAM, aby na nią wskazywał. Procedurę początkową zakończ skokiem pod adres $E45F. Procedurę końcową VBI zakończ skokiem pod adres $E462. Jeśli chcesz zupełnie pominąć systemową procedurę VBI (zyskując w ten sposób więcej czasu na przetwarzanie), zakończ swoją początkową procedurę VBI skokiem pod adres $E462.
Typowy problem z przerwaniami na 8-bitowych mikrokomputerach powstaje, gdy próbujesz zmieniać wektor do przerwania. Wektory są obiektami 2-bajtowymi; ich zmiana zabiera dwie instrukcje zapisu do pamięci. Istnieje mała szansa, iż przerwanie wystąpi po zmianie pierwszego bajtu, lecz przed załadowaniem drugiego bajtu. Może to doprowadzić do zawieszenia się systemu. Rozwiązaniem tego problemu jest systemowa procedura SETVBV pod adresem $E45C. Załaduj rejestr Y mikroprocesora 6502 dolnym bajtem adresu, rejestr X górnym bajtem adresu, a akumulator liczbą 6 dla początkowej VBI lub 7 dla końcowej VBI. Następnie wykonaj instrukcję JSR SETVBV i przerwanie zostanie bezpiecznie włączone. Nowa procedura VBI zacznie się wykonywać w ciągi 1/60 sekundy.
Duża ilość różnorodnych operacji może być wykonywana przy pomocy przerwań 60-hercowych. Po pierwsze operacje ekranowe mogą być wykonywane podczas wygaszania pionowego w celu zapewnienia, iż zmiany te nie będą widoczne na ekranie. Po drugie można wykonywać regularne operacje ekranowe z dużą prędkością. Może to być bardzo ważne w rytmicznych animacjach, gdzie zmiany muszą być wykonywane w tempie niezależnym od innego przetwarzania.
Inną funkcją przerwań od wygaszania pionowego są efekty dźwiękowe w czasie rzeczywistym. Rejestry dźwiękowe w ATARI 400/800 pozwalają kontrolować częstotliwość, głośność i zniekształcenie, lecz nie czas trwania dźwięku. Długość dźwięku można kontrolować przy pomocy VBI przez ustawienie w procedurze wywołującej parametru związanego z długością, który następnie procedura VBI zmniejsza o 1 aż do zera. Ta technika może być użyta do sterowania głośnością dźwięku nadając mu odpowiednią obwiednię. Precyzyjna kontrola częstotliwości i zniekształcenia jest również możliwa poprzez rozszerzenie tej techniki. W efekcie można otrzymać bardzo zawiłe efekty dźwiękowe. Ponieważ czasowa rozdzielczość VBI wynosi tylko 1/60 sekundy, przerwania VBI nie nadają się do sterowania jedynie głośnością kanałów dźwiękowych.
Przerwania VBl są również użyteczne do obsługi danych wejściowych od użytkownika. Zwykle te dane wymagają niewiele przetwarzania, lecz ciągłej uwagi. VBI pozwala sprawdzać dane użytkownika co 1/60 sekundy bez niepokojenia programu głównego. Jest to idealne rozwiązanie dla utrzymania ciągłości obliczeniowej bez ignorowania użytkownika.
Na koniec VBI pozwalają na prostą formę przetwarzania współbieżnego. Program pierwszoplanowy pracuje pod kontrolą VBI, natomiast program w tle pracuje w kodzie głównym. Jak z każdym przerwaniem należy utrzymać dokładną separację przetwarzanych danych w obu programach. Jednakże pożytek z przerwania pionowego wygaszania jest tak duży, iż warte to jest zachodu.
Jedną z miar potęgi systemu operacyjnego jest jego przystosowalność. Jak łatwo jest użytkownikowi skorzystać z procedur OS lub zmodyfikować i przystosować procedury systemowe?
W tym względzie system operacyjny komputera domowego ATARI osiąga wysokie noty. W praktycznie każdym przypadku, w którym dostęp do procedur systemowych byłby korzystny, OS posiada "haczyki", gdzie możesz dołączyć się do procedur systemowych lub je zastąpić swoimi własnymi.
Ta elastyczność udostępniana jest przez kombinację kilku różnych mechanizmów. Pierwszym z nich jest tablica w ROM zawierająca instrukcje skoków JMP do najważniejszych procedur OS. W przyszłych wersjach OS położenie tej tablicy skoków nie ulegnie zmianie, chociaż jej wartości prawdopodobnie tak. Dlatego, jeśli twoje oprogramowanie uzyskuje dostęp do głównych procedur OS poprzez tą tablicę, to będzie ono również pracowało na przyszłych wersjach OS. Jeśli natomiast twoje oprogramowanie nie używa tych wektorów w ROM, lecz zamiast tego skacze bezpośrednio do OS ROM, to prawie na pewno ulegnie awarii po uruchomieniu w przyszłej wersji OS.
Drugim mechanizmem jest ciąg wektorów adresowych w RAM, które prowadzą do wielu procedur przetwarzających przerwania. Aby zmienić sposób obsługi określonego przerwania, należy jedynie zmienić pojedynczy wektor, tak aby wskazywał na nowy kod. OS inicjuje te wektory w sekwencji uruchamiania komputera. Ponownie, chociaż inicjowana zawartość tych wektorów może się zmieniać, to jednak ich położenie nie.
Trzecim mechanizmem jest tablica sterowników urządzeń, w której przechowywane są wektory do specyficznych sterowników (np. stacji dysków, drukarki, ...). Więcej informacji na ten temat znajdziesz dalej w tym rozdziale.
Nazwa | Adres | Użycie |
---|---|---|
DISKIV DSKINV CIOV SIOV SETVBV SYSVBV XITVBV SIOINV SENDEV INTINV CIOINV BLKBDV WARMSV COLDSV RBLOKV CSOPIV |
$E450 $E453 $E456 $E459 $E45C $E45F $E462 $E465 $E468 $E46B $E46E $E471 $E474 $E477 $E47A $E47D |
Inicjalizacja sterownika dysku Wektor sterownika dysku Wektor centralnej procedury we/wy Wektor procedury szeregowego we/wy Wektor procedury ustawiania timerów systemowych Systemowe przetwarzanie wygaszania pionowego Wyjście z przetwarzania wygaszania pionowego Inicjalizacja szeregowego we/wy Procedura uaktywnienia przesyłu po magistrali szeregowej Procedura sterownika przerwań Inicjalizacja centralnego we/wy Wektor trybu Blackboard (Memopad) Punkt wejścia do ciepłego startu (RESET SYSTEMU) Punkt wejścia do zimnego startu (włączanie zasilania) Wektor procedury odczytu bloku z kasety Wektor otwarcia kasety do odczytu |
Rys.8-6 Wektory skoków w ROM
Ponieważ ta tablica w ROM jest w rzeczywistości zbudowana z 3-bajtowych instrukcji skoku JMP, to przykładowe użycie wektora w ROM wygląda następująco:
JSR CIOV
Nazwa | Adres | Wartość | Użycie |
---|---|---|---|
-- Adresy na stronie drugiej -- | |||
VDSLST VPRCED VINTER VBREAK VKEYBD VSERIN VSEROR VSEROC VTIMR1 VTIMR2 VTIMR4 VIMIRQ VVBLKI VVBLKD CDTMA1 CDTMA2 BRKKY |
$0200 $0202 $0204 $0206 $0208 $020A $020C $020E $0210 $0212 $0214 $0216 $0222 $0224 $0226 $0228 $0236 |
$E7B3 $E7B3 $E7B3 $E7B3 $FFBE $EB11 $EA90 $EAD1 $E7B3 $E7B3 $E7B3 $E6F6 $E7D1 $E93E $xxxx $xxxx $E754 |
Wektor przerwania NMI od listy wyświetlania Wektor IRQ linii kontynuacji -- obecnie nieużywany Wektor IRQ linii przerwania -- obecnie nieużywany Wektor IRQ przerwania programowego instrukcją BRK Wektor IRQ klawiatury Wektor IRQ gotowości wejścia szeregowego Wektor IRQ gotowości wyjścia szeregowego Wektor IRQ zakończenia nadawania szeregowego Wektor IRQ Timera 1 układu POKEY Wektor IRQ Timera 2 układu POKEY Wektor IRQ Timera 4 układu POKEY Wektor do sterownika IRQ Wektor NMI początku wygaszania pionowego Wektor końca wygaszania pionowego Adres JSR Timera systemowego 1 Adres JSR Timera systemowego 2 Wektor klawisza BREAK (** tylko wersja B **) |
-- Adresy na stronie zerowej -- | |||
CASINI DOSINI DOSVEC RUNVEC INIVEC |
$0002 $000C $000A $02E0 $02E2 |
$xxxx $xxxx $xxxx $xxxx $xxxx |
Wektor inicjalizacyjny programu startowego z kasety Wektor inicjalizacji dysku Wektor uruchamiania oprogramowania dyskowego Wektor ładowania i uruchamiania pliku DUP Wektor inicjalizacji ładowania i uruchamiania pliku DUP |
Literka x oznacza, iż zawartość tego adresu może ulegać zmianie
Rys.8-7 Wektory w pamięci RAM
W przeciwieństwie do tablicy skoków w ROM wektory w RAM są prawdziwymi 2-bajtowymi wektorami adresowymi. Typowy ciąg wywołania jednego z wektorów w RAM może wyglądać następująco:
JSR CALL
CALL JMP (DOSINI)
Jednym z najbardziej wymagających problemów stojących przed projektantem systemu operacyjnego jest określenie sposobu obsługi dużej liczby różnorodnych urządzeń we/wy, które mogą zostać podłączone do tego systemu. Oto kilka ogólnych, filozoficznych wskazówek efektywnej obsługi we/wy:
System operacyjny komputera domowego ATARI 400/800 (OS) został zaprojektowany dokładnie wg powyższych wskazówek. OS ATARI wykorzystuje sterowany tablicą scentralizowany podsystem we/wy. Z punktu widzenia OS we/wy jest zorganizowane wokół tzw. IOCB (ang. Input/Output Control Block – Blok sterujący we/wy). IOCB jest ustandaryzowaną tablicą, która określa jedną kompletną operację wejścia lub wyjścia. Poprzez blok IOCB można wykonać dowolną z ośmiu operacji we/wy. Poprzez zmianę zawartości elementu IOCB użytkownik może zmienić naturę operacji we/wy, a nawet fizyczne urządzenie, które jest celem we/wy.
W ten sposób użytkownik może z łatwością wykonywać operacje we/wy na zupełnie różnych urządzeniach takich jak stacja dysków i drukarka bez zawracania sobie głowy szczegółami sprzętowymi. Większość operacji we/wy wymaga jedynie od użytkownika wpisania do bloku IOCB odpowiednich danych kontrolnych, a następnie przekazanie kontroli do podsystemu we/wy.
Podsystem we/wy tworzą dwa rodzaje elementów: systemowe procedury we/wy i systemowe bloki kontrolne we/wy. Systemowe procedury we/wy zawierają centralną procedurę we/wy (CIO), sterowniki urządzeń (E:, K:, S:, P:, C:, D:, R:) oraz procedurę szeregowego we/wy (SIO).
Tablica adresów sterowników (HATABS) odgrywa główną rolę w połączeniu CIO z poszczególnymi sterownikami urządzeń. Systemowe bloki kontroli we/wy zawierają dane sterujące, które skierowane są do podsystemu we/wy. Interfejs użytkownika jest taki sam dla wszystkich urządzeń (np. rozkazy wysłania wiersza znaków na drukarkę P: lub na ekran edytora E: są bardzo podobne).
Zrozumienie struktury podsystemu we/wy pozwoli ci go lepiej wykorzystywać we własnych aplikacjach. Na rys.8-8 pokazano związek pomiędzy systemowymi procedurami we/wy a systemowymi blokami kontrolnymi we/wy.
Rys.8-8 Podsystem we/wy
Jest cztery rodzaje bloków sterujących:
Bloki sterujące we/wy są wykorzystywane do przesyłania informacji o funkcji we/wy, która ma zostać wykonana. Bloki kontrolne dostarczają systemowym procedurom we/wy informacji kontrolnej do wykonania danej funkcji we/wy. Opis szczegółowej struktury tych czterech typów bloków sterujących znajdziesz w instrukcji do systemu operacyjnego.
Do realizowania komunikacji pomiędzy programami użytkownika a CIO wykorzystywane jest osiem bloków IOCB. Rys.8-9 przedstawia zawartość bloku IOCB dla niektórych typowych funkcji we/wy. Bloki IOCB są następujące:
Nazwa | Adres,długość |
IOCB0 | [$340,16 |
IOCB1 | [$350,16] |
IOCB2 | [$360,16] |
IOCB3 | [$370,16] |
IOCB4 | [$380,16] |
IOCB5 | [$390,16] |
IOCB6 | [$3A0,16] |
IOCB7 | [$3B0,16] |
Drugi rodzaj bloku sterującego, ZIOCB [$0020,16], jest używany do wymiany danych sterującyĉh we/wy pomiędzy CIO a sterownikami urządzeń. Po wywołaniu CIO używa wartości zawartej w rejestrze X jako indeksu do wybranego bloku IOCB, który ma zostać użyty. Następnie CIO przenosi dane sterujące z wybranego bloku IOCB do bloku ZIOCB do użytku przez odpowiedni sterownik urządzenia. Blok ZIOCB ma dla ciebie małe znaczenie, chyba że właśnie piszesz kod nowego sterownika urządzenia lub zastępujesz bieżący sterownik innym.
Sterowniki urządzeń wymagające transmisji we/wy poprzez magistralę szeregową ładują następnie informacje sterujące do bloku DCB [$0300,12]. SIO wykorzysta informację w DCB i zwróci w DCB informację o statusie ostatniego wykorzystania bloku przez sterownik urządzenia. Rys.8-10 ilustruje niektóre typowe funkcje we/wy oraz zawartość powiązanych z nimi bloków DCB.
Rezydentny sterownik dysków nie podpada pod normalną sekwencję wywołań CIO. Zamiast tego używa się bloku DCB do bezpośredniej komunikacji z tym sterownikiem. Więcej informacji znajdziesz w rozdziale 9 "Dyskowy system operacyjny".
Ostatnim rodzajem bloku sterującego spotykanego w podsystemie we/wy jest bufor ramki rozkazu (ang. Command Frame Buffer, CFB). Jest to 4-bajtowa tablica pod adresem $023A, którą wykorzystuje procedura SIO podczas wykonywania operacji na magistrali szeregowej. Te cztery bajty zawierają kod urządzenia, kod rozkazu oraz bajty pomocnicze rozkazu 1 i 2. Przesyłany bufor danych jest zdefiniowany przez dwa wskaźniki BUFRLO [$0032,2] i BFENLO [$0034,2]. Ogólnie nie jest zalecane używanie systemu operacyjnego na tak niskim poziomie. Inne parametry muszą być ustawiane i należy podjąć szczególne starania, aby został wywołany właściwy ciąg podprogramów. CIO i SIO zostały zaprojektowane, tak aby łatwo można je było wywoływać z programu użytkownika. Używaj ich — lecz trzymaj się z dlala od bufora ramki rozkazu!
WYWOŁANIE | ICHID | ICDNO | ICCOM | ICSTA | ICBAL | ICBAH | ICPTL | ICPTH | ICBLL | ICBLH | ICAX1 | ICAX2 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
OTWARCIE PLIKU DO ODCZYTU OTWARCIE PLIKU DO ZAPISU ODCZYT BAJTÓW ZAPIS BAJTÓW ODCZYT REKORDU ZAPIS REKORDU ZAMKNIĘCIE PLIKU STATUS |
X X X X X X X X |
X X X X X X X X |
3 3 7 $B 5 9 $C $D |
(1) (1) (1) (1) (1) (1) (1) (1) |
$80 $80 00 00 00 00 X X |
06 06 06 06 06 06 X X |
X X X X X X X X |
X X X X X X X X |
X X $80 $80 $80 $80 X X |
X X 00 00 00 00 X X |
4 8 X X X X X X |
0 (2) X X X X X X |
Rys.8-9 Blok sterujący wejścia/wyjścia (IOCB)
FUNKCJA | NAZWA | ADRES | STACJA DYSKÓW 810/815 | ZAPIS NA DRUKARKĘ 820 |
|||||
---|---|---|---|---|---|---|---|---|---|
ODCZYT SEKTORA | ZAPIS SEKTORA | ZAPIS | FORMAT | ||||||
810 | 815 | 810 | 815 | ||||||
Numer magistrali szeregowej Numer urządzenia Bajt rozkazu Status Adres bufora Przekroczenie czasu operacji Długość bufora |
DDEVIC DUNIT DCOMND DSTATS DBUFLO DBUFHI DTIMLO DBYTLO DBYTHI DAUX1 DAUX2 |
[$0300] [$0301] [$0302] [$0303] [$0304] [$0305] [$0306] [$0308] [$0309] [$030A] [$030B] |
$30 1-4 $52 $40 U U $30 $80 $00 2* 2* |
$30 1-8 $52 $40 U U $30 00 01 2* 2* |
$30 1-4 $57 $80 U U $30 $80 $00 2* 2* |
$30 1-8 $57 $80 U U $30 00 01 2* 2* |
$30 1-4 $50 $80 U U $31 $80/00 $00/01 - 2* - 2* |
$30 1-4 $21 $40 U U $130 - - - - |
$30 1 $57 $80 U U 5 $40 $00 1* 1* |
1* = Te bajty określają tryb drukarki (zobacz
do instrukcji 820l). 2* = DAUX1 + DAUX2 określają sektor do ODCZYTU, ZAPISU lub WERYFIKACJI. U = Oznacza adres ustawiony przez użytkownika. - = Oznacza wartość ignorowaną |
Rys.8-10 Blok sterujący urządzenia (DCB)
Główną funkcją CIO jest pobranie danych sterujących z IOCB i upewnienie się, iż trafią one do właściwego sterownika urządzenia, a następnie przekazanie sterowania do tego sterownika. Cio działa również jako kolejka dla większości operacji we/wy w systemie. Większość funkcji systemowych we/wy wykorzystuje CIO jako wspólny punkt wejścia, a wszystkie sterowniki wychodzą do systemu poprzez CIO. Na przykład BASIC wywoła CIO przy wykonywaniu polecenia OPEN lub GRAPHICS. CIO wspiera następujące funkcje
OPEN CLOSE GET CHARS READ RECORD PUT CHARS WRITE RECORD STATUS SPECIAL |
Otwieranie urządzenia/pliku Zamykanie urządzenia/pliku Odczyt N znaków Odczyt następnego rekordu Zapis N znaków Zapis następnego rekordu Pobranie stanu urządzenia Działanie specyficzne dla sterownika (np. NOTE dla FMS) |
Możesz wykonywać własne wysołania CIO. Sekwencja wywołania CIO jest następująca:
;Użytkownik ustawił już IOCB LDX #IOCBNUM ;Ustaw indeks IOCB (IOCB * 16) JSR CIOV ;Wektor systemowej procedury do CIO BMI ERROR ;Jeśli zostanie wykonany skok, to CIO zwróciło ;kod błędu w rejestrze Y |
Jak pokazano w powyższym wywołaniu, jeden z bloków IOCB jest używany do przekazywania danych sterujących do CIO. Możesz do tego celu użyć dowolnego z ośmiu bloków IOCB. CIO oczekuje indeksu tego bloku IOCB w rejestrze X. Zapamiętaj, iż wartość ta musi być równa numerowi bloku IOCB pomnożonemu przez 16. Powodem jest to iż CIO wykorzystuje ten indeks do adresowania zawartości różnych IOCB, a każdy z nich ma długość 16 bajtów. Przy powrocie bit znaku w rejestrze stanu mikroprocesora 6502 jest odpowiednio ustawiany do oznaczenia sukcesu lub błędu w operacji we/wy. Jeśli bit N jest wyzerowany, to operacja we/wy powiodła się, a rejestr Y będzie zawierał wartość 1. Jeśli bit N jest ustawiony, to żądanie we/wy dało w wyniku błąd i w takim wypadku rejestr Y będzie zawierał kod tego błędu. Typowym sposobem testowania wyniku operacji we/wy jest użycie instrukcji skoku warunkowego przy minusie (przy ustawionym bicie znaku N) do procedury obsługi błędu. Wartość sukcesu/błędu jest również zwracana w bajcie ICSTA bloku IOCB (zobacz na definicję IOCB). Rozdział 5 instrukcji systemu operacyjnego zawiera przykładowy fragment programu, który wywołuje CIO do otwarcia pliku na dysku, odczytania kilku rekordów, a następnie zamknięcia tego pliku.
CIO kopiuje dane sterujące z wybranego bloku IOCB do bloku ZIOCB na stronie zerowej. Następnie CIO określa punkt wejścia sterownika urządzenia i wykonuje skok poprzez wektor do odpowiedniej procedury sterownika. Rysunek 8-11 przedstawia przebieg systemowej procedury CIO.
Rys.8-11.1 Procedura CIO
Rys.8-11.2 Procedura CIO
CIO oblicza adres punktu wejścia do sterownika urządzenia w sposób pośredni. Przede wszystkim wywołanie OPEN musi poprzedzać wszystkie inne funkcje we/wy związane z danym urządzeniem. Podczas przetwarzania rozkazu OPEN CIO pobiera specyfikację urządzenia dla otwieranego pliku. Specyfikacja ta jest łańcuchem ATASCII wskazywanym przez część adresu bufora w IOCB. Pierwszym elementem tego łańcucha musi być jednoliterowy identyfikator urządzenia (np. 'D' dla stacji dysków, 'P' dla drukarki, ...). Następnie CIO szuka tego znaku w tablicy punktów wejścia sterowników HATABS, która jest w pamięci pod adresami od $031A do $033B (Rys.8-12 pokazuje układ HATABS). CIO rozpoczyna poszukiwania od spodu HATABS i kontynuuje je w górę aż zostanie znaleziona zgodność z identyfikatorem urządzenia. Poszukiwanie jest wykonywane w tym kierunku, aby ułatwić dodawanie lub modyfikację sterowników urządzeń. Podczas wykonywania kodu inicjalizującego tablica HATABS jest kopiowana z ROM do RAM. Urządzenia, które są później inicjowane (np. stacja dysków lub moduł RS-232) dodają informację o swoich sterownikach na spód tej tabeli. W tabeli jest miejsce na 14 elementów, z których 5 zostaje ustawionych podczas inicjalizacji systemu. Jeśliby później został dodany na spodzie tabeli jakiś nowy sterownik drukarki, to CIO znalazłoby go przed znalezieniem sterownika skopiowanego z ROM. Pozwala to nowym sterownikom zastępować stare.
Po zlokalizowaniu identyfikatora urządzenia CIO wie, że następne dwa bajty są adresem wskazującym tablicę punktów wejścia do procedur sterownika tego urządzenia. Jest to tablica adresów procedur, które obsługują każdą z funkcji CIO. Rys.8-13 podaje układ typowej tablicy punktów wejścia.
Aby określić punkt wejścia sterownika, do którego należy skoczyć poprzez wektor, CIO wykorzystuje ICCOM, czyli bajt rozkazu w bloku IOCB, jako indeks w tablicy wejść. Tablice punktów wejścia wszystkich rezydentnych sterowników można znaleźć na listingu systemu operacyjnego. Względne położenie każdego z wektorów w tablicy wejść ma takie same znaczenie we wszystkich tych tablicach. Na przykład pierwszy wpis we wszystkich tablicach punktów wejścia jest wektorem do procedury OPEN sterownika urządzenia.
Możesz skorzystać z elastyczności tablicy HATABS w celu dodania kilku nowych cech do systemu operacyjnego. Rys.8-14 pokazuje przykładowe dodanie sterownika urządzenia pustego NULL. Sterownik urządzenia pustego robi to, co sugeruje jego nazwa: nic. Może to być użyteczne przy wyszukiwaniu błędów w programach. Zamiast czekać na 50.000 dostępów do dysku, aby znaleźć jakiś błąd, wyjście może zostać skierowanie na sterownik NULL. Przy jego pomocy kłopotliwe miejsca w programie można szybciej zidentyfikować.
01 ; TABLICA ADRESÓW STEROWNIKÓW E430 02 PRINTV = $E430 E440 03 CASETV = $E440 E400 04 EDITRV = $E400 E410 05 SCRENV = $E410 E420 06 KEYBDV = $E420 07 ; 0000 08 *= $031A 09 ; 10 HATABS 031A 50 20 .BYTE 'P' DRUKARKA 031B 30E4 30 .WORD PRINTV ADRES TABLICY PUNKTÓW WEJŚCIA 031D 43 40 .BYTE 'C' MAGNETOFON 031E 40E4 50 .WORD CASETV ADRES TABLICY PUNKTÓW WEJŚCIA 0320 45 60 .BYTE 'E' EDYTOR EKRANOWY 0321 00E4 70 .WORD EDITRV ADRES TABLICY PUNKTÓW WEJŚCIA 0323 53 80 .BYTE 'S' STEROWNIK EKRANU 0324 10E4 90 .WORD SCRENV ADRES TABLICY PUNKTÓW WEJŚCIA 0326 4B 0100 .BYTE 'K' KLAWIATURA 0327 20E4 0110 .WORD KEYBDV ADRES TABLICY PUNKTÓW WEJŚCIA 0329 00 0120 .BYTE 0 WOLNY ELEMENT 1 (DOS) 032A 00 00 0130 .BYTE 0,0 032C 00 0140 .BYTE 0 WOLNY ELEMENT 2 (MODUŁ 850) 032D 00 00 0150 .BYTE 0,0 032F 00 0160 .BYTE 0 WOLNY ELEMENT 3 0330 00 00 0170 .BYTE 0,0 0332 60 0180 .BYTE 0 WOLNY ELEMENT 4 0333 00 00 0190 .BYTE 0,0 0335 00 0200 .BYTE 0 WOLNY ELEMENT 5 0336 00 00 0210 .BYTE 0,0 0338 00 0220 .BYTE 0 WOLNY ELEMENT 6 0339 00 00 0230 .BYTE 0,0 033B 00 0240 .BYTE 0 WOLNY ELEMENT 7
Rys.8-12 Tablica adresów sterowników (HATABS)
*= $PRINTV E430 9E EE .WORD PHOPEN-1 OTWARCIE URZĄDZENIA E432 DB EE .WORD PHCLOS-1 ZAMKNIĘCIE URZĄDZENIA E434 9D EE .WORD BADST-1 ODCZYT Z URZĄDZENIA NIEZAIMPLEMENTOWANY E436 A6 EE .WORD PHWRIT-1 ZAPIS NA URZĄDZENIU E438 80 EE .WORD PHSTAT-1 STAN URZĄDZENIA E43A 9D EE .WORD BADST-1 FUNKCJA SPECJALNA NIEZAIMPLEMENTOWANA E43C 4C 78 EE JMP PHINIT INICJALIZACJA URZĄDZENIA
Rys.8-13 Tablica punktów wejścia do sterownika drukarki
0000 10 *= $600 031A 20 HATABS = $031A 0600 A000 40 START LDY #0 0602 B91A03 60 LOOP LDA HATABS,Y 0605 C900 70 CMP #0 ; WOLNY ELEMENT? 0607 F009 80 BEQ FOUND 0609 C8 90 INY 060A C8 0100 INY 060B C8 0110 INY ; WSKAŻ NASTĘPNY ELEMENT HATABS 060C C022 0120 CPY #34 ; KONIEC HATABS? 060E D0F2 0130 BNE LOOP ; NIE ... KONTYNUUJ 0610 38 0140 SEC ; TAK ... INFORMUJ O BŁĘDZIE 0611 60 0150 RTS 0160 ; 0612 A94E 0180 FOUND LDA #'N ; USTAW NAZWĘ URZĄDZENIA 0614 991A03 0190 STA HATABS,Y 0617 C8 0200 INY 0618 A924 0210 LDA #NULLTAB&255 061A 991A03 0220 STA HATABS,Y ; ADRES STEROWNIKA 061D C8 0230 INY 061E A906 0240 LDA #NULLTAB/256 0620 991A03 0250 STA HATABS,Y 0623 60 0260 RTS 0270 0624 3206 0290 NULLTAB .WORD RTHAND-1 ; OPEN 0626 3206 0300 .WORD RTHAND-1 ; CLOSE 0628 3406 0310 .WORD NOFUNC-1 ; READ 062A 3206 0320 .WORD RTHAND-1 ; WRITE 062C 3206 0330 .WORD RTHAND-1 ; STATUS 062E 3406 0340 .WORD NOFUNC-1 ; SPECIAL 0630 4C3306 0350 JMP RTHAND ; INITILIZATION 0360 ; 0633 A001 0380 RTHAND LDY #1 ; FUNKCJA WE/WY WYKONANA Z SUKCESEM 0635 60 0400 NOFUNC RTS ; FUNCTION NIEZAIMPLEMENTOWANA
Rys.8-14 Sterownik urządzenia pustego (NULL)
Sterowniki urządzeń można podzielić na rezydentne i nierezydentne. Sterowniki rezydentne są obecne w pamięci ROM systemu operacyjnego i można je wywoływać poprzez CIO zawsze, gdy dany sterownik posiada swój element w tablicy HATABS. Sterowniki nierezydentne należy najpierw załadować do pamięci RAM i umieścić o nich informację w HATABS, zanim będzie można je wywołać z CIO. Sterownikami rezydentnymi są:
Chociaż sterowniki nierezydentne nie znajdują się w OS ROM, to jednak system operacyjny może je dodać podczas włączania lub systemowego resetu. Możesz nawet dodać swój własny sterownik urządzenia podczas wykonywania programu. Rys.8-14 prezentuje przykład dodawania sterownika do systemu operacyjnego.
Sterowniki urządzeń wykorzystują dane sterujące we/wy przekazane przez CIO w bloku ZIOCB. Dane te są używane do wykonywania funkcji we/wy takich jak OPEN, CLOSE, PUT i GET. Nie wszystkie sterowniki urządzeń wspierają wszystkie rozkazy we/wy (np. próba przesłania znaku za pomocą PUT do klawiatury skończy się błędem 146 – funkcja niezaimplementowana). Rozdział 5 instrukcji do systemu operacyjnego zawiera listę funkcji obsługiwanych przez każdy ze sterowników urządzeń, jak również pełne szczegóły operacyjne tych sterowników.
SIO obsługuje komunikację po magistrali szeregowej pomiędzy sterownikami urządzeń szeregowych w komputerze a urządzeniami na magistrali szeregowej. Komunikuje się ona z wywołującym ją kodem poprzez blok sterujący urządzenia (ang. Device Control Block, DCB). SIO używa danych sterujących we/wy w bloku DCB do wysyłania i odbierania rozkazów i danych po magistrali szeregowej. Sekwencja wywołania jest następująca:
;program wywołujący ustawił DCB w celu wykonania funkcji JSR SIOV ;wektor systemowy do SIO BMI ERROR ;ustawiony bit N oznacza błąd w wykonaniu operacji we/wy
Blok DCB zawiera informację kontrolną we/wy dla SIO i musi zostać ustawiony przed wywołaniem SIO. Rys.8-10 pokazuje zawartość bloku DCB dla kilku typowych operacji we/wy.
Aby wysyłać rozkazy do SIO, musisz zrozumieć strukturę bloku DCB, która została opisana w rozdziale 9 instrukcji systemu operacyjnego. Rys.8-15 demonstruje prostą procedurę w języku asemblera, która wyprowadza wiersz tekstu na drukarkę przez ustawienie DCB i wywołanie SIO.
0000 05 *= $3000 DOWOLNIE WYBRANY PUNKT STARTU 10 ;TA PROCEDURA DRUKUJE WIERSZ NA DRUKARCE PRZEZ WYWOŁANIE SIO POD ADRESEM E459 20 SIOV = $E459 WEKTOR SIO 009B 30 CR = $9B ZNAK KOŃCA WIERSZA 0040 40 PRNTID = $40 NUMER IDENTYFIKACYJNY DRUKARKI NA MAGISTRALI SZEREGOWEJ 004E 45 MODE = $4E TRYB NORMALNY 001C 50 PTIMOT = $001C ADRES NA PRZEKROCZENIE CZASU 0300 60 DDEVIC = $300 NUMER IDENTYFIKACYJNY URZĄDZENIA NA MAGISTRALI SZEREGOWEJ 0301 70 DUNIT = $301 NUMER JEDNOSTKI SZEREGOWEJ 0302 80 DCOMND = $302 ROZKAZ SIO 0303 90 DSTATS = $303 KIERUNEK DANYCH SIO 0304 0100 DBUFLO = $304 DOLNY BAJT ADRESU BUFORA 0305 0110 DBUFHI = $305 GÓRNY BAJT ADRESU BUFORA 0306 0120 DTIMLO = $306 LIMIT CZASU SIO 0307 0130 DTIMHI = $307 0308 0140 DBYTLO = $308 DŁUGOŚĆ BUFORA 0309 0150 DBYTHI = $309 030A 0160 DAUX1 = $30A BAJT POMOCNICZY---TRYB PRACY DRUKARKI 030B 0170 DAUX2 = $30B BAJT POMOCNICZY---NIEUŻYWANY 0180 ; 3000 455841 0190 MESS .BYTE "EXAMPLE 12",CR 3001 4D504C 3005 452031 3009 329B 0200 ; 300B A940 0220 LDA #PRNTID USTAW IDENTYFIKATOR MAGISTRALI 300D 8D0003 0230 STA DDEVIC 3010 A901 0240 LDA #1 USTAW NUMER JEDNOSTKI 3012 8D0103 0250 STA DUNIT 3015 A94E 0260 LDA #MODE 3017 8D0A03 0270 STA DAUX1 NORMALNY TRYB DRUKARKI 301A A901 0275 LDA #1 301C 8D0B03 0280 STA DAUX2 NIEUŻYWANE 301F 8D0703 0290 STA DTIMHI LIMIT CZASU<256 SEKUND 3022 A51C 0300 LDA PTIMOT USTAW LIMIT CZASU SIO DLA DRUKARKI 3024 8D0603 0310 STA DTIMLO 3027 A900 0320 LDA #MESS&255 3029 8D0403 0330 STA DBUFLO USTAW MESS JAKO BUFOR 302C A930 0340 LDA #MESS/256 302E 8D0503 0350 STA DBUFHI 3031 A980 0360 LDA #$80 USTAW KIERUNEK DANYCH SIO 3033 8D0303 0370 STA DSTATS DO ODBIORU PRZEZ URZĄDZENIE PERYFERYJNE 3036 A957 0380 LDA #'W ROZKAZ ZAPISU SIO 3038 8D0203 0390 STA DCOMND 303B 2059E4 0410 JSR SIOV WYWOŁAJ SIO 303E 3001 0420 BMI ERROR 3040 00 0430 GOOD BRK 3041 00 0440 ERROR BRKRys.8-15 Wywołanie CIO w celu wydruku wiersza na drukarce
SIO wykorzystuje trzy przerwania IRQ do sterowania komunikacją po magistrali szeregowej z urządzeniami podłączonymi do tej magistrali:
IRQ | Adres, długość | Funkcja |
---|---|---|
VSERIR VSEROR VSEROC |
[$020A,2] [$020C,2] [$020E,2] |
GOTOWOŚĆ DANYCH ODEBRANYCH SZEREGOWO POTRZEBNE DANE DO WYSŁANIA SZEREGOWEGO TRANSMISJA ZAKOŃCZONA |
Całe wykonywanie programu zostaje wstrzymane, gdy SIO używa magistrali szeregowej do komunikacji. Nawet jeśli nic innego nie dzieje się podczas przesyłu po magistrali szeregowej, to rzeczywiste operacje we/wy są same w sobie sterowane przerwaniami. Metoda komunikacji pomiędzy SIO a sterownikami przerwań jest znana jako metoda semaforowa. Główny kod czeka w pętli, aż sterowniki przerwań zasygnalizują mu, że wykonały operację. Na przykład, podczas wyprowadzania danych SIO umieszcza bajt do przesłania w rejestrze przesuwającym z wyjściem szeregowym, który znajduje się w układzie POKEY. Następnie SIO wchodzi w pętlę i obserwuje pewien znacznik, który będzie ustawiony, gdy żądana operacja we/wy zostanie ukończona. W tym czasie POKEY przesyła na zewnątrz bity po linii szeregowej. Gdy bajt ten będzie wysłany, zostanie wygenerowane przerwanie IRQ – Potrzebne Dane Do Wysłania Szeregowego (ang. Serial Output Needed IRQ). Przerwanie to powoduje skok poprzez wektor do procedury, która ładuje następny bajt z bufora do rejestru przesuwającego z wyjściem szeregowym. Proces ten jest kontynuowany, aż zostanie przesłany cały bufor. Po zatroszczeniu się o wartości sum kontrolnych sterownik przerwania ustawia następnie znacznik zakończenia transmisji. W międzyczasie SIO cierpliwie czekało w pętli na ustawienie tego znacznika. Gdy zobaczy, że znacznik został ustawiony, SIO wróci z powrotem do wywołującej je procedury.
Wykonanie SIO przy wprowadzaniu danych jest podobne. POKEY generuje IRQ (VSERIR), aby poinformować SIO, że odebrano bajt w rejestrze przesuwającym z wejściem szeregowym (SERIN). Sterownik przerwania VSERIR następnie umieszcza ten bajt w buforze i sprawdza, czy został osiągnięty koniec bufora. Jeśli tak, to ustawia znacznik zakończenia transmisji.
W powyższym wyjaśnieniu mogłeś zauważyć, że SIO marnuje nieco czasu czekając bezczynnie na wysłanie lub odbiór informacji z magistrali przez układ POKEY. Ponieważ wektory dla trzech procedur obsługujących przerwania IRQ SIO znajdują się w pamięci RAM, można ich użyć dla twoich własnych sterowników w celu poprawienia wydajności operacji we/wy wykonywanych przez system. W rzeczy samej w ten właśnie sposób moduł interfejsu ATARI 850 jest w stanie wykonywać współbieżne operacje we/wy. Sterownik ten przechwytuje wektory IRQ SIO i kieruje je na swoje własne procedury IRQ, gdy pracuje w trybie współbieżnym we/wy. Pozwala to wywołującemu programowi kontynuować pracę, podczas gdy moduł interfejsu wysyła rozkazy i dane poprzez linię szeregową.
Większość funkcji CIO (OPEN, CLOSE, itp.) jest dostępna poprzez wywołania z poziomu języka BASIC przy użyciu rozkazów OPEN, GET i PUT. Jednakże w języku BASIC brakuje jednego zbioru funkcji CIO – możliwości wykonywania blokowych operacji we/wy o rozmiarze większym niż jeden bajt naraz (GETCHRS i PUTCHRS).
Możliwość wczytania lub zapisu bufora znaków jest potężną zaletą. Na przykład, procedura asemblerowa może zostać załadowana bezpośrednio do pamięci z pliku dyskowego. Albo obraz graficzny w wysokiej rozdzielczości może zostać załadowany bezpośrednio do obszaru pamięci ekranu. Typową metodą usprawniania wydajności programu w języku BASIC jest dostarczenie mu programu w języku maszynowym. który obsługuje pewne funkcje wykonywane wolno przez BASIC. Niestety, znalezienie miejsca w pamięci RAM dla takiej procedury może stanowić kłopotliwy problem. Jednym z rozwiązań jest umieszczenie procedury w obszarze zarezerwowanym dla łańcucha znaków, a następnie wywołanie procedury za pomocą USR ADR(łańcuch). Ponieważ adres łańcucha języka BASIC może się przesuwać podczas edycji programu, to procedura w języku asemblera musi być relokowalna. Dlatego niezmodyfikowane adresowanie pamięci odwołujące się do adresów wewnątrz łańcucha nie będzie działać.
Podprogram z rys.8-16 unika używania łańcuchów przez załadowanie procedury do strony 6 pamięci RAM. W ten sposób procedura w języku asemblera nie musi być relokowalna. Dane sterujące są wstawiane poleceniem POKE do bloku IOCB w celu odczytania procedury w języku asemblera bezpośrednio do pamięci RAM pod adres, pod którym została ona skompilowana przez asembler. Podprogram w języku BASIC z rys.8-16 można również użyć do zapisu danych bezpośrednio z pamięci, gdzie użytkownik określa adres oraz długość bufora danych.
30 REM TEN PROGRAM ŁADUJE NA STRONĘ 6 ZAWARTOŚĆ PLIKU D:TEST 100 DIM FILE$(20),CIO$(7):CIO$="hhh*LVd" 106 REM CIO$ TO PLA,PLA,PLA,TAX,JMP $E456 (CIOV) 110 FILE$="D:TEST":REM NAZWA PLIKU 120 CMD=7:STADR=1536:GOSUB 30000 130 IF ERROR=1 THEN ? "TRANSFER COMPLETE":STOP 135 ? "ERROR # ";ERROR;" OCCURRED AT LINE # ";PEEK(186)+256*PEEK(187) 200 END 300 REM PODPROGRAM USTAWIANIA CIO 310 REM 30000 REM 30001 REM 30002 REM TA PROCEDURA ŁADUJE LUB ZAPISUJE OBSZAR PAMIĘCI Z BASICU 30003 REM PRZEZ USTAWIENIE BLOKU IOCB I BEZPOŚREDNIE WYWOŁANIE CIO 30004 REM 30006 REM NA WEJŚCIU CMD=7 OZNACZA ŁADOWANIE PAMIĘCI 30008 REM CMD=11 OZNACZA ZAPIS PAMIĘCI 30009 REM STADR= ADRES BLOKU PAMIĘCI DO ZAŁADOWANIA LUB ZAPISU 30010 REM BYTES= LICZBA BAJTÓW DO ZAŁADOWANIA LUB ZAPISU 30011 REM IOCB= BLOK IOCB DO UŻYCIA 30012 REM FILE$= NAZWA PLIKU DOCELOWEGO 30013 REM 30014 REM NA WYJŚCIU ERROR=1 OZNACZA WYKONANIE POLECENIA Z SUKCESEM 30018 REM ERROR<>1 OZNACZA NUMER BŁĘDU 30019 REM 30020 REM ELEMENTY BLOKU IOCB 30022 REM 30024 IOCBX=IOCB*16:ICCOM=834+IOCBX:ICSTA=835+IOCBX 30026 ICBAL=836+IOCBX:ICBAH=837+IOCBX 30028 ICBLL=840+IOCBX:ICBLH=841+IOCBX 30029 REM 30030 AUX1=4:IF CMD=11 THEN AUX1=8 30035 TRAP 30900:OPEN #IOCB,AUX1,0,FILE$ 30040 TEMP=STADR:GOSUB 30500 30090 POKE ICBAL,LOW:POKE ICBAH,HIGH 30100 TEMP=BYTES:GOSUB 30500 30130 POKE ICBLL,LOW:POKE ICBLH,HIGH 30140 POKE ICCOM,CMD:ERROR=USR(ADR(CIO$),IOCBX) 30150 ERROR=PEEK(ICSTA):RETURN 30200 REM 30300 REM PROCEDURA ZWRACA GÓRNY I DOLNY BAJT LICZBY 16-BITOWEJ 30400 REM 30500 HIGH=INT(TEMP/256):LOW=INT(TEMP-HIGH*256):RETURN 30550 REM 30600 REM USTAW TUTAJ PUŁAPKĘ NA BŁĄD PODCZAS WYKONYWANIA PROCEDURY 30900 ERROR=PEEK(195) 30920 CLOSE #IOCB:RETURN
Rys.8-16 Bezpośrednie wywołanie CIO z poziomu języka BASIC
W celu otrzymania czystej grafiki i efektów specjalnych układy komputera domowego ATARI są podporządkowane lokalnemu sygnałowi telewizyjnemu. Niestety używane jest wiele "standardów" sygnałów telewizyjnych w różnych krajach. W stanach Zjednoczonych standardem jest system NTSC: 60 ramek na sekundę, 262 poziome linie na ramkę i 228 taktów kolorów na linię. Mówimy o 262 liniach, ponieważ komputer domowy ATARI generuje sygnał bez przeplotu linii; rzeczywisty standard odwołuje się do 525 linii, z których połowa pokazywana jest w każdej ramce. Niektóre kraje Europejskie używają standardu PAL: 50 ramek na sekundę, 312 linii na ramkę. W wyniku odmierzanie czasu jest inne w NTSC i inne w PAL. Zobacz do Rozdziału 2 – ANTIC i lista wyświetlania, gdzie dokładniej przedyskutowano sygnał telewizyjny. Uwagi w tym podrozdziale odnoszą się do systemu NTSC.
Mikroprocesor 6502 jest synchronizowany z sygnałem telewizyjnym na dwa sposoby: przy pomocy synchronizacji zgrubnej i dokładnej. Synchronizacja zgrubna jest osiągana przez użycie tego samego sygnału, który synchronizuje odbiorniki telewizyjne z nadawanym sygnałem telewizyjnym, do wywołania przerwania systemowego. Sygnał ten nazywany jest sygnałem wygaszania pionowego i w odbiornikach telewizyjnych jest on wskazówką, aby wyłączyć strumień elektronów i rozpocząć od góry ekranu przygotowując się na następną ramkę obrazu. Ten sam sygnał jest prezentowany komputerowi jako przerwanie niemaskowane. Programiście udostępnia to regularnie pojawiające się przerwanie, które można użyć do wszystkiego od odmierzania czasu trwania dźwięku do prostej metody programowania wielowątkowego.
Bardziej precyzyjną korelacją pomiędzy przetwarzaniem mikroprocesora 6502 a sygnałem telewizyjnym osiągnięto przez wybór częstotliwości 1,79 MHz na częstotliwość zegarową systemu. Dało to w wyniku bezpośredni związek pomiędzy czasem wykonywania instrukcji maszynowej a odległością, jaką pokonuje strumień elektronów na ekranie. Na przykład, podczas czasu wykonania najkrótszej instrukcji mikroprocesora 6502 (2 takty) strumień elektronów przesuwa się o cztery takty koloru lub o jeden znak trybu graficznego 0 po ekranie. Ten precyzyjny związek czasowy pozwala zdolnemu programiście tworzyć efekty graficzne w środku pojedynczej linii skanowania. Jednakże należy uważać. Bezpośredni dostęp do pamięci przez układ ANTIC sprawia, iż to wewnątrzliniowe odmierzanie czasu staje się bardzo niepewne i będzie się zmieniało w zależności od wybranego trybu graficznego oraz innych czynników. W praktyce oznacza to, iż każda zmiana wewnątrz linii musi być testowana i traktowana jako specjalny przypadek.
Cztery timery zliczające w dół są wbudowane w układ POKEY. Funkcjonują one jako "sprzętowe podprogramy" wielokrotnego użytku. Najczęstsze ich zastosowania wiążą się z kanałami dźwiękowymi przy tworzeniu efektów dźwiękowych (zobacz do Rozdziału 7 – Dźwięk). Można ich również używać jako bezpośrednich timerów zliczających w dół, ponieważ generują one przerwanie IRQ. Każdy timer skojarzony jest z rejestrem częstotliwości, który przechowuje wartość początkową timera. Gdy nastąpi wpis do sprzętowego rejestru STIMER, ta początkowa wartość jest ładowana do timera i rozpoczyna się odliczanie w dół. Gdy timer zliczy do zera, następuje wygenerowanie żądania przerwania IRQ. Ważne jest, iż tylko timery 1, 2 i 4 posiadają wektory przerwań do przetwarzania. Należy podjąć następujące kroki, aby uaktywnić dowolny z timerów:
Jedną z komplikacji przy pracy z tymi timerami jest to, iż odpowiedź na nie mikroprocesora 6502 będzie uprzedzona i prawdopodobnie opóźniona przez bezpośredni dostęp do pamięci układu ANTIC, przerwania z list wyświetlania lub przetwarzanie wygaszania pionowego.
Jest 6 programowych timerów systemowych:
Nazwa | Adres | Wektor lub znacznik |
---|---|---|
RTCLOK CDTMV1 CDTMV2 CDTMV3 CDTMV4 CDTMV5 |
[$0012,3] [$0218,2] [$021A,2] [$021C,2] [$021E,2] [$0220,2] |
żaden CDTMA1 [$0226,2] CDTMA2 [$0228,2] CDTMF3 [$022A,1] CDTMF4 [$022C,1] CDTMF5 [$022E,1] |
Wszystkie timery systemowe są zmniejszane o 1 jako część procesu wygaszania pionowego (VBLANK). Jeśli proces VBLANK jest wyłączony lub przechwycony, to timery te nie będą uaktualniane.
Zegar czasu rzeczywistego (RTCLOK) i timer systemowy 1 (CDTMV1) są uaktualniane podczas początkowej procedury VBLANK w etapie1. RTCLOK zlicza w górę od 0 i jest wartością 3-bajtową. Gdy RTCLOK osiągnie swoją wartość maksymalną (16.777.216), to zostanie zresetowany na zero. RTCLOK można używać jako zegara czasu rzeczywistego, co pokazuje rys.8-17.
Ponieważ timery systemowe są uaktualniane jako część procesu VBLANK, to należy zastosować specjalne kroki ostrożności, aby je poprawnie ustawić. Do tego celu używa się procedury systemowej o nazwie SETVBV [$E45C]. Jej wywołanie wygląda następująco:
Przykład:
LDA #1 ;Ustaw timer systemowy 1 LDY #0 LDX #2 ;Wartość wynosi $200 (512) okresów VBLANK JSR SETVBV ;Wywołaj procedurę systemową, aby ustawić timer
Timery systemowe 1-5 są 2-bajtowymi licznikami. Można je ustawiać przy pomocy procedury SETVBV. System operacyjny zmniejsza ich zawartość podczas przerwania od wygaszania pionowego VBLANK. Timer 1 jest zmniejszany podczas początkowej procedury VBLANK w etapie 1. Timery 2-5 są zmniejszane w etapie 2. System operacyjny wykonuje różne działania, gdy różne timery osiągną wartość 0.
Timery systemowe 1 i 2 posiadają skojarzone z nimi wektory. Gdy timer 1 lub 2 osiąga 0, system operacyjny symuluje rozkaz JSR poprzez wektor dla danego timera. Rys.8-7 podaje wektory dla tych dwóch timerów.
Timery systemowe 3-5 posiadają znaczniki, które są normalnie ustawione (tj. mają wartość różną od zera). Gdy którykolwiek z tych trzech timerów zliczy do zera, system operacyjny wyzeruje jego znacznik. Możesz testować stan znacznika i podjąć odpowiednie działania.
Timery 1-5 są timerami programowymi ogólnego przeznaczenia, które można używać w różnorodnych aplikacjach. Na przykład, timer 1 jest używany przez SIO do odmierzania czasu operacji na magistrali szeregowej. Jeśli timer ten zliczy do zera przed zakończeniem danej operacji na magistrali, zostanie zwrócony błąd przekroczenia czasu (ang. timeout error). Timer 1 jest ustawiany na różne wartości w zależności od urządzenia, z którym jest prowadzona komunikacja. Zapewnia to obszerną ilość czasu dla urządzenia na odpowiedź na żądanie we/wy, a jednocześnie komputer nie będzie na nią czekał w nieskończoność, jeśli dane urządzenie nie jest obecne. Sterownik magnetofonu kasetowego używa timera 3 do ustawiania długości czasu odczytu i zapisu nagłówków taśmowych. Rys.8-18 pokazuje przykład użycia timera 2 do odmierzania czasu dźwięku metronomu.
Timery programowe używane są zwykle wtedy, gdy związana z nimi skala czasu jest większa od jednego okresu wygaszania pionowego VBLANK. Dla czasów krótszych należy zastosować timery sprzętowe lub jakąś inną metodę.
1 POKE 752,1 3 ? "+":REM WYMAŻ EKRAN (+=ESC-CTRL-CLR) 4 ? "HOUR";:INPUT HOUR:? "MINUTE";:INPUT MIN:? "SECOND";:INPUT SEC 5 CMD=1:GOSUB 45 6 ? "+";HOUR;" : ";MIN;" : ";SEC:? " ": ? " " 7 CMD=2:GOSUB 45 9 ? "";HOUR;":";MIN;":";SEC;" ":GOTO 7 10 REM TO JEST DEMONSTRACJA ZEGARA CZASU RZECZYWISTEGO 20 REM PROCEDURA TA PRZYJMUJE CZAS W GODZINACH, MINUTACJ I SEKUNDACH 30 REM USTAWIA ZEGAR CZASU RZECZYWISTEGO NA ZERO 40 REM BIEŻĄCA WARTOŚĆ RTCLOCK JEST UŻYWANA DO DODANIA CZASU POCZĄTKOWEGO, ABY OTRZYMAĆ 42 REM BIEŻĄCY CZAS W GODZ,MIN,SEK 45 HIGH=1536:MED=1537:LOW=1538 50 REM 60 REM ******PUNKT WEJŚCIA****** 65 REM 70 ON CMD GOTO 100,200 95 REM 96 REM ****INICJALIZUJ ZEGAR***** 97 REM 100 POKE 20,0:POKE 19,0:POKE 18,0 105 DIM CLOCK$(50) 106 CLOCK$=" " 107 GOSUB 300 110 IHOUR=HOUR:IMIN=MIN:ISEC=SEC:RETURN 197 REM 198 REM *******ODCZYTAJ ZEGAR***** 199 REM 200 REM 201 A=USR(ADR(CLOCK$)) 210 TIME=C(((PEEK(HIGH)*256)+PEEK(MED))*256)+PEEK(LOW))/59.923334 220 HOUR=INT(TIME/3600):TIME=TIME-(HOUR*3600) 230 MIN=INT(TIME/60):SEC=INT(TIME-(MIN*60)) 235 SEC=SEC+ISEC:IF SEC>60 THEN SEC=SEC-60:MIN=MIN+1 236 MIN=MIN+IMIN:IF MIN>60 THEN MIN=MIN-60:HOUR=HOUR+1 237 HOUR=HOUR+IHOUR 240 HOUR=HOUR-(INT(HOUR/24))*24 250 RETURN 300 FOR J=1 TO 38:READ Z:CLOCK$(J,J)=CHR$(Z):NEXT J:RETURN 310 DATA 104,165,18,141,0,6,165,19,141,1,6,165 320 DATA 20,141,2,6,165,18,205,0,6,208,234 330 DATA 165,19,205,1,6,208,227,165,20,205,2,6,208,220,96Rys.8-17 Zegar czasu rzeczywistego
1 REM TO JEST PROGRAM KONTROLUJĄCY TEMPO METRONOMU 2 REM 3 REM 5 PRINT "+":REM CZYŚĆ EKRAN 10 X=10:REM WARTOŚĆ POCZĄTKOWA TEMPA 20 FOR J=1 TO 10:NEXT J:REM PROGRAMOWA PĘTLA OPÓŹNIAJĄCA 50 IF STICK(0)=14 THEN X=X+1 :REM JOYSTICK DO PRZODU OZNACZA ZWIĘKSZENIE TEMPA 51 IF STICK(0)=13 THEN X=X-1 :REM JOYSTICK DO TYŁU OZNACZA ZWOLNIENIE TEMPA METRONOMU 52 IF X<1 THEN X=1:REM NIGDY NIE SCHODŹ PONIŻEJ JEDEN 53 IF X>255 THEN X=255:REM LUB POWYŻEJ 255 54 REM WYPISZ TAKTY/MINUTĘ 56 ? "";INT(3600/X);" BEATS/MINUTES " 60 POKE 0,X:REM ADRES $0000 ZAWIERA TEMPO DLA 70 NEXT I :REM PONIŻSZEJ PROCEDURY W ASEMBLERZERys.8-18 Procedura metronomu w języku BASIC
40 *=$600 50 ;PROCEDURA METRONOMU...UŻYWA $0000 DO PRZEKAZYWANIA TEMPA METRONOMU 60 ; 70 AUDF1 = $D200 REJESTR CZĘSTOTLIWOŚCI AUDIO 80 AUDC1 = $D201 REJESTR STERUJĄCY AUDIO 90 FREQ = $08 WARTOŚĆ AUDF1 0100 VOLUME = $AF WARTOŚĆ AUDC1 0110 OFF = $A0 WYŁĄCZ GŁOŚNOŚĆ 0120 SETVBV = $E45C PROCEDURA USTAWIANIA WARTOŚCI TIMERA 0130 XITVBV = $E462 0140 CDTMV2 = $021A TIMER 2 0150 CDTMA2 = $0228 WEKTOR TIMERA 2 0160 ZTIMER = $0000 WARTOŚĆ TIMERA VBLANK NA STRONIE ZEROWEJ 0170 ; 0180 START LDA #10 0190 STA ZTIMER 0200 ; USTAW WEKTOR TIMERA 0220 ; 0230 INIT LDA #CNTINT&255 0240 STA CDTMA2 0250 LDA #CNTINT/256 0260 STA CDTMA2+1 0270 ; 0280 ; USTAW WARTOŚĆ TIMERA PO WEKTORZE 0290 ; 0300 LDY ZTIMER USTAW TIMER DWA NA ZLICZANIE 0310 JSR SETIME 0320 RTS 0340 ; ZLICZANIE W DÓŁ METRONOMU WSKAZUJE TUTAJ 0380 ; USTAW KANAŁ AUDIO NA KLIK METRONOMU 0390 0400 CNTINT LDA #VOLUME 0410 STA AUDC1 0420 LDA #FREQ 0430 STA AUDF1 0435 LDY #$FF OPÓŹNIENIE 0440 DELAY DEY 0442 BNE DELAY 0450 STY AUDC1 0460 JMP INIT 0480 ; 0490 ; PODPROGRAM DO USTAWIANIA TIMERA 0500 ; 0520 SETIME LDX #0 LICZBA OKRESÓW VBLANK < 256 0530 LDA #2 USTAW TIMER 2 0540 JSR SETVBV PROCEDURA SYSTEMOWA USTAWIANIA TIMERA 0550 RTS 0560 *=$2E2 0570 .WORD START 0580 .ENDRys.8-19 Procedura metronomu w języku asemblera
Czytelników pragnących zapoznać się ze sposobami reprezentacji liczb w komputerach zapraszam do osobnego artykułu "Binarne Kodowanie Liczb".
Wewnętrznie pakiet FPP konfiguruje liczby jako wartości 6-bajtowe. Każda liczba składa się z 1-bajtowego wykładnika i 5-bajtowej mantysy w formacie BCD (ang. Binary Coded Decimal). Tę reprezentację wybrano, aby zminimalizować błędy zaokrągleń, które mogą się pojawiać w niektórych procedurach arytmetycznych.
Bit znakowy bajtu wykładnika dostarcza znaku mantysy, 0 dla dodatniej, 1 dla ujemnej. Najmniej znaczące 7 bitów wykładnika dostarczają wykładnika potęgi liczby 100 w notacji z nadmiarem 64. W notacji tej wartość 64 jest dodawana do wykładnika zanim zostanie on umieszczony w bajcie wykładnika. Pozwala to wyrazić pełny zakres wykładników, dodatnich i ujemnych, bez potrzeby stosowania bitu znakowego.
Mantysa jest zawsze znormalizowana w taki sposób, iż jej najbardziej znaczący bajt ma wartość niezerową. Jednakże, ponieważ mantysa jest w formacie BCD, a wykładnik reprezentuje potęgi 100 a nie 10, to wynikowa precyzja może posiadać 9 lub dziesięć cyfr dokładnych. Przecinek dziesiętny jest ustawiany na prawo od pierwszego bajtu mantysy, zatem wykładnik mniejszy od 64 (szesnastkowo 40) oznacza liczbę mniejszą od 1.
PRZYKŁADY (wartości w formacie są podane szesnastkowo)
Liczba: -0,02 = -2 × 100-1
Format: BF 02 00 00 00 00 (wykładnik= 80+40-1)
Liczba: 37,0 = 37 × 1000
Format: 40 37 00 00 00 00 (wykładnik= 40+0)
Liczba: -460312 = -46,0312 × 1002
Format: C2 46 03 12 00 00 (wykładnik= 80+40+2)
Liczba zero jest traktowana jako przypadek specjalny i tworzy ją zerowy wykładnik i zerowa mantysa. Test na zero można wykonać sprawdzając albo wykładnik, albo pierwszy bajt mantysy.
Schemat ten pozwala reprezentować dynamiczny zakres liczb od 10-98 do 10+98.
Przy implementacji pakietu FPP wykorzystywane są dwa obszary pamięci RAM:
Obszary te są używane na parametry sterujące jak również do symulacji kilku rejestrów zmiennoprzecinkowych. Dwa pseudorejestry należące do głównego kręgu zainteresowań noszą nazwy FR0 i FR1 (adresy odpowiednio $00D4-$00D9 i $00E0-$00E5). Każdy z tych pseudorejestrów ma długość 6 bajtów i jest w stanie przechowywać liczbę w reprezentacji zmiennoprzecinkowej. 2-bajtowy wskaźnik jest używany do wskazywania liczby zmiennoprzecinkowej. Nazywa się on FLPTR i przebywa pod adresem $00FC.
Do konwersji pomiędzy liczbami zmiennoprzecinkowymi a łańcuchami ATASCII należy udostępnić bufory na łańcuchy tekstowe. Bufor wyjściowy nosi nazwę LBUFF i jest 128 bajtowym blokiem o adresie od $0580 do $05FF. Bufor wejściowy jest określany przez 2-bajtowy wskaźnik INBUFF pod adresem $00F3. Również jednobajtowy indeks CIX o adresie $00F2 jest używany jako przesunięcie w buforze wskazywanym przez INBUFF.
Typowa sekwencja rozkazów przy używaniu pakietu zmiennoprzecinkowego z poziomu języka asemblera wygląda następująco: najpierw łańcuch ATASCII reprezentujący jedną z liczb, które mają być użyte w procedurze arytmetycznej, zostaje umieszczony w jakimś buforze w dowolnym miejscu w pamięci. Następnie wskaźnik INBUFF zostaje ustawiony na początek tego łańcucha. Również wartość indeksu CIX powinna wynosić zero. Liczba jest wtedy gotowa do konwersji na jej zmiennoprzecinkową reprezentację, zatem zostaje wywołana procedura AFP. Spowoduje to umieszczenie liczby zmiennoprzecinkowej w rejestrze FR0, skąd można jej użyć w dowolnej operacji FPP. Po wykonaniu operacji matematycznych zmiennoprzecinkowy wynik będzie w rejestrze FR0. Wywołanie procedury FASC zamieni tą liczbę na łańcuch ATASCII umieszczony w LBUFF. Przykład tego procesu znajdziesz na rys.8-21.
Aby użyć wartości 16-bitowych z pakietem FPP, umieść te dwa bajty liczby w dwóch najniższych bajtach rejestru FR0 ($D4 i $D5) i wykonaj rozkaz JSR IFP, który zamieni tę liczbę całkowitą na jej reprezentację zmiennoprzecinkową i pozostawi wynik w FR0. Podprogram FPI wykonuje operację odwrotną.
Tabelka poniżej wymienia dostępne funkcje, ich adresy w ROM, używane pseudorejestry oraz przybliżony, maksymalny czas obliczeń.
NAZWA | ADRES | FUNKCJA | WYNIK | MAKSYMALNY CZAS WYKONANIA (mikrosekundy) |
AFP FASC IFP FPI FSUB FADD FMUL FDIV FLDOR FLDOP FLD1R FLD1P FSTOR FSTOP FMOVE PLYEVL EXP EXP1O LOG LOG10 ZFR0 AF1 |
D800 D8E6 D9AA D9D2 DA60 DA66 DADB DB28 DD89 DD8D DD98 DD9C DDA7 DDA8 DDB6 DD40 DDC0 DDCC DECD DED1 DA44 DA46 |
ATASCII na liczbę zmiennoprzecinkową Liczba zmiennoprzecinkowa na ATASCII Liczba całkowita na zmiennoprzecinkową Liczba zmiennoprzecinkowa na całkowitą FR0-FR1 Odejmowanie FR0+FR1 Dodawanie FR0*FR1 Mnożenie FR0/FR1 Dzielenie Ładowanie liczby zmiennoprzecinkowej przy pomocy X,Y Ładowanie liczby zmiennoprzecinkowej przy pomocy FLPTR Ładowanie liczby zmiennoprzecinkowej przy pomocy X,Y Ładowanie liczby zmiennoprzecinkowej przy pomocy FLPTR Zapis liczby zmiennoprzecinkowej przy pomocy X,Y Zapis liczby zmiennoprzecinkowej przy pomocy FLPTR Przeniesienie FR0 Obliczenia wielomianowe Potęgowanie - eFR0 Potęgowanie - 10FR0 Logarytm naturalny Logarytm dziesiętny Zerowanie Zerowanie rejestru w X |
FR0 LBUFF FR0 FR0 FR0 FR0 FR0 FR0 FR0 FR0 FR1 FR1 FR0 FR0 FR1 FR0 FR0 FR0 FR0 FR0 FR0 zmienny |
3500 950 1330 2400 740 710 12000 10000 70 60 70 60 70 70 60 88300 115900 108800 136000 125400 80 80 |
Rys.8-20 Procedury zmiennoprzecinkowe
0000 20 *= $4000 ; DOWOLNIE WYBRANY PUNKT STARTOWY DDB6 30 FMOVE = $DDB6 DA60 40 FSUB = $DA60 0482 50 FTEMP = $0482 DDA7 60 FSTOR = $DDA7 D8E6 70 FASC = $D8E6 00F3 80 INBUFF = $00F3 D800 85 AFP = $D800 00F2 90 CIX = $00F2 0580 100 LBUFF = $0580 009B 120 CR = $9B 0009 130 PUTREC = $09 0005 140 GETREC = $05 E456 150 CIOV = $E456 0342 160 ICCOM = $0342 0344 170 ICBAL = $0344 0348 180 ICBLL = $0348 190 ; 200 ; DEMONSTRACJA LICZB ZMIENNOPRZECINKOWYCH 210 ; ODCZYTUJE DWIE LICZBY Z EDYTORA EKRANOWEGO, 215 ; ZAMIENIA JE NA REPREZENTACJE ZMIENNOPRZECINKOWE, 220 ; ODEJMUJE PIERWSZĄ OD DRUGIEJ, 225 ; UMIESZCZA WYNIK W FTEMP, 230 ; KTÓRY JEST REJESTREM ZDEFINIOWANYM PRZEZ UŻYTKOWNIKA, 240 ; I WYŚWIETLA WYNIK. 4000 205340 260 START JSR GETNUM ; POBIERZ PIERWSZĄ LICZBĘ Z E: 4003 20B6DD 270 JSR FMOVE ; PRZENIEŚ LICZBĘ Z FR0 DO FR1 4006 205340 280 JSR GETNUM ; POBIERZ DRUGĄ LICZBĘ Z E: 4009 2060DA 290 JSR FSUB ; FR0 <-- FR0-FR1 400C 900A 300 BCC NOERR ; OMIŃ, JEŚLI NIE MA BŁĘDU 400E A981 340 LDA #ERRMSG&255 ; JEŚLI JEST, WYŚWIETL WIADOMOŚĆ 4010 8D4403 350 STA ICBAL 4013 A940 360 LDA #ERRMSG/256 4015 4C3940 370 JMP CONTIN 4018 A282 390 NOERR LDX #FTEMP&255 ; UMIEŚĆ WYNIK W FTEMP 401A A004 400 LDY #FTEMP/256 401C 20A7DD 410 JSR FSTOR 420 ; 430 ; ZAMIEŃ LICZBĘ NA ŁAŃCUCH ATACSII. 440 ; ZNAJDŹ KONIEC ŁAŃCUCHA, 445 ; ZMIEŃ LICZBĘ UJEMNĄ NA DODATNIĄ, 450 ; I DODAJ ZNAK POWROTU KARETKI. 401F 20E6D8 470 JSR FASC ; LICZBA ZMIENNOPRZECINKOWA NA ATASCII, WYNIK W LBUFF 4022 A0FF 480 LDY #$FF 4024 C8 490 MLOOP INY 4025 B1F3 500 LDA (INBUFF),Y ; ZAŁADUJ NASTĘPNY BAJT 4027 10FB 510 BPL MLOOP ; JEŚLI DODATNI, KONTYNUUJ 4029 297F 520 AND #$7F ; JEŚLI NIE, WYMASKUJ BIT ZNAKU 402B 91F3 530 STA (INBUFF),Y 402D C8 540 INY 402E A99B 550 LDA #CR ; ZAPISZ ZNAK POWROTU KARETKI 4030 91F3 560 STA (INBUFF),Y 570 ; 580 ; WYŚWIETL WYNIK 4032 A5F3 600 LDA INBUFF ; POBIERZ ADRES BUFORA 4034 8D4403 610 STA ICBAL 4037 A5F4 620 LDA INBUFF+1 4039 8D4503 630 CONTIN STA ICBAL+1 403C A909 640 LDA #PUTREC ; ROZKAZ DO ZAPISU REKORDU 403E 8D4203 650 STA ICCOM 4041 A928 660 LDA #40 ; USTAW DŁUGOŚĆ BUFORA NA 40 4043 8D4803 670 STA ICBLL 4046 A900 690 LDA #0 4048 8D4903 700 STA ICBLL+1 404B A200 710 LDX #0 ; IOCB 0 NA EDYTOR EKRANOWY 404D 2056E4 720 JSR CIOV ; WYWOŁAJ CIO 4050 4C0040 730 JMP START ; JESZCZE RAZ 740 ; 750 ; POBIERZ ŁAŃCUCH ATASCII Z E: 755 ; ZAMIEŃ GO NA LICZBĘ ZMIENNOPRZECINKOWĄ, WYNIK W FR0 4053 A905 780 GETNUM LDA #GETREC ; POBIERZ REKORD (ZAKOŃCZONY ZNAKIEM CR) 4055 8D4203 790 STA ICCOM 4058 A980 800 LDA #LBUFF&255 ; USTAW ADRES BUFORA RÓWNY LBUFF 405A 8D4403 810 STA ICBAL 405D A905 820 LDA #LBUFF/256 405F 8D4503 830 STA ICBAL+1 4062 A928 840 LDA #40 ; USTAW DŁUGOŚĆ BUFORA NA 40 4064 8D4803 850 STA ICBLL 4067 A900 860 LDA #0 4069 8D4903 870 STA ICBLL+1 406C A200 880 LDX #0 ; IOCB 0 NA EDYTOR EKRANOWY 406E 2056E4 890 JSR CIOV ; WYWOŁAJ CIO 4071 A980 900 LDA #LBUFF&255 ; ZAPISZ ADRES BUFORA W INBUFF 4073 85F3 910 STA INBUFF 4075 A905 920 LDA #LBUFF/256 4077 85F4 930 STA INBUFF+1 4079 A900 940 LDA #0 ; USTAW INDEKS BUFORA NA 0 407B 85F2 950 STA CIX 407D 2000D8 960 JSR AFP ; WYWOŁAJ ATASCII NA LICZBĘ ZMIENNOPRZECINKOWĄ 4080 60 970 RTS 4081 45 980 ERRMSG .BYTE "ERROR",CR 4082 52 4083 52 4084 4F 4085 52 4086 9B 1000 ; ADRES POCZĄTKU PROCEDURY 4087 1020 * = $2E0 02E0 0040 1030 .WORD START 02E2 1040 .END
Rys.8-21 Przykład zmiennoprzecinkowy
![]() |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2023 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone
pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.