Rozdział 1URUCHOMIENIE INTERPRETERAW czasie inicjowania systemu komputerowego przez procedurę RESET (zob. "Mapa pamięci Atari XL/XE. Podstawowe procedury systemu operacyjnego") inicjowany jest także zainstalowany cartridge. Po zakończeniu inicjowania i ewentualnym odczytaniu DOS-u sterowanie komputerem jest przekazywane do cartridge'a, którego rolę pełni w tym przypadku interpreter Basica. Odpowiednie informacje znajdują się w czterech rejestrach umieszczonych na końcu obszaru zajętego przez cartridge.Warto przy okazji wspomnieć, że na końcu interpretera pozostało dziewięć pustych bajtów pamięci (równych $00), które można wykorzystać przy jego modyfikowaniu. Te niewykorzystane bajty znajdują się w obszarze $BFF1-$BFF9.
0100 ;CARTridge
0110 ;
0120 *= $BFFA
0130 ;
0140 CARTRUN .WORD $A000
0150 CARTINS .BYTE $00
0160 CARTOPT .BYTE $05
0170 CARTINI .WORD $BFF0
Bajt $00 w rejestrze CARTINS (CARTridge INSerted) oznacza,
że cartridge jest obecny i należy przekazać mu sterowanie. W
celu zainicjowania cartridge'a wywoływana jest procedura,
której adres zawiera rejestr CARTINI (CARTridge INItialization
address). W przypadku interpretera Basica adres ten wskazuje
tylko na instrukcję RTS, a więc interpreter nie wymaga
inicjowania i następuje powrót do procedury RESET. Kolejnym
sprawdzanym rejestrem jest CARTOPT (CARTridge OPTions). Jeśli
zawiera on wartość różną od zera (jak w tym przypadku) to
wykonywany jest wstępny odczyt z dyskietki. Po całkowitym
zainicjowaniu systemu procedura RESET kończy się skokiem do
adresu wskazanego wektorem CARTRUN (CARTridge RUN address). W
interpreterze Basica znajduje się tu adres procedury zimnego
startu interpretera CDST.Na początku procedury CDST sprawdzane są znaczniki LOADFLG (LOADing FLaG) i WARMST (WARM STart). Gdy pierwszy z nich jest różny od zera, to znaczy, że start systemu odbywa się w trakcie odczytu z urządzenia zewnętrznego i przeprowadzany jest start zimny. W przeciwnym razie start gorący jest wykonywany, jeśli znacznik WARMST jest różny od zera. Przy zimnym starcie najpierw wartość dolnej granicy dostępnej pamięci RAM jest przepisywana z rejestru MEMLO do rejestru LOMEM, a znaczniki LOADFLG i MEOLFLG (Modified End Of Line FLaG) są zerowane. Następnie wartość z MEMLO jest umieszczana w rejestrach określających położenie bloków programu od VNTP do BMEMHI (zob. Wprowadzenie). Z kolei poprzez dwukrotne wywołanie procedury INSEL wszystkie bloki powyżej tablicy nazw zmiennych przesuwane są o jeden bajt, a bloki powyżej tablicy instrukcji jeszcze o trzy bajty. W uzyskane w ten sposób miejsce w tabeli nazw zmiennych wpisywane jest zero (nie ma nazwy żadnej zmiennej), a do tabeli instrukcji ciąg bajtów $00, $80, $03, który oznacza pustą instrukcję w trybie bezpośrednim (dokładnie jest to opisane w rozdziale poświęconym tokenizacji programu). Faza zimnego startu kończy się wpisaniem wartości $0A do rejestru tabulacji PTABW (Position of TABulate Width).
0100 ;Start Basic cartridge
0110 ;
0120 CLALL = $BD45
0130 INSEL = $A87A
0140 LOADFLG = $CA
0150 LOMEM = $80
0160 MEOLFLG = $92
0170 MEMLO = $02E7
0180 PRTPRM = $BD62
0190 PSTMAD = $BD9D
0200 PTABW = $C9
0210 RSTBRG = $A8F1
0220 RSTCHN = $BD5B
0230 STARP = $8C
0240 STMCUR = $8A
0250 VNTD = $84
0260 VNTP = $82
0270 VVTP = $86
0280 WARMST = $08
0290 ;
0300 *= $A000
0310 ;
0320 ;ColD STart
0330 ;
0340 CDST LDA LOADFLG
0350 BNE CONT
0360 LDA WARMST
0370 BNE WMST
0380 CONT LDX #$FF
0390 TXS
0400 CLD
0410 ;
0420 ;eXecute NEW statement
0430 ;
0440 XNEW LDX MEMLO
0450 LDY MEMLO+1
0460 STX LOMEM
0470 STY LOMEM+1
0480 LDA #$00
0490 STA MEOLFLG
0500 STA LOADFLG
0510 INY
0520 TXA
0530 LDX #VNTP
0540 LOOP STA $00,X
0550 INX
0560 STY $00,X
0570 INX
0580 CPX #MEOLFLG
0590 BCC LOOP
0600 LDX #VVTP
0610 LDY #$01
0620 JSR INSEL
0630 LDX #STARP
0640 LDY #$03
0650 JSR INSEL
0660 LDA #$00
0670 TAY
0680 STA (VNTD),Y
0690 STA (STMCUR),Y
0700 INY
0710 LDA #$80
0720 STA (STMCUR),Y
0730 INY
0740 LDA #$03
0750 STA (STMCUR),Y
0760 LDA #$0A
0770 STA PTABW
0780 WMST JSR RSTBRG
0790 ;
0800 ;WaRM STart
0810 ;
0820 WRMST JSR CLALL
0830 WRMST2 JSR RSTCHN
0840 LDA MEOLFLG
0850 BEQ WAITIN
0860 JSR PSTMAD
0870 ;
0880 ;WAIT for INput
0890 ;
0900 WAITIN JSR PRTPRM
Dalszy przebieg procedury CDST jest wspólny zarówno dla
zimnego, jak i gorącego startu. Najpierw wywoływana jest
procedura RSTBRG, która zeruje rejestry DATAD (DATa ADdress),
DATALN (DATA LiNe number), ERRCOD (ERRor CODe), STOPLN (STOP
LiNe number) i RADFLG (RADian FLaG) oraz umieszcza wartość $80
w rejestrze IRQSTAT (IRQ STATus) i w starszym bajcie rejestru
TRAPLN (TRAP LiNe number). Procedura ta kończy się bezpośrednim
skokiem do procedury CLALL. Zaraz po zakończeniu procedura ta
jest wywoływana ponownie. Jest to spowodowane koniecznością
wywoływania procedury CLALL przy wznawianiu pracy interpretera
od etykiety WRMST. Natomiast procedura RSTBRG jest
wykorzystywana także przez inne procedury interpretera i
zakończenie jej skokiem do CLALL oszczędza kilkanaście bajtów
pamięci.Sama procedura CLALL najpierw zeruje rejestry generatorów dźwięku AUDF i AUDC, a więc wyłącza dźwięk. Następnie wywołuje siedem razy procedurę CLCHN umieszczając w rejestrze IODVC (Input/Output DeViCe) wartości od 7 do 1, co powoduje zamknięcie wszystkich kanałów komunikacji z urządzeniami zewnętrznymi poza kanałem 0 używanym przez edytor. Procedura CLCHN jest opisana w rozdziale 6.4. (Obsługa komunikacji).
0100 ;ReSeT Basic ReGisters
0110 ;
0120 CLALL = $BD45
0130 DATAD = $B6
0140 IRQSTAT = $11
0150 RADFLG = $FB
0160 TRAPLN = $BC
0170 ;
0180 *= $B8F1
0190 ;
0200 LDX #$05
0210 LDY #$00
0220 LOOP STY DATAD,X
0230 DEX
0240 BPL LOOP
0250 STY RADFLG
0260 DEY
0270 STY TRAPLN+1
0280 STY IRQSTAT
0290 JMP CLALL
0100 ;CLose ALL channels
0110 ;
0120 AUDF1 = $D200
0130 CLCHN = $BCF7
0140 IODVC = $C1
0150 ;
0160 *= $BD45
0170 ;
0180 LDA #$00
0190 LDX #$07
0200 SND STA AUDF1,X
0210 DEX
0220 BNE SND
0230 LDY #$07
0240 STY IODVC
0250 CHN JSR CLCHN
0260 DEC IODVC
0270 BNE CHN
0280 RTS
Jeżeli znacznik końca wiersza MEOLFLG jest różny od zera,
to teraz jest wywoływana procedura PSTMAD. Jest to możliwe
jedynie w przypadku gorącego startu interpretera. Odczytuje ona
zawartość rejestru CSTAD (Current STatement ADdress) i
umieszcza młodszy bajt w buforze wejściowym, w miejscu
wskazanym przez starszy bajt. Na zakończenie zerowany jest
znacznik MEOLFLG.
0100 ;Put STateMent ADdress
0110 ;
0120 CSTAD = $97
0130 INBUFP = $F3
0140 MEOLFLG = $92
0150 ;
0160 *= $BD9D
0170 ;
0180 LDY CSTAD+1
0190 LDA CSTAD
0200 STA (INBUFP),Y
0210 LDA #$00
0220 STA MEOLFLG
0230 RTS
Procedura startu interpretera kończy się wywołaniem
procedury PRTPRM. Powoduje ona umieszczenie na ekranie napisu
"READY" oraz znaków końca wiersza (RETURN) przed i za napisem.
Dzięki temu napis ten pojawia się zawsze w nowym wierszu
ekranu. Procedura PRTPRM po wywołaniu od etykiety PRTRET służy
do umieszczenia na ekranie tylko znaku RETURN. Do służącego
jako licznik wyświetlanych znaków rejestru X jest wtedy
wpisywana wartość zero zamiast sześć. Wykorzystywana przez
PRTPRM procedura PRPCHN jest opisana także w rozdziale "Obsługa
komunikacji" (6.4).
0100 ;PRinT PRoMpt
0110 ;
0120 CIX = $F2
0130 PRPCHN = $BA99
0140 ;
0150 *= $BD62
0160 ;
0170 PRTPRM LDX #$06
0180 LOOP STX CIX
0190 LDA READYP,X
0200 JSR PRPCHN
0210 LDX CIX
0220 DEX
0230 BPL LOOP
0240 RTS
0250 ;
0260 ;READY Prompt
0270 ;
0280 READYP .BYTE $9B,"YDAER",$9B
0290 ;
0300 ;PRinT RETurn character
0310 ;
0320 PRTRET LDX #$00
0330 BEQ LOOP
Po wykonaniu wszystkich opisanych wyżej czynności następuje
bezpośrednie przejście do procedury kontroli składni programu -
SYNTAX, której opis znajduje się w następnym rozdziale. Należy
jeszcze zwrócić uwagę na kilka etykiet znajdujących się w
procedurze startu. Są one wykorzystywane przez inne procedury
interpretera, jeśli wymagane jest ponowne jego zainicjowanie.Pozostała jeszcze do omówienia wywoływana przez CDST procedura INSEL. Tworzy ona miejsce dla umieszczania wewnątrz obszaru pamięci programu nowych elementów tego programu: wierszy, zmiennych, wartości itd. Przed jej wywołaniem w rejestrze Y musi zostać umieszczona wielkość wstawianego elementu programu, a w rejestrze X adres wektora wskazującego miejsce jego wpisania do programu.
0100 ;INSert program ELement
0110 ;
0120 APPMHI = $0E
0130 BMEMHI = $90
0140 CSTAD = $97
0150 INSMER = $B930
0160 LENPEL = $A4
0170 MEMTOP = $02E5
0180 MEOLFLG = $92
0190 MRANGE = $A2
0200 NEWMHI = $9B
0210 OLDMHI = $99
0220 ;
0230 *= $A87A
0240 ;
0250 LDA #$00
0260 STY LENPEL
0270 STA LENPEL+1
0280 TYA
0290 SEC
0300 ADC BMEMHI
0310 TAY
0320 LDA BMEMHI+1
0330 ADC LENPEL+1
0340 CMP MEMTOP+1
0350 BCC SET
0360 BNE ERR
0370 CPY MEMTOP
0380 BCC SET
0390 BEQ SET
0400 ERR JMP INSMER
0410 SET SEC
0420 LDA BMEMHI
0430 SBC $00,X
0440 STA MRANGE
0450 LDA BMEMHI+1
0460 SBC $01,X
0470 STA MRANGE+1
0480 CLC
0490 ADC $01,X
0500 STA OLDMHI+1
0510 LDA $00,X
0520 STA OLDMHI
0530 STA CSTAD
0540 ADC LENPEL
0550 STA NEWMHI
0560 LDA $01,X
0570 STA CSTAD+1
0580 ADC LENPEL+1
0590 ADC MRANGE+1
0600 STA NEWMHI+1
0610 LOOP LDA $00,X
0620 ADC LENPEL
0630 STA $00,X
0640 LDA $01,X
0650 ADC LENPEL+1
0660 STA $01,X
0670 INX
0680 INX
0690 CPX #MEOLFLG
0700 BCC LOOP
0710 STA APPMHI+1
0720 LDA BMEMHI
0730 STA APPMHI
0740 LDX MRANGE+1
0750 INX
0760 LDY MRANGE
0770 BNE DCR2
0780 NOP
0790 BEQ NXT2
0800 NOP
0810 DCR1 DEY
0820 DEC OLDMHI+1
0830 DEC NEWMHI+1
0840 NXT1 LDA (OLDMHI),Y
0850 STA (NEWMHI),Y
0860 DCR2 DEY
0870 BNE NXT1
0880 LDA (OLDMHI),Y
0890 STA (NEWMHI),Y
0900 NXT2 DEX
0910 BNE DCR1
0920 RTS
Przekazana do procedury wielkość wstawianego elementu jest
najpierw umieszczana w rejestrze LENPEL (LENgth of Program
ELement), a następnie dodawana jest do niej aktualna zawartość
rejestru BMEMHI. Jeśli uzyskany wynik przekracza wartość MEMTOP
(MEMory TOP), to przez skok do procedury INSMER sygnalizowany
jest brak wystarczającego obszaru pamięci (INSufficient Memory
ERror) - zob. rozdział 3, "Obsługa błędów". W przeciwnym razie
wszystkie elementy programu o wyższych adresach są przesuwane w
górę, aby uzyskać miejsce dla nowego elementu.Przed przemieszczeniem obliczana jest wielkość przesuwanego bloku, a uzyskany wynik zapisywany jest w rejestrze MRANGE (Memory RANGE). Aktualny adres końca programu jest przepisywany do rejestrów OLDMHI (OLD Memory HIgh address) oraz CSTAD i, po dodaniu wielkości elementu, umieszczany jest w rejestrze NEWMHI (NEW Memory HIgh address). Teraz wielkość elementu zawarta w LENPEL służy do skorygowania wartości wektorów wskazujących przesuwane bloki programu. Poprawiana jest również zawartość rejestru APPMHI (APPlication Memory HIgh address) wykorzystywanego przez system operacyjny. Ostatecznie zawartość obszaru pamięci o wielkości określonej przez MRANGE jest przemieszczana od adresu wskazanego wektorem OLDMHI do adresu wskazanego przez NEWMHI. Przemieszczenie to jest wykonywane od wyższych do niższych adresów, aby uniknąć zniszczenia przepisywanej informacji. W opróżnionym w ten sposób miejscu dotychczasowa zawartość pozostaje nadal, aż do wpisania nowych informacji (obszar ten nie jest zerowany). Procedura INSEL jest często wykorzystywana przez interpreter, posiada także swój odpowiednik o odwrotnym działaniu - DELEL - opisany w następnym rozdziale. |