Programowanie: Użycie OS-a przy wyłączonym ROM-ie

From Atariki

(Różnice między wersjami)
Jump to: navigation, search
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.

Personal tools