Powrót do spisu treści

Rozdział 1

URUCHOMIENIE INTERPRETERA

    W 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.
Zientara Wojciech: Mapa pamięci Atari XL/XE. Procedury interpretera Basica, SOETO, Warszawa, 1988.