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

From Atariki

(Różnice między wersjami)
Jump to: navigation, search
Wersja z dnia 22:39, 3 gru 2019
Mono (Dyskusja | wkład)
(tablice skokow i wektorow)
← Previous diff
Aktualna wersja
Mono (Dyskusja | wkład)
(Handler - minimalizacja czasu kiedy przerwanie wskazuje przez wektor w ram)
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 procedur przerwań umieszczonych w [[ROM]]-ie w sytuacji kiedy ten jest wyłączony.
= Handler = = 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, w którym może się pojawić ROM (patrz "Restrykcje pamięciowe"):
<pre> <pre>
nmiint sec nmiint sec
- scs+ .byte $24 ;BIT $18 ($18 to opcode CLC niżej)
irqint clc irqint clc
 +
 + ;wlaczenie OS ROM
 +
 + inc PORTB ;$D301
pha pha
Linia 14: Linia 18:
pha pha
tsx tsx
- 
- ;wlaczenie OS ROM 
- 
- inc PORTB ;$D301 
;odlozenie na stos danych dla powrotu z przerwania (RTI) ;odlozenie na stos danych dla powrotu z przerwania (RTI)
Linia 34: Linia 34:
jmp (IRQVEC) ;$FFFE jmp (IRQVEC) ;$FFFE
-iret ;wylaczenie OS ROM+iret pla
 + tax
 + pla
 + 
 + ;wylaczenie OS ROM
dec PORTB ;$D301 dec PORTB ;$D301
- 
- pla 
- tax 
- pla 
rti rti
</pre> </pre>
Linia 72: Linia 72:
= Działanie = = 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 OS ROM jest włączony przerwanie obsługiwane jest przez standardowe procedury umieszczone w systemie operacyjnym (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.+Kiedy OS 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 zależnie od rodzaju zgłoszonego przerwania.
-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:+W obydwu przypadkach ma ona za zadanie włączenie ROM-u, wykonanie procedury obsługi przerwania według wektora znajdującego się już w ROM, oraz przywrócenie konfiguracji pamięci 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 zawartości rejestru stanu F procesora odłożonego na stos w sekwencji wywołania przerwania. Zduplikowanie tej wartości jest niezbędne dla poprawnego działania systemowych procedur obsługi przerwań (tylko wartość rejestru F odłożona na stosie zawiera poprawne wartości znaczników I i B), ponieważ testują one:
* czy przerwane zostało wykonanie przerwania IRQ (w przypadku obsługi przerwania NMI), * 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). * 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).
 +
 +Podczas obsługi przerwania IRQ może się zdarzyć, że nadejdzie nowe zgłoszenie IRQ. W tej sytuacji, po powrocie z procedury obsługi bieżącego przerwania a jeszcze przed wykonaniem procedury iret, obsłużone zostanie nowe przerwanie za pomocą systemowej procedury zawartej w ROM. Dzieje się tak z powodu duplikacji rejestru F odkładanego na stos w procedurze irqint, w którym znacznik I jest zgaszony. Dopiero po zakończeniu obsługi wszystkich zgłoszonych przerwań następuje wykonanie procedury iret przywracającej konfigurację PORTB.
= Wywoływanie procedur OS = = Wywoływanie procedur OS =
Linia 94: Linia 97:
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. 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:+= Przelotki =
 + 
 +Wygodnym sposobem realizowania skoków do procedur OS jest zdefiniowanie tzw. "przelotek", które zadbają o konfigurację pamięci i jej odtworzenie po powrocie z procedury.
 + 
 +<b>UWAGA!</b> Takie "przelotki" analogicznie, jak procedura handlera przerwań, powinny również znajdować się poza obszarem, w którym może pojawić się ROM (patrz "Restrykcje pamięciowe").
 + 
 +Wywołania przez systemową [[Tablica_skok%C3%B3w|tablicę skoków]]:
<pre> <pre>
-JSIOINTjump:+JSIOINT_jump:
lda PORTB ;$D301 lda PORTB ;$D301
pha pha
Linia 109: Linia 118:
</pre> </pre>
-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:+Nieco odmienna jest metoda wywoływania procedur dostępnych przez [[Tablice_wektor%C3%B3w_ROM|tablicę wektorów]], ponieważ wektory wskazują adres procedury zmniejszony o jeden i jako takie służą do wykonania skoku przez RTS:
<pre> <pre>
-SIO_S_SPECIAL_jump:+CIO_S_SPECIAL_jump:
lda PORTB lda PORTB
pha pha
Linia 123: Linia 132:
rts rts
-?call lda $E410+$0A+1+?call lda $E410+$0A+1 ;tablica handlera S: wektor SPECIAL
pha pha
lda $E410+$0A lda $E410+$0A
Linia 129: Linia 138:
rts rts
</pre> </pre>
-Ta metoda powinna być używana również do wywołania procedury PUTBT dostępnej w rejestrze ICPUTB bloku IOCB.+Ta metoda powinna być używana również do wywołania procedury PUTBT dostępnej w rejestrze ICPUTB bloku IOCB n.p.
 +<pre>
 +;IN: X-IOCB#*16, A-data
 +;OUT: Y-status, N-error flag
 +CIO_PUTBT_jump:
 + tay
 + lda PORTB
 + pha
 + ora #%00000001
 + sta PORTB
 + 
 + jsr ?call
 + 
 + pla
 + sta PORTB
 + cpy #0
 + rts
 + 
 +?call lda ICPUTB+1,x
 + pha
 + lda ICPUTB,x ;$0346
 + pha
 + tya
 + rts
 +</pre>
= Rejestry OS w RAM = = 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ą zarezerwowane dla potrzeb systemu operacyjnego.
= DLI = = DLI =
Linia 144: Linia 177:
sec sec
- scs+ .byte $24 ;BIT $18
irqint clc irqint clc
Linia 150: Linia 183:
... ...
</pre> </pre>
-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:+Należy jednak pamiętać, że wtedy 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:
<pre> <pre>
custom_dli: custom_dli:
Linia 161: Linia 194:
... ...
- jsr _jakas_procedura_os_+ jsr OS_ROUTINE
... ...
Linia 169: Linia 202:
rti rti
</pre> </pre>
-lub też wykorzystać wyżej wspomnianą "przelotkę":+lub też wykorzystać opisane wyżej "przelotki":
<pre> <pre>
custom_dli: custom_dli:
pha pha
... ...
- jsr _jakas_procedura_os_jump+ jsr OS_ROUTINE_jump
... ...
pla pla
rti rti
</pre> </pre>
 +Trzeba to mieć też na uwadze kiedy w procedurze DLI wykorzystuje się dane lub procedury leżące pod ROM-em i w analogiczny sposób zagwarantować odpowiednią konfigurację PORTB.
 +
 +<b>UWAGA!</b> Wektor VDSLST powinien wskazywać na procedurę obsługi DLI zdefiniowaną przez użytkownika i znajdującą się poza obszarem w którym może pojawić się ROM (patrz "Restrykcje pamięciowe").
 +
 += Restrykcje pamięciowe =
 +
 +Procedury handlera, "przelotek" czy procedur obsługi przerwań zdefiniowanych przez użytkownika (a także procedura inicjalizacji całego mechanizmu) powinny znajdować się w RAM poza obszarami w których istnieje ryzyko pojawienia się pamięci ROM, a takim ryzykiem obarczone są:
 +
 +* $5000..$57FF - [[SELF TEST|SELF-TEST]], lub [[MapRAM]]
 +* $8000..$9FFF - [[Cartridge|cartridge]]
 +* $A000..$BFFF - [[Cartridge|cartridge]], wbudowany [[Atari BASIC]] (XL/XE), wbudowana gra ([[XEGS]])
 +* $C000..$CFFF - [[XL OS|OS]] ROM
 +* $D000..$D7FF - obszar rejestrów hardware
 +* $D800..$DFFF - [[XL OS|OS]] ROM ([[Pakiet matematyczny|pakiet matematyczny]]) lub ROM [[Nowe urządzenia|nowego urządzenia]]
 +* $E000..$FFFF - [[XL OS|OS]] ROM
 +
 +W przypadku gdy wykorzystywana jest pamięć dodatkowa ([[130XE|XE]]) również obszar $4000..$7FFF jest obszarem ryzykownym.
 +
 +Jeśli programista może zagwarantować, że określony rodzaj pamięci nie będzie nigdy przełączany, wtedy oczywiście procedury obsługi przełączania pamięci mogą być umieszczone w odnośnym obszarze (z oczywistych przyczyn obszar rejestrów hardware ani OS ROM do takich nie należy).
= Trivia = = Trivia =
Opisana tutaj sztuczka jest stosowana między innymi przez [[Turbo BASIC XL]], [[U-BASIC]] oraz [[SpartaDOS X]]. Opisana tutaj sztuczka jest stosowana między innymi przez [[Turbo BASIC XL]], [[U-BASIC]] oraz [[SpartaDOS X]].
 +
 += Linki =
 +
 +* http://www.atari.org.pl/forum/viewtopic.php?id=7336 - dyskusja na forum AtariArea
 +* [[Mapa pamięci]]
[[Kategoria:Niezbędnik kodera]] [[Kategoria:Niezbędnik kodera]]

Aktualna wersja

Ż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 procedur przerwań umieszczonych w ROM-ie w sytuacji kiedy ten jest wyłączony.

Spis treści

Handler

Kod handlera przerwań powinien być umieszczony poza obszarem, w którym może się pojawić ROM (patrz "Restrykcje pamięciowe"):

nmiint  sec
        .byte $24       ;BIT $18 ($18 to opcode CLC niżej)

irqint  clc

        ;wlaczenie OS ROM

        inc PORTB       ;$D301

        pha
        txa
        pha
        tsx

        ;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    pla
        tax
        pla

        ;wylaczenie OS ROM

        dec PORTB       ;$D301
        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 OS ROM jest włączony przerwanie obsługiwane jest przez standardowe procedury umieszczone w systemie operacyjnym (ponieważ wektory NMIVEC oraz IRQVEC znajdują się wtedy w obszarze ROM).

Kiedy OS 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 zależnie od rodzaju zgłoszonego przerwania. W obydwu przypadkach ma ona za zadanie włączenie ROM-u, wykonanie procedury obsługi przerwania według wektora znajdującego się już w ROM, oraz przywrócenie konfiguracji pamięci 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 zawartości rejestru stanu F procesora odłożonego na stos w sekwencji wywołania przerwania. Zduplikowanie tej wartości jest niezbędne dla poprawnego działania systemowych procedur obsługi przerwań (tylko wartość rejestru F odłożona na stosie zawiera poprawne wartości znaczników I i B), 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).

Podczas obsługi przerwania IRQ może się zdarzyć, że nadejdzie nowe zgłoszenie IRQ. W tej sytuacji, po powrocie z procedury obsługi bieżącego przerwania a jeszcze przed wykonaniem procedury iret, obsłużone zostanie nowe przerwanie za pomocą systemowej procedury zawartej w ROM. Dzieje się tak z powodu duplikacji rejestru F odkładanego na stos w procedurze irqint, w którym znacznik I jest zgaszony. Dopiero po zakończeniu obsługi wszystkich zgłoszonych przerwań następuje wykonanie procedury iret przywracającej konfigurację PORTB.

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.

Przelotki

Wygodnym sposobem realizowania skoków do procedur OS jest zdefiniowanie tzw. "przelotek", które zadbają o konfigurację pamięci i jej odtworzenie po powrocie z procedury.

UWAGA! Takie "przelotki" analogicznie, jak procedura handlera przerwań, powinny również znajdować się poza obszarem, w którym może pojawić się ROM (patrz "Restrykcje pamięciowe").

Wywołania przez systemową tablicę skoków:

JSIOINT_jump:
        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:

CIO_S_SPECIAL_jump:
        lda PORTB
        pha
        ora #%00000001
        sta PORTB

        jsr ?call

        pla
        sta PORTB
        rts

?call   lda $E410+$0A+1  ;tablica handlera S: wektor SPECIAL
        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 n.p.

;IN: X-IOCB#*16, A-data
;OUT: Y-status, N-error flag
CIO_PUTBT_jump:
        tay
        lda PORTB
        pha
        ora #%00000001
        sta PORTB

        jsr ?call

        pla
        sta PORTB
        cpy #0
        rts

?call   lda ICPUTB+1,x
        pha
        lda ICPUTB,x     ;$0346
        pha
        tya
        rts

Rejestry OS w RAM

Rejestry $00..$7F oraz $2xx i $3xx są 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
        .byte $24        ;BIT $18

irqint  clc

        ...

Należy jednak pamiętać, że wtedy 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 OS_ROUTINE
        ...

        pla
        sta PORTB
        pla
        rti

lub też wykorzystać opisane wyżej "przelotki":

custom_dli:
        pha
        ...
        jsr OS_ROUTINE_jump
        ...
        pla
        rti

Trzeba to mieć też na uwadze kiedy w procedurze DLI wykorzystuje się dane lub procedury leżące pod ROM-em i w analogiczny sposób zagwarantować odpowiednią konfigurację PORTB.

UWAGA! Wektor VDSLST powinien wskazywać na procedurę obsługi DLI zdefiniowaną przez użytkownika i znajdującą się poza obszarem w którym może pojawić się ROM (patrz "Restrykcje pamięciowe").

Restrykcje pamięciowe

Procedury handlera, "przelotek" czy procedur obsługi przerwań zdefiniowanych przez użytkownika (a także procedura inicjalizacji całego mechanizmu) powinny znajdować się w RAM poza obszarami w których istnieje ryzyko pojawienia się pamięci ROM, a takim ryzykiem obarczone są:

W przypadku gdy wykorzystywana jest pamięć dodatkowa (XE) również obszar $4000..$7FFF jest obszarem ryzykownym.

Jeśli programista może zagwarantować, że określony rodzaj pamięci nie będzie nigdy przełączany, wtedy oczywiście procedury obsługi przełączania pamięci mogą być umieszczone w odnośnym obszarze (z oczywistych przyczyn obszar rejestrów hardware ani OS ROM do takich nie należy).

Trivia

Opisana tutaj sztuczka jest stosowana między innymi przez Turbo BASIC XL, U-BASIC oraz SpartaDOS X.

Linki

Personal tools