Programowanie: Użycie OS-a przy wyłączonym ROM-ie
From Atariki
| Wersja z dnia 21:55, 3 gru 2019 Mono (Dyskusja | wkład) (dli przelotka) ← Previous diff |
Wersja z dnia 22:39, 3 gru 2019 Mono (Dyskusja | wkład) (tablice skokow i wektorow) Next diff → |
||
| Linia 1: | Linia 1: | ||
| Żeby swobodnie używać mechanizmów [[OS]]-a a przy tym mieć dostęp do całego [[RAM]]-u trzeba zadbać tylko o poprawne wykonanie przerwań będących w [[ROM]]-ie w sytuacji kiedy ten jest wyłączony. | Żeby swobodnie używać mechanizmów [[OS]]-a a przy tym mieć dostęp do całego [[RAM]]-u trzeba zadbać tylko o poprawne wykonanie przerwań będących w [[ROM]]-ie w sytuacji kiedy ten jest wyłączony. | ||
| + | |||
| + | = Handler = | ||
| Kod handlera przerwań powinien być umieszczony poza obszarem ROM-u ($5000..$57FF, $A000..$BFFF, $C000..$FFFF): | Kod handlera przerwań powinien być umieszczony poza obszarem ROM-u ($5000..$57FF, $A000..$BFFF, $C000..$FFFF): | ||
| Linia 41: | Linia 43: | ||
| rti | rti | ||
| </pre> | </pre> | ||
| + | |||
| + | = Inicjalizacja = | ||
| + | |||
| Wszystko co jest potrzebne do uruchomienia mechanizmu to inicjalizacja wektorów NMIVEC i IRQVEC pod ROM-em: | Wszystko co jest potrzebne do uruchomienia mechanizmu to inicjalizacja wektorów NMIVEC i IRQVEC pod ROM-em: | ||
| <pre> | <pre> | ||
| Linia 64: | Linia 69: | ||
| </pre> | </pre> | ||
| Od tej pory można swobodnie wyłączać i włączać dowolny obszar ROM (przez zwykłą modyfikację rejestru PORTB) bez obawy o to, że komputer się zawiesi. | Od tej pory można swobodnie wyłączać i włączać dowolny obszar ROM (przez zwykłą modyfikację rejestru PORTB) bez obawy o to, że komputer się zawiesi. | ||
| + | |||
| + | = Działanie = | ||
| W przypadku kiedy ROM jest włączony przerwanie obsługiwane jest przez standardowe procedury umieszczone w ROM (ponieważ wektory NMIVEC oraz IRQVEC znajdują się wtedy w obszarze ROM). | W przypadku kiedy ROM jest włączony przerwanie obsługiwane jest przez standardowe procedury umieszczone w ROM (ponieważ wektory NMIVEC oraz IRQVEC znajdują się wtedy w obszarze ROM). | ||
| Linia 72: | Linia 79: | ||
| * czy przerwanie IRQ zostało zgłoszone przez układ I/O, czy może przerwanie zostało wywołane przez rozkaz BRK (w przypadku obsługi przerwania IRQ). | * czy przerwanie IRQ zostało zgłoszone przez układ I/O, czy może przerwanie zostało wywołane przez rozkaz BRK (w przypadku obsługi przerwania IRQ). | ||
| Po wykonaniu procedury z ROM sterowanie przekazywane jest do procedury iret, której jedynym zadaniem jest ponowne odtworzenie konfiguracji pamięci (odłączenie ROM). | Po wykonaniu procedury z ROM sterowanie przekazywane jest do procedury iret, której jedynym zadaniem jest ponowne odtworzenie konfiguracji pamięci (odłączenie ROM). | ||
| + | |||
| + | = Wywoływanie procedur OS = | ||
| Trzeba pamiętać (co właściwie powinno być oczywiste), że gdy w programie chcemy wywołać dowolną systemową procedurę z ROM, a jest on aktualnie odłączony, to trzeba go sobie włączyć: | Trzeba pamiętać (co właściwie powinno być oczywiste), że gdy w programie chcemy wywołać dowolną systemową procedurę z ROM, a jest on aktualnie odłączony, to trzeba go sobie włączyć: | ||
| Linia 80: | Linia 89: | ||
| jsr JSIOINT ;$E459 | jsr JSIOINT ;$E459 | ||
| </pre> | </pre> | ||
| - | Najlepiej dla procedur systemowych, które wywoływane są w programie zdefiniować sobie w obszarze nie pokrywającym się z ROM tzw. "przelotki" np: | + | |
| + | Odwołania do procedur OS-a odbywają się przez [[Tablice_wektor%C3%B3w_ROM|tablice wektorów]] oraz [[Tablica_skok%C3%B3w|tablicę skoków]]. Stanowią one oficjalne punkty wejścia do procedur systemu operacyjnego i gwarantują, że niezależnie od wersji oraz rodzaju systemu operacyjnego zainstalowanego w komputerze zawsze zostanie wywołana procedura żądana przez użytkownika. | ||
| + | |||
| + | Wyjątek stanowią procedury [[Pakiet_matematyczny|pakietu matematycznego]] który nie posiada tablicy skoków, przez co odpowiednie procedury niezależnie od wersji pakietu zainstalowanego w komputerze zawsze muszą znajdować się pod ustalonymi adresami. | ||
| + | |||
| + | Wywołania przez systemową tablicę skoków (JMP), najprościej zrealizować n.p. tak: | ||
| <pre> | <pre> | ||
| JSIOINTjump: | JSIOINTjump: | ||
| Linia 94: | Linia 108: | ||
| rts | rts | ||
| </pre> | </pre> | ||
| - | i używać ich do wywołania procedur OS-a. | + | |
| + | Nieco odmienna jest metoda wywoływania procedur dostępnych przez tablicę wektorów, ponieważ wektory wskazują adres procedury zmniejszony o jeden i jako takie służą do wykonania skoku przez RTS: | ||
| + | <pre> | ||
| + | SIO_S_SPECIAL_jump: | ||
| + | lda PORTB | ||
| + | pha | ||
| + | ora #%00000001 | ||
| + | sta PORTB | ||
| + | |||
| + | jsr ?call | ||
| + | |||
| + | pla | ||
| + | sta PORTB | ||
| + | rts | ||
| + | |||
| + | ?call lda $E410+$0A+1 | ||
| + | pha | ||
| + | lda $E410+$0A | ||
| + | pha | ||
| + | rts | ||
| + | </pre> | ||
| + | Ta metoda powinna być używana również do wywołania procedury PUTBT dostępnej w rejestrze ICPUTB bloku IOCB. | ||
| + | |||
| + | = Rejestry OS w RAM = | ||
| Rejestry $00..$7F oraz $2xx i $3xx są to rejestry zarezerwowane dla potrzeb systemu operacyjnego. | Rejestry $00..$7F oraz $2xx i $3xx są to rejestry zarezerwowane dla potrzeb systemu operacyjnego. | ||
| - | Ta sztuczka jest stosowana między innymi przez [[Turbo BASIC XL]], [[U-BASIC]] oraz [[SpartaDOS X]]. | + | = DLI = |
| W przypadku gdy w programie używane jest przerwanie [[Display List]], które zazwyczaj jest krytyczne czasowo, można zmodyfikować punkt wejścia do przerwania NMI tak, aby zagwarantować identyczne zależności czasowe jak w przypadku gdy przerwanie obsługiwane jest bezpośrednio przez procedurę systemu operacyjnego: | W przypadku gdy w programie używane jest przerwanie [[Display List]], które zazwyczaj jest krytyczne czasowo, można zmodyfikować punkt wejścia do przerwania NMI tak, aby zagwarantować identyczne zależności czasowe jak w przypadku gdy przerwanie obsługiwane jest bezpośrednio przez procedurę systemu operacyjnego: | ||
| Linia 134: | Linia 171: | ||
| lub też wykorzystać wyżej wspomnianą "przelotkę": | lub też wykorzystać wyżej wspomnianą "przelotkę": | ||
| <pre> | <pre> | ||
| - | _jakas_procedura_os_jump: | ||
| - | lda PORTB | ||
| - | pha | ||
| - | ora #%00000001 | ||
| - | sta PORTB | ||
| - | jsr _jakas_procedura_os_ | ||
| - | pla | ||
| - | sta PORTB | ||
| - | rts | ||
| - | |||
| custom_dli: | custom_dli: | ||
| pha | pha | ||
| Linia 152: | Linia 179: | ||
| rti | rti | ||
| </pre> | </pre> | ||
| + | |||
| + | = Trivia = | ||
| + | |||
| + | Opisana tutaj sztuczka jest stosowana między innymi przez [[Turbo BASIC XL]], [[U-BASIC]] oraz [[SpartaDOS X]]. | ||
| [[Kategoria:Niezbędnik kodera]] | [[Kategoria:Niezbędnik kodera]] | ||
Wersja z dnia 22:39, 3 gru 2019
Żeby swobodnie używać mechanizmów OS-a a przy tym mieć dostęp do całego RAM-u trzeba zadbać tylko o poprawne wykonanie przerwań będących w ROM-ie w sytuacji kiedy ten jest wyłączony.
Spis treści |
Handler
Kod handlera przerwań powinien być umieszczony poza obszarem ROM-u ($5000..$57FF, $A000..$BFFF, $C000..$FFFF):
nmiint sec
scs
irqint clc
pha
txa
pha
tsx
;wlaczenie OS ROM
inc PORTB ;$D301
;odlozenie na stos danych dla powrotu z przerwania (RTI)
lda #>iret ;adres procedury iret
pha
lda #<iret
pha
lda $103,x ;skopiowanie wartosci rejestru stanu procesora
pha
;skok przez odpowiedni wektor przerwania
scc
jmp (NMIVEC) ;$FFFA
jmp (IRQVEC) ;$FFFE
iret ;wylaczenie OS ROM
dec PORTB ;$D301
pla
tax
pla
rti
Inicjalizacja
Wszystko co jest potrzebne do uruchomienia mechanizmu to inicjalizacja wektorów NMIVEC i IRQVEC pod ROM-em:
sei
lda #%00000000
sta NMIEN ;$D40E
lda #%11111110
sta PORTB ;$D301
ldx #<nmiint
ldy #>nmiint
stx NMIVEC ;$FFFA
sty NMIVEC+1
ldx #<irqint
ldy #>irqint
stx IRQVEC ;$FFFE
sty IRQVEC+1
lda #%01000000
sta NMIEN ;$D40E
cli
Od tej pory można swobodnie wyłączać i włączać dowolny obszar ROM (przez zwykłą modyfikację rejestru PORTB) bez obawy o to, że komputer się zawiesi.
Działanie
W przypadku kiedy ROM jest włączony przerwanie obsługiwane jest przez standardowe procedury umieszczone w ROM (ponieważ wektory NMIVEC oraz IRQVEC znajdują się wtedy w obszarze ROM). Kiedy ROM jest odłączony wektor wejścia w przerwanie pobierany jest z NMIVEC lub IRQVEC, które znajdują się w RAM i wykonywana jest procedura przerwania nmiint lub irqint. Obydwie te procedury mają za zadanie włączenie ROM-u, wykonanie procedury obsługi przerwania według wektora znajdującego się już w ROM, oraz przywrócenie konfiguracji ROM po powrocie. Odbywa się to poprzez zapalenie najmłodszego bitu PORTB (włączenie OS ROM), odłożenie na stos adresu powrotu do procedury iret oraz wartości rejestru F procesora odłożonego na stos w sekwencji wywołania przerwania. Zduplikowanie tej wartości jest niezbędne dla poprawnego działania procedur obsługi przerwań zachowanych w ROM, ponieważ testują one:
- czy przerwane zostało wykonanie przerwania IRQ (w przypadku obsługi przerwania NMI),
- czy przerwanie IRQ zostało zgłoszone przez układ I/O, czy może przerwanie zostało wywołane przez rozkaz BRK (w przypadku obsługi przerwania IRQ).
Po wykonaniu procedury z ROM sterowanie przekazywane jest do procedury iret, której jedynym zadaniem jest ponowne odtworzenie konfiguracji pamięci (odłączenie ROM).
Wywoływanie procedur OS
Trzeba pamiętać (co właściwie powinno być oczywiste), że gdy w programie chcemy wywołać dowolną systemową procedurę z ROM, a jest on aktualnie odłączony, to trzeba go sobie włączyć:
lda #%11111111
sta PORTB ;$D301
jsr JSIOINT ;$E459
Odwołania do procedur OS-a odbywają się przez tablice wektorów oraz tablicę skoków. Stanowią one oficjalne punkty wejścia do procedur systemu operacyjnego i gwarantują, że niezależnie od wersji oraz rodzaju systemu operacyjnego zainstalowanego w komputerze zawsze zostanie wywołana procedura żądana przez użytkownika.
Wyjątek stanowią procedury pakietu matematycznego który nie posiada tablicy skoków, przez co odpowiednie procedury niezależnie od wersji pakietu zainstalowanego w komputerze zawsze muszą znajdować się pod ustalonymi adresami.
Wywołania przez systemową tablicę skoków (JMP), najprościej zrealizować n.p. tak:
JSIOINTjump:
lda PORTB ;$D301
pha
ora #%00000001
sta PORTB ;$D301
jsr JSIOINT ;$E459
pla
sta PORTB ;$D301
rts
Nieco odmienna jest metoda wywoływania procedur dostępnych przez tablicę wektorów, ponieważ wektory wskazują adres procedury zmniejszony o jeden i jako takie służą do wykonania skoku przez RTS:
SIO_S_SPECIAL_jump:
lda PORTB
pha
ora #%00000001
sta PORTB
jsr ?call
pla
sta PORTB
rts
?call lda $E410+$0A+1
pha
lda $E410+$0A
pha
rts
Ta metoda powinna być używana również do wywołania procedury PUTBT dostępnej w rejestrze ICPUTB bloku IOCB.
Rejestry OS w RAM
Rejestry $00..$7F oraz $2xx i $3xx są to rejestry zarezerwowane dla potrzeb systemu operacyjnego.
DLI
W przypadku gdy w programie używane jest przerwanie Display List, które zazwyczaj jest krytyczne czasowo, można zmodyfikować punkt wejścia do przerwania NMI tak, aby zagwarantować identyczne zależności czasowe jak w przypadku gdy przerwanie obsługiwane jest bezpośrednio przez procedurę systemu operacyjnego:
nmiint bit NMIST ;$D40F
spl
jmp (VDSLST) ;$0200
sec
scs
irqint clc
...
Należy jednak pamiętać, że po wejściu do procedury obsługi przez wektor VDSLST ($200) nie ma gwarancji że ROM jest włączony. Jeśli więc w procedurze obsługi przerwania DLI chcemy użyć jakiejś procedury z ROM należy osobiście zadbać o poprawne skonfigurowanie pamięci, oraz odtworzenie jej przed wyjściem z przerwania n.p. tak:
custom_dli:
pha
lda PORTB
pha
ora #%00000001
sta PORTB
...
jsr _jakas_procedura_os_
...
pla
sta PORTB
pla
rti
lub też wykorzystać wyżej wspomnianą "przelotkę":
custom_dli:
pha
...
jsr _jakas_procedura_os_jump
...
pla
rti
Trivia
Opisana tutaj sztuczka jest stosowana między innymi przez Turbo BASIC XL, U-BASIC oraz SpartaDOS X.
