Rozdział 2
PROCEDURY STARTU KOMPUTERA
2.1. Główna procedura RESET
Po włączeniu zasilania komputera oraz po naciśnięciu
klawisza RESET, który zeruje układy komputera, konieczne jest
zainicjowanie pracy systemu. Zadanie to wykonuje procedura
RESET mająca dwa warianty przebiegu.
Wariant zimnego startu (RESET COLD) jest wykonywany zawsze
po włączeniu zasilania (tzw. Power Up). Po naciśnięciu klawisza
RESET wykonywany jest wariant startu gorącego (RESET WARM).
Należy pamiętać, że dokonanie zmian w niektórych rejestrach
systemowych w obszarze RAM może spowodować przejście z
procedury startu gorącego do startu zimnego. Odwrotna zmiana
wariantu procedury jest niemożliwa.
2.1.1. Struktura procedury RESET
Cały przebieg procedury startu jest bardzo skomplikowany,
zostanie więc przedstawiony etapami poczynając od schematu
blokowego.
<RESET>
|
+-----+
| SEI |
+-----+
|
v
+-------------+
| sprawdzenie |
| zawartości | niepoprawna
| rejestrów |---->-----+
| PUPBT1-3 | |
+-------------+ |
| |
poprawna | |
v |
<RESETWM> |
| |
v |
/---------\ |
/ cartridge \ tak v
< wyjęty lub >----->--->+
\ włożony ? / |
\---------/ |
| nie |
| |
v |
/-----------\ |
nie / czy jest \ |
+-<----< dołączony > |
| \ cartridge ? / |
| \-----------/ |
| | tak |
| v |
| ++---------++ |
| || NEWCART || |
| ++---------++ |
| | |
| v |
| /-------\ tak |
| < nowy? >--->------->+
| \-------/ |
| | nie |
| v |
+--------------+ |
| | <POWER UP>
v | |
/--------\ nie v |
< COLDST=0 >--->------>+<-------+
\--------/ |
tak | |
| <RESETCD>
| |
v v
+------------| +----------+
| WARMST=$FF | | WARMST=0 |
+------------+ +----------+
| |
+------->+<------+
|
v
+-----+
| SEI |
| CLD |
+-----+
|
v
++--------++
|| CARTGO ||
++--------++
|
|
v
nie /--------\ tak
+---<----< WARMST=0 >---->---+
| \--------/ |
v v
<WARM2> +---------------+
| | zerowanie RAM |
v | w obszarze |
tak /-------\ | $0008-$FFFF |
+-<----< DERRF=0 > +---------------+
| \-------/ |
| | nie v
| v +----------------+
| +----------+ | DOSVEC=TESTROM |
| | APPMHI=0 | +----------------+
| +----------+ |
| | v
+---------+ | +-------------+
| | | sprawdzenie |
v v | pamięci ROM |
+---------------+ +-------------+
| zerowanie RAM | |
| w obszarach | v
| $0200-$03ED | +------------+
| i $10-$7F | | COLDST=$FF |
+---------------+ +------------+
| |
+------------->+<-------------+
|
v
<COLD2>
|
v
/----------\
tak / czy BASIC \ nie
+--<---< jest >--->--+
| \ dołączony? / |
| \----------/ |
+----------+ +----------+
| BASICF=0 | | BASICF=1 |
+----------+ +----------+
| |
+------------->+<------------+
|
|
v
+--------------+
| ustawienie |
| PUPBT1-3 |
| i marginesów |
+--------------+
|
+--------------+
| ustawienie |
| parametrów |
| zależnych od |
| systemu TV |
+--------------+
|
+---------------+
| przeniesienie |
| wektorów |
| przerwań |
| i tabeli |
| sterowników |
| z ROM do RAM |
+---------------+
|
v
++---------++
|| SYSINIT ||
++---------++
|
/---------\
/ udane \nie ++---------++
< inicjowanie >-->|| TESTINI ||
\ systemu ? / ++---------++
\---------/
| tak
v
nie /----------\
+----<---< RAMSIZ>$B0 >
| \----------/
v | tak
/----------\ |
/ czy jest \ nie v
< w gnieździe >--->-->+
\ cartridge? / |
\----------/ |
tak | |
| |
v |
++---------++ |
|| NEWCART || |
++---------++ |
| |
v |
++----------++ |
|| INITCART || |
++----------++ |
| v
+------------->+
|
v
+-----------+
| otwarcie |
| edytora |
+-----------+
|
v
/-------\ nie +-------+
< udane ? >------>| RESET |
\-------/ +-------+
tak |
v
++---------++
|| CASBOOT ||
++---------++
|
v
nie /---------------\ tak
+---<---< jest cartridge? >--->---+
| \---------------/ |
| v
| /---------\
v tak / wykonać \
+<-------------------<---< odczyt >
| \ z dysku ? /
v \---------/
++------++ nie |
|| BOOT || |
++------++ |
| |
+--------------->+<-------------+
|
|
v
+----------+
| COLDST=0 |
+----------+
|
v
nie /---------------\ tak
+---<---< jest cartridge? >---+
| \---------------/ |
| v
| /---------------\
v nie / przekazać \
+<--------------<---< sterowanie >
| \ do cartridge'a? /
| \---------------/
| tak |
v v
++--------++ ++---------++
|| DOSVEC || || CARTRUN ||
++--------++ ++---------++
2.1.2. Przebieg procedury RESET
Po włączeniu zasilania układy wewnętrzne komputera
ustawiają (na drodze sprzętowej) licznik programu procesora na
wartość RESETCD ($C2C8). Po przekazaniu sterowania procesorowi
zaczyna on wykonywanie programu od tego właśnie miejsca.
Odmiennie zachowuje się procesor po otrzymaniu sygnału
RESET. Pobiera on dwa bajty z rejestru RESETVEC ($FFFC) i
umieszcza je w liczniku programu. Ta operacja także dokonywana
jest sprzętowo. W komputerach Atari w rejestrze RESETVEC
znajduje się adres procedury RESET ($C2AA). Od tego więc
miejsca kontynuowane jest wykonywanie programu.
Zasadnicza procedura RESET przedstawia się następująco:
0100 ; RESET 0270 DERRF = $03EC
0110 ; 0280 DLIV = $0200
0120 APPMHI = $0E 0290 DOSVEC = $0A
0130 BASICF = $03F8 0300 GINTLK = $03FA
0140 BOOT = $C58B 0310 HATABS = $031A
0150 CARTGO = $C471 0320 ICAX1 = $034A
0160 CARTINI = $BFFE 0330 ICBUFA = $0344
0170 CARTINS = $BFFC 0340 ICCMD = $0342
0180 CARTOPT = $BFFD 0350 INIT31A = $C42E
0190 CARTRUN = $BFFA 0360 INIT200 = $C44B
0200 CASBOOT = $C66E 0370 JCIOMAIN = $E456
0210 CHBAS = $02F4 0380 KEYREP = $02DA
0220 CHACTL = $02F3 0390 KRPDEL = $02D9
0230 CKROM1 = $FF73 0400 LINKSOM = $E739
0240 CKROM2 = $FF92 0410 LMARGIN = $52
0250 COLDST = $0244 0420 LNFLG = $00
0260 DDEVIC = $0300 0430 NEWCART = $C4C9
0440 NGFLAG = $01 1000 BNE WARM2
0450 PAL = $D014 1010 LDA #$00
0460 PALNTS = $62 1020 LDY #$08
0470 PORTB = $D301 1030 STA RAMLO
0480 PUPBT1 = $033D 1040 STA RAMLO+1
0490 PUPBT2 = $033E 1050 LOOP LDA #$FF
0500 PUPBT3 = $033F 1060 STA (RAMLO),Y
0510 RAMLO = $04 1070 CMP (RAMLO),Y
0520 RAMSIZ = $02E4 1080 BEQ OK1
0530 RMARGIN = $53 1090 LSR NGFLAG
0540 SYSINIT = $C535 1100 OK1 LDA #$00
0550 TESTINI = $5003 1110 STA (RAMLO),Y
0560 TESTROM = $F223 1120 CMP (RAMLO),Y
0570 TRAMSZ = $06 1130 BEQ OK2
0580 TRIG3 = $D013 1140 LSR NGFLAG
0590 WARMST = $08 1150 OK2 INY
0600 ; 1160 BNE LOOP1
0610 *= $C290 1170 INC RAMLO+1
0620 ; 1180 LDX RAMLO+1
0630 RESETWM SEI 1190 CPX TRAMSZ
0640 LDA TRIG3 1200 BNE LOOP1
0650 CMP GINTLK 1210 LDA # <TESTROM
0660 BNE RESETCD 1220 STA DOSVEC
0670 ROR A 1230 LDA # >TESTROM
0680 BCC OLDCART 1240 STA DOSVEC+1
0690 JSR NEWCART 1250 LDA PORTB
0700 BNE RESETCD 1260 AND #$7F
0710 OLDCART LDA COLDST 1270 STA PORTB
0720 BNE RESETCD 1280 JSR CKROM1
0730 LDA #$FF 1290 BCS BAD
0740 BNE CONT 1300 JSR CKROM2
0750 RESET SEI 1310 BCC ROMOK
0760 LDX #$8C 1320 BAD LSR NGFLAG
0770 DELAY1 DEY 1330 ROMOK LDA PORTB
0780 BNE DELAY1 1340 ORA #$80
0790 DEX 1350 STA PORTB
0800 BNE DELAY1 1360 LDA #$FF
0810 LDA PUPBT1 1370 STA COLDST
0820 CMP #$5C 1380 BNE COLD2
0830 BNE RESETCD 1390 WARM2 LDX #$00
0840 LDA PUPBT2 1400 LDA DERRF
0850 CMP #$93 1410 BEQ LOOP2
0860 BNE RESETCD 1420 STX APPMHI
0870 LDA PUPBT3 1430 STX APPMHI+1
0880 CMP #$25 1440 TXA
0890 BEQ RESETWM 1450 LOOP2 STA DLIV,X
0900 RESETCD LDA #$00 1460 CPX #$ED
0910 CONT STA WARMST 1470 BCS BYPASS
0920 SEI 1480 STA DDEVIC,X
0930 CLD 1490 BYPASS DEX
0940 LDX #$FF 1500 BNE LOOP2
0950 TXS 1510 LDX #$10
0960 JSR CARTGO 1520 LOOP3 STA LNFLG,X
0970 LDA #$01 1530 INX
0980 STA NGFLAG 1540 BPL LOOP3
0990 LDA WARMST 1550 COLD2 LDX #$00
1560 LDA PORTB 2060 NOERR LDX #$00
1570 AND #$02 2070 STX TRAMSZ
1580 BEQ BASICON 2080 LDX RAMSIZ
1590 INX 2090 CPX #$B0
1600 BASICON STX BASICF 2100 BCS NOCART
1610 LDA #$5C 2110 LDX CARTINS
1620 STA PUPBT1 2120 BNE NOCART
1630 LDA #$93 2130 INC TRAMSZ
1640 STA PUPBT2 2140 JSR NEWCART
1650 LDA #$25 2150 JSR INITCART
1660 STA PUPBT3 2160 NOCART LDA #$03
1670 LDA #$02 2170 LDX #$00
1680 STA LMARGIN 2180 STA ICCMD,X
1690 LDA #$27 2190 LDA # <NAME
1700 STA RMARGIN 2200 STA ICBUFA,X
1710 LDA PAL 2210 LDA # <NAME
1720 AND #$0E 2220 STA ICBUFA+1,X
1730 BNE TVPAL 2230 LDA #$0C
1740 LDA #$05 2240 STA ICAX1,X
1750 LDX #$01 2250 JSR JCIOMAIN
1760 LDY #$28 2260 BPL DELAY2
1770 BNE SETTV 2270 JMP RESET
1780 TVPAL LDA #$06 2280 DELAY2 INX
1790 LDX #$00 2290 BNE DELAY2
1800 LDY #$30 2300 INY
1810 SETTV STA KEYREP 2310 BPL DELAY2
1820 STX PALNTS 2320 JSR CASBOOT
1830 STY KRPDEL 2330 LDA TRAMSZ
1840 LDX #$25 2340 BEQ DBOOT
1850 LOOP4 LDA INIT200,X 2350 LDA CARTBOOT
1860 STA DLIV,X 2360 ROR A
1870 DEX 2370 BCC NOBOOT
1880 BPL LOOP4 2380 DBOOT JSR BOOT
1890 LDX #$0E 2390 JSR LINKSOM
1900 LOOP5 LDA INIT31A,X 2400 NOBOOT LDA #$00
1910 STA HATABS,X 2410 STA COLDST
1920 DEX 2420 LDA TRAMSZ
1930 BPL LOOP5 2430 BEQ DOSVECC
1940 JSR SYSINIT 2440 LDA CARTOPT
1950 CLI 2450 AND #$04
1960 LDA NGFLAG 2460 BEQ DOSVECC
1970 BNE NOERR 2470 COLDCART JMP (CARTRUN)
1980 LDA PORTB 2480 DOSVECC JMP (DOSVEC)
1990 AND #$7F 2490 INITCART JMP (CARTINI)
2000 STA PORTB 2500 CLCRTS CLC
2010 LDA #$02 2510 RTS
2020 STA CHACTL 2520 ;
2030 LDA #$E0 2530 *= $C448
2040 STA CHBAS 2540 NAME .BYTE "E:",$9B
2050 GOMEMTST JMP TESTINI
Przebieg procedury RESET zależy w znacznym stopniu od
rodzaju startu (zimny czy gorący). Przy gorącym starcie przede
wszystkim kontrolowane są różne rejestry systemowe w celu
sprawdzenia, czy nie zachodzi konieczność wykonania zimnego
startu.
Najpierw sprawdzane są trzy rejestry PUPBT (Power UP Byte),
które muszą zawierać ściśle określone wartości - kolejno $5C,
$93 i $25. W następnej kolejności kontrolowana jest obecność
cartridge'a oraz jego rodzaj. Jeżeli został on wyjęty, włożony
lub zamieniony, to cały system inicjowany jest ponownie.
Wykorzystywany tu rejestr TRIG3 jest ustawiany na drodze
sprzętowej i zawiera 1, jeśli jest dołączony zewnętrzny
cartridge. Wartość rejestru GINTLK jest ustalana według TRIG3
podczas inicjowania komputera. Niezgodność ich zawartości
powoduje więc przejście do zimnego startu.
Na końcu tego etapu kontrolowany jest wskaźnik COLDST.
Jeżeli jego wartość jest różna od zera, także następuje
przejście do zimnego startu. Gdy wszystkie sprawdzenia wypadły
pomyślnie, wskaźnik WARMST uzyskuje wartość $FF (służy on
póżniej do rozróżniania rodzaju startu.
Jeżeli zostało włączone zasilanie lub system rozpoznał
konieczność dokonania zimnego startu, to wskaźnik WARMST jest
ustawiany na wartość zero. Od tego miejsca obie procedury
przebiegają wspólnie.
Następnie wywoływana jest procedura CARTGO, która sprawdza
obecność cartridge'a i rozpoznaje jego rodzaj, inicjuje porty
I/O, oraz sprawdza wielkość dostępnej pamięci RAM. Obliczona
wielkość RAM (w stronach) jest umieszczana w rejestrze TRAMSZ.
Kolejnym etapem jest zerowanie pamięci RAM. Przy starcie
zimnym kasowana jest zawartość całej pamięci od adresu $08 do
wartości umieszczonej w TRAMSZ. Podczas startu gorącego
wyzerowaniu ulegają jedynie obszary od $10 do $7F oraz od $0200
do $03ED. Procedura zimnego startu sprawdza jeszcze poprawność
pamięci ROM przez przeliczenie sum kontrolnych oraz ustawia
wskaźnik COLDST na wartość $FF i wektor DOSVEC na adres
procedury TESTROM.
Teraz następuje ustawienie wartości w rejestrach systemu
operacyjnego w pamięci RAM. Najpierw wskaźnik BASICF otrzymuje
wartość 0, gdy interpreter Basica jest dołączony lub 1, gdy
jest odłączony. Do rejestrów PUPBT wpisywane są odpowiednie
wartości (zob. wyżej) oraz ustawiane są marginesy ekranu. Po
rozpoznaniu według zawartości rejestru PAL rodzaju systemu
telewizyjnego (PAL czy NTSC) ustalane są wartości zmiennych
systemowych zależnych od częstotliwości zegara taktującego (PAL
ma 50 Hz, a NTSC - 60 Hz). Są to wielkości określające szybkość
powtarzania klawisza (KEYREP) oraz czas rozpoczęcia powtarzania
przy stałym jego wciśnięciu (KRPDEL).
Wektory systemu znajdujące się na drugiej stronie pamięci
są teraz przepisywane z tabeli INIT200, która jest umieszczona
w ROM-ie. Tabela ta zawiera systemowe wektory przerwań
maskowalnych i niemaskowalnych, zajmujące obszar $0200-$0225.
0100 ;INITiation table $200
0110 ;
0120 CPUIRQ = $FC19
0130 EXITVBL = $C28A
0140 ISRODN = $EAAD
0150 ISRSIR = $EB2E
0160 ISRXD = $EAEC
0170 PLARTI = $C0CD
0180 RTI = $C0CE
0190 SINDRYI = $C030
0200 SYSVBL = $C0E2
0210 ZERO = $00
0220 ;
0230 *= $C44B
0240 ;
0250 INIT200 .WORD RTI,PLARTI
0260 .WORD PLARTI,PLARTI
0270 .WORD CPUIRQ,ISRSIR
0280 .WORD ISRODN,ISRXD
0290 .WORD PLARTI,PLARTI
0300 .WORD PLARTI,SINDRYI
0310 .WORD ZERO,ZERO
0320 .WORD ZERO,ZERO
0330 .WORD ZERO,SYSVBL
0340 .WORD EXITVBL
Następnie przenoszona jest tabela adresów procedur obsługi
urządzeń zewnętrznych (HATABS). Nie jest ona wypełniana w
całości, gdyż tabela INIT31A zawiera jedynie adresy procedur
zapisanych w ROM-ie. Znajdują się tam adresy procedur obsługi
edytora (E:), ekranu (S:), klawiatury (K:), drukarki (P:) i
magnetofonu (C:).
0100 ;INITiation table $31A
0110 ;
0120 CASVEC = $E440
0130 EDTVEC = $E400
0140 KBDVEC = $E420
0150 PRTVEC = $E430
0160 SCRVEC = $E410
0170 ;
0180 *= $C42E
0190 ;
0200 INIT31A .BYTE 'P
0210 .WORD PRTVEC
0220 .BYTE 'C
0230 .WORD CASVEC
0240 .BYTE 'E
0250 .WORD EDTVEC
0260 .BYTE 'S
0270 .WORD SCRVEC
0280 .BYTE 'K
0290 .WORD KBDVEC
Procedury obsługi innych urządzeń (np. stacji dysków lub
modemu) są zapisywane w pamięci RAM i dla udostępnienia ich
systemowi operacyjnemu tabela HATABS jest uzupełniana podczas
późniejszego instalowania tych urządzeń.
Po tych wszystkich operacjach wywoływana jest procedura
SYSINIT, która przeprowadza inicjowanie pozostałej części
systemu oraz urządzeń zewnętrznych. Będzie ona dokładnie
opisana w dalszej części.
Błędy występujące podczas wykonywania powyższych procedur
są sygnalizowane w rejestrze NGFLAG. Po zakończeniu SYSINIT
zawartość tego rejestru jest kontrolowana i gdy wskazuje błędy,
to program przechodzi do wbudowanej procedury testowania
komputera (tzw. SELFTEST). W przeciwnym wypadku kontynuowana
jest procedura RESET.
Jeżeli dołączony jest cartridge (rejestr CARTINS ma wartość
1, gdy brak cartridge'a i Basic jest odłączony), to teraz jest
on inicjowany (lecz jeszcze nie uruchamiany). Na zakończenie
tej części kanał IOCBO jest otwierany dla edytora. Gdy przy
otwieraniu wystąpi błąd, następuje skok do początku procedury
RESET.
W tym momencie cały system jest już gotowy do pracy. Teraz
poszukiwane jest wyjście z procedury RESET do programu
użytkownika. Najpierw przez wywołanie CASBOOT dokonywana jest
próba odczytu z kasety. Następnie, po sprawdzeniu, czy nie
zabrania tego zainstalowany cartridge (CARTOPT=0 oznacza zakaz
odczytu), podejmowana jest próba odczytu z dyskietki. Dopiero
po tym wskaźnik COLDST jest ustawiany na wartość 0, która
spowoduje po naciśnięciu klawisza RESET wykonanie gorącego
startu.
Na zakończenie sterowanie komputerem zostaje przekazane pod
adres zawarty w rejestrze DOSVEC (jeżeli nie ma cartridge'a i
nie został dokonany odczyt z kasety lub dyskietki, to nadal
jest tam adres TESTROM) albo, jeśli zainstalowany cartridge
zabraniał odczytu, pod adres zawarty w rejestrze CARTRUN.
Pewną ciekawostką jest umieszczenie na końcu procedury
RESET zupełnie niepotrzebnych tu instrukcji CLC i RTS.
Przewidywano wykorzystanie ich przez różne procedury systemu
operacyjnego, lecz mogą one z powodzeniem zostać użyte w
programie użytkownika.
2.2. Obliczanie sum kontrolnych
Podczas inicjowania komputera sprawdzana jest poprawność
układów pamięci ROM zawierających system operacyjny. Dokonywane
jest to przez zsumowanie zawartości wszystkich bajtów pamięci i
porównanie otrzymanego wyniku z zapisaną w ROM sumą kontrolną.
Ponieważ system operacyjny jest zapisany w dwóch
oddzielnych blokach pamięci, które posiadają odrębne sumy
kontrolne, to sprawdzenie poprawności ROM wykonywane jest przez
dwie procedury - CKROM1 i CKROM2.
Procedura CKROM1 kontroluje pamięć ROM znajdującą się w
obszarach $C002-$CFFF, $5000-$57FF i $D800-$DFFF. Obszary
$E000-$FFF7 i $FFFA-$FFFF są kontrolowane przez procedurę
CKROM2.
Porównanie podanych obszarów ROM ze wskazanymi na początku
książki wykazuje dwie dwubajtowe luki. Są to miejsca
umieszczenia sum kontrolnych, które oczywiście nie podlegają
sprawdzaniu. Pierwszy blok pamięci ma sumę kontrolną pod
adresem $C000 (CHSRO1), a drugi pod $FFF8 (CHSRO2).
0100 ;Check ROM
0110 ;
0120 CHSRO1 = $C000
0130 CHSRO2 = $FFF8
0140 CKSUM = $8B
0150 GETCKS = $FFA9
0160 ;
0170 *= $FF73
0180 ;
0190 CKROM1 LDX #$00
0200 STX CKSUM
0210 STX CKSUM+1
0220 LOOP JSR GETCKS
0230 CPX #$0C
0240 BNE LOOP
0250 LDA CHSRO1
0260 LDX CHSRO1+1
0270 CHECK CMP CKSUM
0280 BNE BAD
0290 CPX CKSUM+1
0300 BNE BAD
0310 CLC
0320 RTS
0330 BAD SEC
0340 RTS
0400 CKROM LDX #$00
0410 STX CKSUM
0420 STX CKSUM+1
0430 LDX #$0C
0440 JSR GETCKS
0450 JSR GETCKS
0460 LDA CHSRO2
0470 LDX CHSRO2+1
0480 JMP CHECK
Przebieg obu procedur jest bardzo prosty. Po wyzerowaniu
rejesrtu CKSUM, w którym będzie zliczana suma bajtów pamięci
ROM, wywoływana jest właściwa procedura obliczająca sumę
kontrolną - GETCKS. Następnie obliczona suma jest porównywana z
sumą zapisaną w ROM. Jeżeli są one równe, to bit przeniesienia
(Carry) w rejestrze statusu procesora jest kasowany, w
przeciwnym razie jest on ustawiany.
Powrót do procedury RESET z ustawionym bitem Carry powoduje
zmianę zawartości rejestru NGFLAG, który służy do kontroli
poprawności inicjowania systemu.
Bezpośrednio obliczająca sumę kontrolną procedura GETCKS
wymaga przy wywołaniu przekazania w rejestrze X numeru
sprawdzanego bloku pamięci. Adres początkowy i końcowy tego
bloku jest pobierany z tabeli CKSTAB.
0100 ;GET ChecK Sum
0110 ;
0120 CKSUM = $8B
0130 TMPREG = $9E
0140 ;
0150 *= $FFA9
0160 ;
0170 LDY #$00
0180 LOOP LDA CKSTAB,X
0190 STA TMPREG,Y
0200 INX
0210 INY
0220 CPX #$04
0230 BNE LOOP
0240 LDY #$00
0250 NEXT CLC
0260 LDA (TMPREG),Y
0270 ADC CKSUM
0280 STA CKSUM
0290 BCC NXT1
0300 INC CKSUM+1
0310 NXT1 INC TMPREG
0320 BNE NXT2
0330 INC TMPREG+1
0340 NXT2 LDA TMPREG
0350 CMP TMPREG+2
0360 BNE NEXT
0370 LDA TMPREG+1
0380 CMP TMPREG+3
0390 BNE NEXT
0400 RTS
0410 ;
0420 CKSTAB
0430 .WORD $C002,$D000
0440 .WORD $5000,$5800
0450 .WORD $D800,$E000
0460 .WORD $E000,$FFF8
0470 .WORD $FFFA,$00
GETCKS najpierw pobiera z CKSTAB adres początkowy i końcowy
sprawdzanego bloku (według wartości X) i umieszcza je w
tymczasowym rejestrze TMPREG. Następnie korzystając z podanych
adresów odczytuje zawartości kolejnych komórek pamięci i dodaje
je do zawartości CKSUM. Po osiągnięciu adresu końcowego
procedura się kończy.
Warto zauważyć, że adres końcowy w tabeli CKSTAB wskazuje
na pierwszą komórkę pamięci nie należącą do badanego bloku.
Jest to spowodowane zwiększaniem adresu na końcu pętli.
Ostatnia informacja dotyczy rejestrów w pamięci RAM
wykorzystywanych przez powyższe procedury. Znajdują się one w
obszarze przeznaczonym dla oprogramowania i po procedurze
inicjowania systemu nie są więcej wykorzystywane przez OS.
Oprócz procedur sprawdzających poprawność pamięci ROM
system operacyjny zawiera jeszcze procedurę obliczającą sumę
kontrolną obszaru $BFF0-$C0EF. Sumuje ona wartości bajtów w tym
obszarze i umieszcza je w rejestrze CARTCK. Ponieważ przedtem
dokonywane jest porównanie obliczonej sumy z aktualną
zawartością tego rejestru, umożliwia to także sprawdzenie, czy
została dokonana zamiana cartridge'a. W tym właśnie celu
procedura NEWCART jest wywoływana na początku procedury
gorącego startu. W przypadku stwierdzenia takiej zamiany
następuje przejście do zimnego startu systemu.
0100 ;NEW CARTridge ?
0110 ;
0120 CART = $BFF0
0130 CARTCK = $03EB
0140 ;
0150 *= $C4C9
0160 ;
0170 LDA #$00
0180 TAX
0190 CLC
0200 LOOP ADC CART,X
0210 INX
0220 BNE LOOP
0230 CMP CARTCK
0240 STA CARTCK
0250 RTS
Niezależnie od rodzaju startu procedura ta jest wywoływana
- gdy cartridge jest dołączony - po zainicjowaniu systemu, a
przed zainicjowaniem cartridge'a.
2.3. Procedury inicjowania bloków systemu
Prawidłowa praca całego systemu komputerowego wymaga
umieszczenia w rejestrach znajdujących się w pamięci RAM oraz w
rejestrach sprzętowych określonych wartości, które będą
wykorzystywane potem przez OS. Czynność ta nazywana jest
inicjowaniem i wykonywana jest przez kilkanaście procedur
wywoływanych kolejno podczas startu systemu.
Jako ostatnia wykonywana jest procedura inicjowania
cartridge'a. (jeśli jest dołączony). Jest ona umieszczona w
cartridge'u, a jej wektor zapisany jest pod adresem $BFFE.
Ponieważ znajduje się ona w cartridge'u, to nie może być tutaj
opisana.
2.3.1. Procedury rozpoznania cartridge'a i RAM
Przed zainicjowaniem system musi sprawdzić, jakimi
dysponuje obszarami pamięci RAM i dodatkowej pamięci ROM
(cartridge). Do tego celu służą procedury CARTGO i GRAMHI.
Procedura CARTGO sprawdza najpierw obecność cartridge'a w
gnieździe i jeśli jest, to jego rodzaj. W przypadku
stwierdzenia obecności cartridge'a diagnostycznego (ustawiony
bit 7 rejestru CARTOPT) dalsze sterowanie jest przekazywane do
niego. W przeciwnym razie dokonywane jest inicjowanie portów
I/O poprzez procedurę IOPORTINI.
Teraz określany jest status wbudowanego interpretera
Basica. Jest on sterowany poprzez bit 1 w PORTB. Jeżeli bit ten
jest skasowany (równy zero), to pamięć ROM zawierająca
interpreter jest dostępna w obszarze $A000-$BFFF. Gdy bit 1 w
PORTB jest ustawiony (równy jeden), układ zarządzania pamięcią
blokuje dostęp do interpretera.
W tej fazie interpreter jest najpierw odłączany. Jeżeli
jest to start zimny, sprawdzany jest rejestr CONSOL
sygnalizujący stan klawiszy konsoli (START, SELECT i OPTION).
Klawiszom tym są przyporządkowane odpowiednio bity 0, 1 i 2.
Normalnie bity te są ustawione i rejestr CONSOL zawiera wartość
$07. Naciśnięcie któregoś klawisza kasuje odpowiadający mu bit.
Gdy bit 2 CONSOL jest ustawiony (klawisz OPTION nie wciśnięty),
interpreter Basica jest ponownie włączany przez skasowanie bitu
1 PORTB.
Podczas startu gorącego włączenie Basica następuje po
stwierdzeniu wartości zero w rejestrze BASICF, który otrzymał
odpowiednią wartość podczas wcześniejszej fazy procedury RESET.
0100 ;CARTridge GOes ?
0110 ;
0120 BASICF = $03F8
0130 CARTINI = $BFFE
0140 CARTINS = $BFFC
0150 CARTOPT = $BFFD
0160 CONSOL = $D01F
0170 IOPORTINI = $C4DA
0180 PORTB = $D301
0190 RAMLO = $04
0200 TRAMSZ = $06
0210 TRIG3 = $D013
0220 WARMST = $08
0230 ;
0240 *= $C471
0250 ;
0260 LDA TRIG3
0270 ROR A
0280 BCC PINI
0290 LDA CARTINS
0300 BNE PINI
0310 LDA CARTOPT
0320 BPL PINI
0330 JMP (CARTINI)
0340 PINI JSR IOPORTINI
0350 LDA PORTB
0360 ORA #$02
0370 STA PORTB
0380 LDA WARMST
0390 BEQ CNSL
0400 LDA BASICF
0410 BNE GRAMHI
0420 BEQ ON
0430 CNSL LDA CONSOL
0440 AND #$04
0450 BEQ GRAMHI
0460 ON LDA PORTB
0470 AND #$FD
0480 STA PORTB
0490 ;
0500 ;Get RAM HIgh
0510 ;
0520 GRAMHI LDA #$00
0530 TAY
0540 STA RAMLO+1
0550 LDA #$28
0560 STA TRAMSZ
0570 LOOP LDA (RAMLO+1),Y
0580 EOR #$FF
0590 STA (RAMLO+1),Y
0600 CMP (RAMLO+1),Y
0610 BNE END
0620 EOR #$FF
0630 STA (RAMLO+1),Y
0640 CMP (RAMLO+1),Y
0650 BNE END
0660 INC TRAMSZ
0670 BNE LOOP
0680 END RTS
CARTGO nie kończy się instrukcją RTS (powrót z procedury),
lecz przechodzi bezpośrednio w procedurę GRAMHI. Sprawdzana
jest tu wielkość dostępnej pamięci RAM mierzona w stronach (po
256 KB). Pierwszy bajt każdej strony pamięci jest dwukrotnie
poddawany operacji EOR (exclusive-or) z wartością $FF i za
każdym razem porównywany ze swoją poprzednią wartością. Jeśli
operacja EOR nie powoduje zmiany zawartości komórki, oznacza
to, że nie jest to komórka pamięci RAM. Aktualnie obliczona
liczba stron pamięci RAM jest zapisywana tymczasowo do rejestru
TRAMSZ.
Warto zauważyć, że przyjęty sposób testowania pamięci RAM
nie powoduje zmiany jej zawartości, dzięki czemu zapisany w
pamięci program nie ulega skasowaniu podczas gorącego startu.
Samo sprawdzanie wielkości RAM jest konieczne z powodu
istnienia różnych odmian komputerów w serii XL i XE oraz
możliwości zainstalowania cartridge'a o wielkości 8 lub 16 KB.
Na przykład model 600XL, mający identyczny system operacyjny,
posiada jedynie 16 KB RAM.
2.3.2. Procedura inicjowania portów I/O.
Gdy nie została stwierdzona obecność cartridge'a
diagnostycznego, to z CARTGO jest wywoływana procedura
IOPORTINI. Jej zadaniem jest zainicjowanie portów I/O. Są to
sprzętowe rejestry wewnętrznych, specjalizowanych układów
komputera, które służą do obsługi urządzeń zewnętrznych i
odciążają w tej pracy jednostkę centralną (procesor 6502).
0100 ;I/O PORT INItiation
0110 ;
0120 ANTIC = $D400
0130 AUDC3 = $D205
0140 AUDC4 = $D207
0150 AUDCTL = $D208
0160 GTIA = $D000
0170 PACTL = $D302
0180 PBCTL = $D303
0190 PIA = $D300
0200 POKEY = $D200
0210 PORTA = $D300
0220 PORTB = $D301
0230 SEROUT = $D20D
0240 SKCTL = $D20F
0250 ;
0260 *= $C4DA
0270 ;
0280 LDA #$00
0290 TAX
0300 STA PBCTL
0310 NEXT STA GTIA,X
0320 STA ANTIC,X
0330 STA POKEY,X
0340 CPX #$01
0350 BEQ BYPASS
0360 STA PIA,X
0370 BYPASS INX
0380 BNE NEXT
0390 LDA #$3C
0400 STA PBCTL
0410 LDA #$FF
0420 STA PORTB
0430 LDA #$38
0440 STA PACTL
0450 STA PBCTL
0460 LDA #$00
0470 STA PORTA
0480 LDA #$FF
0490 STA PORTB
0500 LDA #$3C
0510 STA PACTL
0520 STA PBCTL
0530 LDA PORTB
0540 LDA PORTA
0550 LDA #$22
0560 STA SKCTL
0570 LDA #$A0
0580 STA AUDC3
0590 STA AUDC4
0600 LDA #$28
0610 STA AUDCTL
0620 LDA #$FF
0630 STA SEROUT
0640 RTS
W pierwszej fazie procedury zerowane są wszystkie rejestry
układów GTIA, ANTIC i POKEY oraz rejestry układu PIA z
wyjątkiem PORTB. Wyzerowanie tego rejestru, sterującego
zarządzaniem obszarami pamięci komputera, spowodowałoby
zawieszenie się systemu z powodu odłączenia pamięci ROM
zawierającej system operacyjny.
Najdłuższa część procedury przeznaczona jest na ustalenie
stanu początkowego rejestrów układu PIA. Znaczna długość tej
fazy jest spowodowana specyficznym działaniem układu PIA, w
którym rejestry PORTA i PORTB są sterowane pośrednio poprzez
rejestry PACTL i PBCTL. W rezultacie przeprowadzonych operacji
port A ustawiany jest jako rejestr wejściowy, a port B jako
wyjściowy.
Ostatnią czynnością jest nadanie wartości początkowych
rejestrom POKEY-a, które obsługują zegary transmisji danych
przez złącze szeregowe oraz z klawiatury. Są to rejestry
kontroli generatorów dźwięku AUDC3 i AUDC4 oraz rejestr
kontrolujący wszystkie generatory AUDCTL (dokładny opis ich
funkcji znajduje się w książce "Mapa pamięci Atari XL/XE.
Procedury wejścia/wyjścia" (SOETO, 1988). Od tej chwili
komputer może komunikować się z urządzeniami zewnętrznymi. Do
prawidłowej pracy każde z tych urządzeń wymaga jednak jeszcze
oddzielnego zainicjowania, co wykonuje procedura SYSINIT.
2.3.3. Procedura inicjowania systemu
Najważniejszą z procedur wywoływanych przez RESET jest
procedura SYSINIT, której zadaniem jest właściwe zainicjowanie
pracy całego systemu operacyjnego. Po jej wykonaniu komputer
powinien być gotowy do pracy.
0100 ;SYStem INITiation
0110 ;
0120 BREAKIRQ = $C092
0130 CASVEC = $E440
0140 CKEY = $03E9
0150 CONSOL = $D01F
0160 EDTVEC = $E400
0170 IRQSTAT = $11
0180 JCIOINIT = $E46E
0190 JDSKINIT = $E450
0200 JNMIEN = $E46B
0210 JSIOINIT = $E465
0220 KBDVEC = $E420
0230 MEMLO = $02E7
0240 MEMTOP = $02E5
0250 NEWINITC = $E49B
0260 NEWIOREQ = $C96E
0270 PRTVEC = $E430
0280 RAMSIZ = $02E4
0290 SCRVEC = $E410
0300 TRAMSZ = $06
0310 VBRKEY = $0236
0320 VPIRQ = $0238
0330 ;
0340 *= $C535
0350 ;
0360 DEC IRQSTAT
0370 LDA # <BREAKIRQ
0380 STA VBRKEY
0390 LDA # >BREAKIRQ
0400 STA VBRKEY+1
0410 LDA TRAMSZ
0420 STA RAMSIZ
0430 STA MEMTOP+1
0440 LDA #$00
0450 STA MEMTOP
0460 LDA #$00
0470 STA MEMLO
0480 LDA #$07
0490 STA MEMLO+1
0500 JSR EDTVEC+$0C
0510 JSR SCRVEC+$0C
0520 JSR KBDVEC+$0C
0530 JSR PRTVEC+$0C
0540 JSR CASVEC+$0C
0550 JSR JCIOINIT
0560 JSR JSIOINIT
0570 JSR JNMIEN
0580 JSR JDSKINIT
0590 LDA # <NEWIOREQ
0600 STA VPIRQ
0610 LDA # >NEWIOREQ
0620 STA VPIRQ+1
0630 JSR NEWINITC
0640 LDA CONSOL
0650 AND #$01
0660 EOR #$01
0670 STA CKEY
0680 RTS
W pierwszym kroku procedury kasowane są wszystkie żądania
przerwań maskowalnych IRQ przez ustawienie rejestru IRQSTAT na
wartość $FF ($00-1=$FF). Następnie wektor przerwania
wywoływanego przez klawisz BREAK ustawiany jest na adres
procedury BREAKIRQ.
Ustalona poprzednio wielkość pamięci RAM (zapisana w
TRAMSZ) jest teraz przepisywana do rejestrów MEMTOP i RAMSIZ,
przy czym ten drugi zawiera tylko liczbę stron pamięci. Do
rejestru MEMLO jest natomiast wpisywana wartość $0700, która
określa najniższy adres pamięci dostępny dla oprogramowania. Ma
to na celu ochronę obszaru zmiennych oraz buforów systemowych,
a także rejestrów wykorzystywanych przez oprogramowanie.
Teraz kolejno wywoływane są procedury inicjowania urządzeń
zewnętrznych, a następnie systemowych procedur wejścia/wyjścia
oraz przerwań niemaskowalnych. Do wektora VPIRQ (Vector
Parallel IRQ) jest przy tym wpisywany adres procedury NEWIOREQ,
która obsługuje przerwania wywoływane przez nowe urządzenia.
Ostatnią czynnością jest sprawdzenie w rejestrze CONSOL,
czy został wciśnięty klawisz START. Jeżeli tak, to znacznik
CKEY otrzymuje wartość 1, w przeciwnym wypadku 0.
2.3.4. Procedura inicjowania edytora
Procedura ta jest wywoływana trzykrotnie w celu
zainicjowania kolejno edytora, klawiatury i ekranu. Jej
wywołanie odbywa się pośrednio poprzez adresy skoku umieszczone
w tablicy procedur obsługi. Dla wymienionych urządzeń adresy te
są aktualnie jednakowe i wskazują procedurę POWERON, jednak
takie rozwiązanie umożliwia łatwe wprowadzenie zmian w
ewentualnych, następnych wersjach OS. Jest to jeden z wielu
przykładów dalekowzroczności projektantów Atari.
0100 ;POWER ON action
0110 ;
0120 FKDEF = $FC11
0130 FKDEFP = $60
0140 KBCODES = $02FC
0150 KEYDEF = $FB51
0160 KEYDEFP = $79
0170 RAMSIZ = $02E4
0180 RAMTOP = $6A
0190 SHFOLK = $02BE
0200 ;
0210 *= $EF6E
0220 ;
0230 LDA #$FF
0240 STA KBCODES
0250 LDA RAMSIZ
0260 STA RAMTOP
0270 LDA #$40
0280 STA SHFOLK
0290 LDA # <KEYDEF
0300 STA KEYDEFP
0310 LDA # >KEYDEF
0320 STA KEYDEFP+1
0330 LDA # <FKDEF
0340 STA FKDEFP
0350 LDA # >FKDEF
0360 STA FKDEFP+1
0370 RTS
Procedura POWERON kolejno ustawia wszystkie parametry
niezbędne do pracy edytora (klawiatury i ekranu). Do rejestru
KBCODES wpisywana jest wartość $FF, która oznacza, że nie
został naciśnięty żaden klawisz. Wielkość dostępnej pamięci (w
stronach) przepisywana jest z RAMSIZ do RAMTOP. Wartość $40
umieszczona w SHFOLK oznacza, że klawiatura pracuje w trybie
dużych liter.
Na zakończenie wektory KEYDEFP i FKDEFP są ustawiane na
wartości adresów zawartych w pamięci ROM tabel zawierających
kody klawiszy. Tabela FKDEF dotyczy klawiszy funkcyjnych F1-F4,
które występują jedynie w modelu 1200XL. Ponieważ system
operacyjny był pisany z myślą o całej serii XL, to tabela ta
znajduje się we wszystkich modelach, lecz nie jest
wykorzystywana poza 1200XL.
2.3.5. Procedura inicjowania drukarki
Zainicjowanie drukarki polega jedynie na ustawieniu w
rejestrze PTIMOT wartości $1E. Określa ona tzw. Timeout, czyli
czas oczekiwania komputera na odpowiedź po wysłaniu polecenia
do urządzenia zewnętrznego i jest różna dla różnych urządzeń.
Jeżeli po odliczeniu wskazanej przez Timeout liczby cykli
zegarowych komputer nie otrzyma odpowiedzi z urządzenia, to
wywoływany jest błąd o kodzie 138 (przekroczony czas
oczekiwania). Używanie wartości Timeout przy komunikacji z
urządzeniami peryferyjnymi pozwala na współpracę komputera z
urządzeniami o różnej szybkości pracy i jest kolejnym
przykładem elastyczności systemu.
0100 ;PRinter INITiation
0110 ;
0120 PTIMOT = $0314
0130 ;
0140 *= $FE99
0150 ;
0160 LDA #$1E
0170 STA PTIMOT
0180 RTS
2.3.6. Procedura inicjowania magnetofonu
Ponieważ magnetofon jest jedynym "nieinteligentnym"
urządzeniem zewnętrznym, tzn. nie ma wbudowanych układów do
komunikacji z komputerem, to komputer wysyła polecenia i dane
bez oczekiwania na odpowiedź lub potwierdzenie. Z tego powodu
nie jest określany czas oczekiwania na odpowiedź (Timeout).
Inicjowanie magnetofonu polega więc jedynie na ustawieniu w
rejestrze CBAUD (Cassette BAUD rate) szybkości transmisji na
600 bodów (bitów na sekundę).
0100 ;CASsette INITiation
0110 ;
0120 CBAUD = $02EE
0130 ;
0140 *= $FCDB
0150 ;
0160 LDA #$CC
0170 STA CBAUD
0180 LDA #$05
0190 STA CBAUD+1
0200 RTS
Stosowana w Atari szybkość transmisji z magnetofonu nie
jest oszałamiająca (np. w Commodore 64 stosuje się 3800 bodów).
Dlatego też istnieje wiele programów przyspieszających zapis i
odczyt. Ingerują one między innymi w zawartość rejestru CBAUD.
2.3.7. Inicjowanie bloku kontroli urządzeń
Blok kontroli urządzeń (Device Control Block) jest
wykorzystywany przez procedurę SIO przede wszystkim do
komunikacji ze stacją dysków elastycznych. Przygotowanie
systemu do współpracy ze stacją dysków wymaga określenia czasu
oczekiwania na odpowiedź (Timeout), tak jak dla drukarki.
Dodatkowo ustalana jest na 128 bajtów długość sektora
zapisanego na dyskietce.
0100 ;DiSK INITiation
0110 ;
0120 DSCTLN = $02D5
0130 DSKTIM = $0246
0140 ;
0150 *= $C6A3
0160 ;
0170 LDA #$A0
0180 STA DSKTIM
0190 LDA #$80
0200 STA DSCTLN
0210 LDA #$00
0220 STA DSCTLN+1
0230 RTS
2.3.8. Inicjowanie centralnej procedury I/O
Wykonywane przez procedurę CIOINIT zainicjowanie centralnej
procedury obsługi operacji wejścia/wyjścia polega jedynie na
wpisaniu do wszystkich bloków kontroli (IOCB) dwóch wartości.
Identyfikator urządzenia (ICCHID) otrzymuje wartość $FF, co
oznacza urządzenie nieistniejące. Jako adres procedury Put Byte
(odczytu lub zapisu bajtu - zależnie od sposobu dostępu)
umieszczany jest adres procedury CIONOPN.
0100 ;Central I/O INITiation
0110 ;
0120 ICCHID = $0340
0130 ICPUTB = $0346
0140 ;
0150 *= $E4C1
0160 ;
0170 LDX #$00
0180 LOOP LDA #$FF
0190 STA ICCHID,X
0200 LDA # <CIONOPN-1
0210 STA ICPUTB,X
0220 LDA # >CIONOPN
0230 STA ICPUTB+1,X
0240 TXA
0250 CLC
0260 ADC #$10
0270 TAX
0280 CMP #$80
0290 BCC LOOP
0300 RTS
0310 ;
0320 ;CIO Not OPeN
0330 ;
0340 CIONOPN LDY #$85
0350 RTS
Próba odczytu lub zapisu przez wywołanie procedury CIO
spowoduje teraz umieszczenie w rejestrze Y wartości $85, czyli
wystąpieniu błędu "NOT OPEN" (kanał nie został otwarty).
2.3.9. Inicjowanie szeregowej procedury I/O
Przygotowanie do pracy procedury SIO, która bezpośrednio
obsługuje transmisję poprzez szynę szeregową, wymaga jedynie
wpisania odpowiednich wartości do rejestru kontroli złącza
szeregowego i klawiatury (Serial and Keyboard ConTroL) oraz
jego odpowiednika w pamięci RAM (tzw. rejestr-cień). Poza tym
procedura inicjowania ustawia znacznik zezwolenia na dźwięk
podczas transmisji, a do rejestrów kontroli portów układu PIA
wpisuje wartości, które ustawiają PORTA i PORTB jako rejestry
przesyłania danych.
0100 ;Serial I/O INITiation
0110 ;
0120 IOSNDEN = $41
0130 PACTL = $D302
0140 PBCTL = $D303
0150 SKCTL = $D20F
0160 SKCTLS = $0232
0170 ;
0180 *= $E95C
0190 ;
0200 LDA #$3C
0210 STA PACTL
0220 LDA #$3C
0230 STA PBCTL
0240 LDA #$03
0250 STA SKCTLS
0260 STA IOSNDEN
0270 STA SKCTL
0280 RTS
2.3.10. Inicjowanie nowych urządzeń
System operacyjny Atari był projektowany tak, aby umożliwić
maksymalną elastyczność. Szybki rozwój techniki czynił
oczywistym powstanie w przyszłości urządzeń, których działanie
trudno było przewidzieć podczas tworzenia systemu. Z tego
powodu tabela procedur obsługi urządzeń zewnętrznych została
umieszczona w pamięci RAM i przewidziano możliwość jej
rozszerzania do jedenastu wpisów.
Sposób ten jest stosowany także w innych komputerach,
projektanci Atari poszli jednak jeszcze dalej! Założyli
powstanie w przyszłości urządzeń zewnętrznych korzystających z
szyny równoległej komputera i nazwali je "nowymi urządzeniami"
(new device). Do ich obsługi przewidziano liczne procedury
systemu operacyjnego. Procedury te przez kilka lat stanowiły
powód do zdziwienia, a nawet kpin. Przewidywania twórców Atari
okazały się jednak słuszne: jest już pierwsze urządzenie
korzystające z tych procedur - twardy dysk 20 MB firmy Supra
Corp.
Chociaż na etapie projektowania nie można było przewidzieć
nawet zasady działania tych urządzeń, to jednak trzeba było
ustalić kilka podstawowych warunków. Przede wszystkim w
obszarze portów I/O wydzielono część przestrzeni adresowej dla
rejestrów nowych urządzeń ($D100-$D1FF). Następnie ustalono, że
nowe urządzenie będzie powodowało odłączenie obszaru ROM
zawierającego procedury operacji zmiennoprzecinkowych
($D800-$DFFF). W uzyskanej w ten sposób przestrzeni adresowej
zostanie sprzętowo (przez przełączenie linii magistrali
adresowej) umieszczona część pamięci ROM urządzenia.
Po tej długiej, lecz koniecznej dygresji czas na opis
procedury inicjowania nowych urządzeń.
0100 ;NEW device INITiation
0110 ;
0120 DEVID1 = $D803
0130 DEVID2 = $D80B
0140 DEVINIT = $D819
0150 PDVREG = $D1FF
0160 PDVRS = $0248
0170 ;
0180 *= $C90C
0190 ;
0200 LDA #$01
0210 STA PDVRS
0220 DEV LDA PDVRS
0230 STA PDVREG
0240 LDA DEVID1
0250 CMP #$80
0260 BNE NEXT
0270 LDA DEVID2
0280 CMP #$91
0290 BNE NEXT
0300 JSR DEVINIT
0310 NEXT ASL PDVRS
0320 BNE DEV
0330 LDA #$00
0340 STA PDVREG
0350 RTS
Procedura kolejno aktywizuje nowe urządzenia (może być ich
osiem) i sprawdza dwa bajty identyfikacyjne (DEVID1=$80 i
DEVID2=$91). Jeżeli wynik jest pozytywny, to wywoływana jest
procedura inicjowania urządzenia zapisana w jego pamięci (od
adresu DEVINIT). Uaktywnienie urządzenia polega na ustawieniu
bitu o odpowiadającym mu numerze (od 0 do 7) w rejestrze PDVREG
(Parallel DeVice REGister) znajdującym się w tym urządzeniu.
Rejestr ten posiada w obszarze zmiennych systemowych komputera
swój rejestr-cień PDVRS.
2.3.11. Inicjowanie przerwań niemaskowalnych
Po przygotowaniu do pracy całego systemu wykonywana jest
procedura uruchamiająca przerwania niemaskowalne (NMI - Non
Maskable Interrupt). Umieszcza ona w rejestrze NMIEN (NMI
ENable) wartość $40, co oznacza zezwolenie na przerwania
wywoływane przez impuls synchronizacji pionowej obrazu (zob.
rozdział 3.1.1.). Dodatkowo przepisuje ona wartość wskaźnika
TRIG3, sygnalizującego obecność cartridge'a do rejestru GINTLK.
0100 ;NMI ENaBLe
0110 ;
0120 GINTLK = $03FA
0130 NMIEN = $D40E
0140 TRIG3 = $D013
0150 ;
0160 *= $C00C
0170 ;
0180 LDA #$40
0190 STA NMIEN
0200 LDA TRIG3
0210 STA GINTLK
0220 RTS
2.4. Procedury odczytu wstępnego (boot)
Po zainicjowaniu pracy wszystkich niezbędnych elementów
systemu procedura RESET musi przekazać sterowanie komputera do
programu użytkownika. W tym celu po zimnym starcie próbuje
dokonać odczytu z magnetofonu i stacji dysków, a po starcie
gorącym sprawdza, czy taki odczyt był uprzednio wykonany.
Pozytywny wynik (odczytu lub sprawdzenia) powoduje skok do
adresu wskazanego przez wektor inicjowania odczytanego
programu. W tym miejscu pojawia się największa możliwość
ingerencji w procedurę RESET i wykonania programu wskazanego
przez programistę.
2.4.1. Procedura odczytu z magnetofonu
Jako pierwsza wywoływana jest procedura odczytu z
magnetofonu.
0100 ;CASsette BOOT
0110 ;
0120 BLOCK1 = $C5BB
0130 BOOT? = $09
0140 CASINI = $02
0150 CASSBT = $03EA
0160 CKEY = $03E9
0170 DOSINI = $0C
0180 GAPTYP = $3E
0190 JCASOPIN = $E47D
0200 WARMST = $08
0210 ;
0220 *= $C66E
0230 ;
0240 LDA WARMST
0250 BEQ RD
0260 LDA BOOT?
0270 AND #$02
0280 BEQ EXIT
0290 JMP CASINITC
0300 RD LDA CKEY
0310 BEQ EXIT
0320 LDA #$80
0330 STA GAPTYP
0340 INC CASSBT
0350 JSR JCASOPIN
0360 JSR BLOCK1
0370 LDA #$00
0380 STA CASSBT
0390 STA CKEY
0400 ASL BOOT?
0410 LDA DOSINI
0420 STA CASINI
0430 LDA DOSINI+1
0440 STA CASINI+1
0450 EXIT RTS
0460 CASINITC JMP (CASINI)
Jeśli jest to start gorący (WARMST=$FF), to kontrolowany
jest znacznik BOOT?. Gdy ma on ustawiony bit 1, wykonywany jest
skok do programu, którego adres wskazuje wektor CASINI. W
przeciwnym wypadku następuje wyjście z procedury CASBOOT i
powrót do RESET.
Przy zimnym starcie systemu najpierw sprawdzany jest
znacznik CKEY, określający, czy został naciśnięty klawisz
START. Zerowa wartość tego znacznika oznacza brak odczytu z
magnetofonu i powoduje opuszczenie CASBOOT.
Po stwierdzeniu konieczności odczytu z magnetofonu rejestr
GAPTYP ustawiany jest na $80, co oznacza krótkie przerwy między
rekordami zapisanymi na kasecie oraz zwiększana jest wartość
wskaźnika CASSBT (z 0 na 1). Następnie wywoływana jest
procedura CASOPIN, której zadaniem jest otworzenie kanału IOCB
do odczytu z magnetofonu. Teraz poprzez skok do środka
procedury BOOT (zob. niżej), w miejsce oznaczone etykietą
BLOCK1, wykonywany jest właściwy odczyt z magnetofonu.
Na zakończenie zerowane są wskaźniki CASSBT i CKEY, a BOOT?
jest mnożony przez 2. Ponieważ procedura BOOT umieszcza wektor
startowy programu w rejestrze DOSINI, a po odczycie z
magnetofonu wykorzystywany jest wektor CASINI, to trzeba
jeszcze przepisać jego zawartość (z DOSINI do CASINI).
2.4.2. Procedura odczytu ze stacji dysków
Procedura wstępnego odczytu ze stacji dysków rozpoczyna się
tak samo jak odczyt z magnetofonu. Jedynie zamiast bitu 1 przy
gorącym starcie sprawdzany jest bit 0 wskaźnika BOOT?,
sygnalizujący poprawny odczyt z dyskietki. Ustawienie tego bitu
powoduje skok do adresu zawartego w rejestrze DOSINI.
0100 ;BOOT
0110 ;
0120 BLOAD = $C629
0130 BOOT? = $09
0140 BOOTAD = $0242
0150 CASBUF = $0400
0160 CASSBT = $03EA
0170 DAUX1 = $030A
0180 DAUX2 = $030B
0190 DBUFA = $0304
0200 DCMND = $0302
0210 DFLAG = $0240
0220 DOSINI = $0C
0230 DOSINITC = $C63B
0240 DRDERR = $C63E
0250 DSECCNT = $0241
0260 DUNIT = $0301
0270 GETBLK = $C659
0280 JDSKINT = $E453
0290 RAMLO = $04
0300 WARMST = $08
0310 ;
0320 *= $C58B
0330 ;
0340 LDA WARMST
0350 BEQ RD
0360 LDA BOOT?
0370 AND #$01
0380 BEQ EXIT
0390 JMP DOSINITC
0400 RD LDA #$01
0410 STA DUNIT
0420 LDA #$53
0430 STA DCMND
0440 JSR JDSKINT
0450 BMI EXIT
0460 RP1 LDA #$00
0470 STA DAUX2
0480 LDA #$01
0490 STA DAUX1
0500 LDA # <CASBUF
0510 STA DBUFA
0520 LDA # >CASBUF
0530 STA DBUFA+1
0540 BLOCK1 JSR GETBLK
0550 BPL NER
0560 ERR JSR DRDERR
0570 LDA CASSBT
0580 BEQ RP1
0590 EXIT RTS
0600 NER LDX #$03
0610 LOOP1 LDA CASBUF,X
0620 STA DFLAG,X
0630 DEX
0640 BPL LOOP1
0650 LDA BOOTAD
0660 STA RAMLO
0670 LDA BOOTAD+1
0680 STA RAMLO+1
0690 LDA CASBUF+4
0700 STA DOSINI
0710 LDA CASBUF+5
0720 STA DOSINI+1
0730 NXT LDY #$7F
0740 LOOP2 LDA CASBUF,Y
0750 STA (RAMLO),Y
0760 DEY
0770 BPL LOOP2
0780 CLC
0790 LDA RAMLO
0800 ADC #$80
0810 STA RAMLO
0820 LDA RAMLO+1
0830 ADC #$00
0840 STA RAMLO+1
0850 DEC DSECCNT
0860 BEQ END
0870 INC DAUX1
0880 RP2 JSR GETBLK
0890 BPL NXT
0900 JSR DRDERR
0910 LDA CASSBT
0920 BNE ERR
0930 BEQ RP2
0940 END LDA CASSBT
0950 BEQ BLD
0960 JSR GETBLK
0970 BLD JSR BLOAD
0980 BCS ERR
0990 JSR DOSINITC
1000 INC BOOT?
1010 RTS
W przypadku zimnego startu zawsze podejmowana jest próba
odczytu ze stacji dysków numer 1. W tym celu do rejestru DUNIT
wpisywany jest numer stacji (1), a do DCMND kod rozkazu odczytu
statusu ($53). Potem wywoływana jest procedura DSKINT i po
uzyskaniu negatywnego wyniku (brak odpowiedzi od stacji)
następuje opuszczenie procedury BOOT.
Gdy została stwierdzona gotowość do pracy stacji numer 1
(status dodatni), numer sektora jest ustawiany na 1, a jako
adres bufora do umieszczenia odczytanego bloku wskazywany jest
bufor magnetofonu (CASBUF). W tym miejscu (od etykiety BLOCK1)
następuje wejście z procedury CASBOOT - ta część jest wspólna
dla odczytu z obu urządzeń. Teraz wywoływana jest procedura
GETBLK, która pobiera blok bajtów z urządzenia zewnętrznego.
Jeśli podczas odczytu wystąpił błąd, to wywoływana jest
procedura DRDERR i w przypadku magnetofonu następuje
zakończenie odczytu, a w przypadku stacji dysków próba odczytu
jest ponawiana (aź do skutku). Do rozróżnienia urządzenia, z
którego dokonywany jest odczyt, służy tu znacznik CASSBT
(CASSette BooT). Przy odczycie ze stacji dysków ma on wartość
zero, a przy odczycie z magnetofonu procedura CASBOOT nadaje mu
wartość $01.
Po bezbłędnym odczycie bloku pierwsze sześć bajtów z bufora
jest przenoszone do różnych rejestrów: bajt 1 do DFLAG, bajt 2
do DSECCNT, bajty 3 i 4 do BOOTAD i RAMLO oraz bajty 5 i 6 do
DOSINI. Dzięki temu DSECCNT (Disc SECtor CouNTer) zawiera
liczbę bloków do odczytu, BOOTAD (BOOT ADdress) i RAMLO adres
początkowy umieszczenia odczytanych bloków w pamięci, a DOSINI
adres inicjowania odczytanego programu. Ostatnim krokiem tego
etapu jest przeniesienie zawartości bufora magnetofonu do
miejsca ładowania wskazanego wektorem RAMLO.
Dalszy przebieg odczytu jest podobny. Kolejno, aż do
wyzerowania licznika DSECCNT, bloki danych są odczytywane do
bufora magnetofonu i stąd przenoszone na miejsce wskazane przez
RAMLO. Wektor RAMLO jest zwiększany po odczycie każdego bloku o
128, co zapewnia zapisanie odczytanych bloków w pamięci
bezpośrednio jeden za drugim. Wystąpienie błędu w którymkolwiek
momencie odczytu powoduje wywołanie procedury DRDERR i
przerwanie odczytu z magnetofonu lub ponowny odczyt (od
początku, tj. od pierwszego sektora) ze stacji dysków.
Po zakończeniu odczytu wywoływana jest procedura BLOAD oraz
procedura inicjowania (od adresu umieszczonego w DOSINI). Przed
opuszczeniem procedury BOOT zwiększana jest jeszcze o jeden
zawartość wskaźnika BOOT?.
2.4.3. Pomocnicze procedury odczytu
Procedury wstępnego odczytu CASBOOT i BOOT wykorzystują
kilka procedur pomocniczych. Procedury DSKINT (Disk INTerface),
CIOMAIN (CIO MAIN routine), CASOPIN (CASsette OPen for INput) i
CASRDBL (CASsette ReaD BLock) są standardowymi procedurami
wejścia/wyjścia i są opisane w książce "Mapa pamięci Atari
XL/XE. Procedury wejścia/wyjścia" wydanej przez SOETO. Tu
przedstawione będą tylko procedury GETBLK, DRDERR i BLOAD.
0100 ;GET BlocK
0110 ;
0120 CASSBT = $03EA
0130 DCMND = $0302
0140 DUNIT = $0301
0150 JCASRDBL = $E47A
0160 JDSKINT = $E453
0170 ;
0180 *= $C659
0190 ;
0200 LDA CASSBT
0210 BEQ DSK
0220 JMP JCASRDBL
0230 DSK LDA #$52
0240 STA DCMND
0250 LDA #$01
0260 STA DUNIT
0270 JMP JDSKINT
Procedura GETBLK rozpoznaje według zawartości rejestru
CASSBT rodzaj urządzenia zewnętrznego (stacja dysków czy
magnetofon) i przechodzi do procedury odczytu z magnetofonu
CASRDBL, albo ustawia numer stacji dysków (1) i kod rozkazu
odczytu sektora ($52) oraz przechodzi do procedury operacji
dyskowych DSKINT.
0100 ;Boot LOADer
0110 ;
0120 BOOTAD = $0242
0130 DOSINI = $0C
0140 RAMLO = $04
0150 ;
0160 *= $C629
0170 ;
0180 CLC
0190 LDA BOOTAD
0200 ADC #$06
0210 STA RAMLO
0220 LDA BOOTAD+1
0230 ADC #$00
0240 STA RAMLO+1
0250 JMP (RAMLO)
0260 DOSINITC JMP (DOSINI)
Zadaniem procedury BLOAD jest wykonanie wstępnych czynności
wymaganych przez wczytany program. W tym celu adres ładowania
programu pobrany z rejestru BOOTAD jest zwiększany o 6 (liczba
bajtów nagłówka) i umieszczany w RAMLO. Wektor RAMLO służy
następnie do wykonania skoku do wczytanego programu (do jego
części wstępnej - w przypadku magnetofonu jest to zwykle
zatrzymanie silnika).
0100 ;Disk ReaD ERRor
0110 ;
0120 ICBUFA = $0344
0130 ICBUFL = $0348
0140 ICCMD = $0342
0150 JCIOMAIN = $E456
0160 ;
0170 ;Disk ERRor MeSsaGe
0180 ;
0190 *= $C43D
0200 ;
0210 DERRMSG .BYTE "BOOT ERROR"
0220 .BYTE $9B ;End Of Line
0230 ;
0240 ;Disk ReaD ERRor
0250 ;
0260 *= $C63E
0270 ;
0280 LDX # <DERRMSG
0290 LDY # >DERRMSG
0300 PUTLINE TXA
0310 LDX #$00
0320 STA ICBUFA,X
0330 TYA
0340 STA ICBUFA+1,X
0350 LDA #$09
0360 STA ICCMD,X
0370 LDA #$FF
0380 STA ICBUFL,X
0390 JMP JCIOMAIN
Wystąpienie błędu w dowolnej fazie procedury BOOT powoduje
wywołanie procedury DRDERR. W rejestrze X umieszczany jest
młodszy, a w rejestrze Y starszy bajt adresu tekstu "BOOT
ERROR". Następnie są one przepisywane do ICBUFA jako adres
bufora dla IOCB 0, a do rejestru ICCMD wpisywany jest kod
rozkazu "Put Line" (wyślij linię). Po przejściu do procedury
CIOMAIN powoduje to wyświetlenie na ekranie wskazanego napisu.
Procedurę tą można łatwo wykorzystać do pisania na ekranie
w trybie 0. Należy wpisać do rejestrów X i Y adres tekstu i
wywołać procedurę DRDERR od etykiety PUTLINE ($C642) zamiast od
początku. Maksymalna długość tekstu (razem ze znakiem końca
linii - RETURN) może wynosić 255 bajtów. Tekst jest umieszczany
na ekranie począwszy od aktualnej pozycji kursora.
2.5. Procedura testu komputera
W przypadku wystąpienia błędu podczas inicjowania systemu
operacyjnego wywoływana jest procedura TESTROM.
0100 ;TEST ROM enable
0110 ;
0120 SWITROM = $C8FC
0130 ;
0140 *= $F223
0150 ;
0160 JMP SWITROM
Jedyną jej funkcją jest bezpośredni skok do procedury
SWITROM. Wydaje się to całkiem bezsensowne, lecz w tym miejscu
znajdował się w starych modelach Atari 400/800 początek
procedury tzw. "memo pad". Skok ten służy więc zachowaniu
adresu pomimo zmiany systemu, gdyż adres ten wykorzystywany
jest w niektórych programach.
0100 ;SWITch ROM
0110 ;
0120 COLDST = $0244
0130 JTESTST = $E483
0140 PORTB = $D301
0150 ;
0160 *= $C8FC
0170 ;
0180 LDA #$FF
0190 STA COLDST
0200 LDA PORTB
0210 AND #$7F
0220 STA PORTB
0230 JMP JTESTST
Właściwe przejście do testowania komputera odbywa się w
procedurze SWITROM. Ustawia ona wskaźnik zimnego startu na $FF
(zimny start po RESET) oraz przełącza program testowania
pamięci (SELFTEST) do obszaru $5000-$57FF. Na zakończenie
wykonuje pośredni skok do procedury testującej.
|