Programowanie: Użycie OS-a przy wyłączonym ROM-ie: Różnice pomiędzy wersjami

Z Atariki
Przejdź do nawigacji Przejdź do wyszukiwania
Mono (dyskusja | edycje)
m →Przelotki: obszar krytyczny
Mono (dyskusja | edycje)
m →Przelotki: function not implemented
 
(Nie pokazano 38 pośrednich wersji utworzonych przez tego samego użytkownika)
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 96: Linia 99:
= Przelotki =
= Przelotki =


Wygodnym sposobem realizowania skoków do procedur OS jest zdefiniowanie tzw. "przelotek", które zadbają o konfigurację pamięci i jej odtworzenie już po wykonaniu skoku.
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.


Takie "przelotki" analogicznie, jak procedura handlera przerwań powinna również znajdować się poza obszarem ROM ($A000..$BFFF, $C000..$FFFF).
<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]]:
Wywołania przez systemową [[Tablica_skok%C3%B3w|tablicę skoków]]:
Linia 117: Linia 120:
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:
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 129: 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 135: 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
        ldy #$92        ;FUNCTION NOT IMPLEMENTED
        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 150: Linia 178:


         sec
         sec
         scs
         .byte $24        ;BIT $18


irqint  clc
irqint  clc
Linia 156: Linia 184:
         ...
         ...
</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 185: Linia 213:
         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 z 3 lip 2024, 13:05

Ż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

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
        ldy #$92         ;FUNCTION NOT IMPLEMENTED
        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