Powrót do spisu treści

Rozdział 3

OBSŁUGA URZĄDZEŃ ZEWNĘTRZNYCH

    System operacyjny Atari zawiera procedury obsługi pięciu urządzeń zewnętrznych. Są to: edytor (E: - editor), ekran (S: - screen), klawiatura (K: - keyboard), magnetofon (C: - cassette) i drukarka (P: - printer). Bliższego wyjaśnienia wymaga jedynie edytor. Jest to urządzenie zewnętrzne składające się z ekranu w trybie 0 i klawiatury.

    Procedury obsługujące komunikację poprzez wyżej wymienione urządzenia oraz ich wektory znajdują się w pamięci ROM komputera. Można je więc wykorzystać we własnych programach. Korzystając z podanych opisów można również ułożyć własne procedury obsługi tych urządzeń i wykorzystywać je poprzez zmianę wpisu w HATABS.

    Opis trzech pierwszych urządzeń (E, S i K) jest dość skomplikowany, ponieważ ich procedury wzajemnie się wywołują. Sprawia to wrażenie pewnego bałaganu, lecz jest to bałagan pozorny. Zastosowany system pozwala na efektywną pracę wszystkich urządzeń i jednocześnie oszczędza znaczny obszar pamięci. W związku z tym opis został ułożony w kolejności ułatwiającej zrozumienie, lecz niezupełnie dostosowanej do struktury CIO.

3.1. Procedury obsługi klawiatury

    Klawiatura jest urządzeniem wejścia, to znaczy, że można z niej tylko odczytywać dane. Ponieważ klawiatura jest fizycznie wbudowana do komputera, to część procedur ma znaczenie prawie symboliczne i służy jedynie do zapewnienia poprawnego przebiegu operacji CIO. Odpowiednie wektory w tabeli adresowej KBDVEC wskazują adresy następujących procedur:
         OPEN     - KBOPN
         CLOSE    - KBOPN
         GET      - KBGBYT
         PUT      - EDSP
         STATUS   - KBOPN
         SPECIAL  - EDSP
    System operacyjny nie przewiduje dla klawiatury operacji zapisu i operacji specjalnych. Etykietą EDSP jest oznaczony rozkaz RTS w procedurze KBOPN. Po wywołaniu jednej z tych operacji powoduje to uzyskanie w wyniku błędu $92 (FUNCTION NOT IMPLEMENTED). Zostało to wyjaśnione przy opisie GOHAND.

3.1.1. Odczyt z klawiatury

    Procedura odczytu z klawiatury służy do odczytu znaku w kodzie ATASCII (ATari ASCII). Oprócz pobrania znaku z odpowiedniego rejestru musi więc jeszcze rozpoznać specjalne kombinacje klawiszy, które nie mają swoich odpowiedników w tym kodzie. Schematyczny przebieg procedury jest przedstawiony na rysunku 8 (str. 42).

    Rozpoczyna się ona nie od fizycznego początku (IGNORE), lecz od etykiety KBGBYT. Najpierw zerowany jest znacznik SUPERF (SUPER Flag) i sprawdzany bit 0 w ICAX1Z. Gdy jest on ustawiony, to znaczy, że odczyt wykonywany jest z ekranu. Do rejestru ATACHR (ATASCII CHaRacter) wpisywany jest więc znak RETURN ($9B), co wywołuje potem odczyt z edytora i procedura się kończy. Jeśli znak ma być odczytany z klawiatury, to sprawdzany jest rejestr KBCODES (KeyBoard CODE Shadow register). Wartość $FF w tym rejestrze oznacza, że żaden klawisz nie został naciśnięty. W takim przypadku następuje skok do KBGBYT i opisane wyżej operacje są powtarzane, aż do naciśnięcia klawisza.
            0100 ATACHR = $02FB
            0110 DSTAT = $4C
            0120 FKDEFP = $60
            0130 HOLDCH = $7C
            0140 ICAX1Z = $2A
            0150 INVFLG = $02B6
            0160 IRQSTAT = $11
            0170 KBCODES = $02FC
            0180 KBOPN = $F21E
            0190 KEYCLK = $F983
            0200 KEYDEFP = $79
            0210 NOCLIK = $02DB
            0220 SHFLOK = $02BE
            0230 SUPERF = $03E8
            0240 TSTCNT = $F93C
            0250 ;
            0260     *=  $F2F8
            0270 ;
            0280 IGNORE LDA #$FF
            0290     STA KBCODES
            0300 ;
            0310 ;KeyBoard Get BYTe
            0320 ;
            0330 KBGBYT LDA #$00
            0340     STA SUPERF
            0350 ;
            0360 ;Keyboard GET CHaracter
            0370 ;
            0380 KGETCH LDA ICAX1Z
            0390     LSR A
            0400     BCS RET
            0410     LDA #$80
            0420     LDX IRQSTAT
            0430     BEQ STAT
            0440     LDA KBCODES
            0450     CMP #$FF
            0460     BEQ KBGBYT
            0470     STA HOLDCH
            0480     LDX #$FF
            0490     STX KBCODES
            0500     LDX NOCLIK
            0510     BNE KEY
            0520     JSR KEYCLK
            0540 KEY TAY
            0550     CPY #$C0
            0560     BCS IGNORE
            0570     LDA (KEYDEFP),Y
            0590 SAC STA ATACHR
            0600     TAX
            0610     BMI INV
            0620     JMP CTR
            0630 INV CMP #$80
            0640     BEQ IGNORE
            0650     CMP #$81
            0660     BNE SHF
            0670     LDA INVFLG
            0680     EOR #$80
            0690     STA INVFLG
            0700     BCS IGNORE
            0710 SHF CMP #$82
            0720     BNE CPL
            0730     LDA SHFLOK
            0740     BEQ LOW
            0750     LDA #$00
            0760     STA SHFLOK
            0770     BEQ IGNORE
            0780 CPL CMP #$83
            0790     BNE CTL
            0800 LOW LDA #$40
            0810     STA SHFLOK
            0820     BNE IGNORE
            0830 CTL CMP #$84
            0840     BNE EOF
            0850     LDA #$80
            0860     STA SHFLOK
            0870     JMP IGNORE
            0880 EOF CMP #$85
            0890     BNE KCL
            0900     LDA #$88
            0910 STAT STA DSTAT
            0920     STA IRQSTAT
            0930 RET LDA #$9B
            0940     JMP FIN
            0950 KCL CMP #$89
            0960     BNE FNC
            0970     LDA NOCLIK
            0980     EOR #$FF
            0990     STA NOCLIK
            1000     BNE IGN
            1010     JSR KEYCLK
            1020 IGN JMP IGNORE
            1030 FNC CMP #$BE
            1040     BCS CFK
            1050     CMP #$8A
            1060     BCC IGN
            1070     SBC #$8A
            1080     ASL HOLDCH
            1090     BPL FKY
            1100     ORA #$04
            1110 FKY TAY
            1120     LDA (FKDEFP),Y
            1130     JMP SAC
            1140 CFK CMP #$92
            1150     BCS CTR
            1160     CMP #$8E
            1170     BCC IGN
            1180     SBC #$72
            1190     INC SUPERF
            1200     BNE FIN
            1220 CTR LDA HOLDCH
            1230     CMP #$40
            1240     BCS CTRL
            1250     LDA ATACHR
            1260     CMP #$61
            1270     BCC CTRL
            1280     CMP #$7B
            1290     BCS CTRL
            1300     LDA SHFLOK
            1310     BEQ CTRL
            1320     ORA HOLDCH
            1330     JMP KEY
            1340 CTRL JSR TSTCNT
            1350     BEQ EXIT
            1360     LDA ATACHR
            1370     EOR INVFLG
            1390 FIN STA ATACHR
            1400 EXIT JMP KBOPN

            
                         +------------+
+------->< IGNORE >----->| KBCODE=$FF |
|                        +------------+
|                               |
|                               v
|                        +------------+
|    +-->< KBGBYT >----->| SUPERF=$00 |
|    |                   +------------+
|    |                          |
|    |                          v
|    |                      /-------\
|    |                     / odczyt  \ tak
|    |   < KGETCH >------><  znaku z  >---->---+
|    |                     \ ekranu? /         |
|    |                      \-------/          |
|    |                          | nie          |
|    |                          v              |
|    |                    /----------\         |
|    |                   / naciśnięty \ tak    v
|    |                  <   klawisz    >------>+
|    |                   \  BREAK  ?  /        |
|    |                    \----------/         |
|    |                          | nie          |
|    |                          v              |
|    |                    /----------\         |
|    |               nie / nasiśnięty \        |
|    +-------------<----<     inny     >       |
|                        \  klawisz ? /        |
|                         \----------/         |
|                               | tak          |
|                               v              v
|                        +-------------+ +--------------+
|                        | odczyt kodu | | kod klawisza |
|                        |  klawisza   | |   = RETURN   |
|                        +-------------+ +--------------+
|                               |              |
|                               v              |
|                          /---------\         |
|      +-----------+  tak /    czy    \        |
+------| wykonanie |<----<  specjalny  >       |
       +-----------+      \ klawisz ? /        |
                           \---------/    +----+
                                | nie     |
                                v         v
                            +-----------------+
                            | zapisanie znaku |
                            |    do ATACHR    |
                            +-----------------+
                                     |
                                     v
                                 < KBOPN >

          Rys.8. Odczyt znaku z klawiatury
    Po naciśnięciu klawisza jego kod jest przepisywany do rejestru HOLDCH (CHOLD CHaracter), a rejestr KBCODE otrzymuje wartość $FF, aby umożliwić następny odczyt. Jeśli zawartość rejestru NOCLIK (NO key CLIcK) jest równa zero, to wywoływana jest procedura KEYCLK. Generuje ona dźwięk naciśnięcia klawisza przez zapisywanie 127 razy rejestru CONSOL (jego bit 3 steruje dźwiękiem).
            0100 ;KEY CLicK
            0110 ;
            0120 CONSOL = $D01F
            0130 VCOUNT = $D40B
            0140 ;
            0150     *=  $F983
            0160 ;
            0170     LDX #$7E
            0180     PHA
            0190 NEXT STX CONSOL
            0200     LDA VCOUNT
            0210 WAIT CMP VCOUNT
            0220     BEQ WAIT
            0230     DEX
            0240     DEX
            0250     BPL NEXT
            0260     PLA
            0270     RTS
    Teraz kod naciśniętego klawisza jest zamieniany na kod ATASCII według wartości umieszczonych w tabeli definicji klawiszy (KEYDEF). Ponieważ w tabeli wpisane są tylko 192 kody, to przedtem kody wyższe od $BF są eliminowane przez skok do etykiety IGNORE. Tabela definicji klawiszy znajduje się wprawdzie w pamięci ROM, lecz odwołanie do niej następuje według wektora KEYDEFP (KEY DEFinitions Pointer). Przez utworzenie nowej tabeli i zmianę tego wektora można więc zmienić znaczenie prawie wszystkich klawiszy, co zresztą jest stosowane w wielu programach użytkowych.

    Na przykład, zdefiniowanie nowego zestawu znaków i przedefiniowanie klawiatury umożliwia stworzenie bazy danych posiadającej polskie litery i sortującej dane z ich uwzględnieniem. Oczywiście pojawia się wtedy problem drukowania takiego tekstu, lecz można go rozwiązać przez wpisanie nowej procedury obsługi drukarki, która normalnym znakom przywróci standardowy kod ASCII, a polskie litery wydrukuje w trybie graficznym lub jako złożenie dwóch znaków standardowych (np. "ł" = "l" + "/"). System operacyjny Atari daje tu programiście szerokie pole do popisu.

    Po dokładnym przejrzeniu tabeli KEYDEF łatwo zauważyć, że kilka klawiszy naciśniętych wraz z CONTROL nie posiada żadnego znaczenia. Poprzez ich przedefiniowanie można więc uzyskać dodatkowe funkcje. Umieszczone w tabeli kody klawiszy F1-F4 dotyczą jedynie modelu 1200XL, który posiada te klawisze. Ich definicje można zmienić tylko w zakresie występującym w tabeli, ponieważ w kombinacji z CONTROL mają one specjalne funkcje, które są wykonywane już podczas przerwania IRQ wywołanego naciśnięciem klawisza.
            0100 ;KEYboard DEFinitions table
            0110 ;
            0120 BL  =   $FD     ;bell
            0130 BS  =   $7E     ;backspace
            0140 CD  =   $1D     ;cursor down
            0150 CK  =   $84     ;CTRL key lock
            0160 CL  =   $1E     ;cursol left
            0170 CP  =   $82     ;caps
            0180 CR  =   $1F     ;cursor right
            0190 CS  =   $7D     ;clear screen
            0200 CT  =   $9E     ;clear TAB
            0210 CU  =   $1C     ;cursor up
            0220 DC  =   $FE     ;delete char
            0230 DL  =   $9C     ;delete line
            0240 EF  =   $85     ;end of file
            0250 ES  =   $1B     ;escape
            0260 F1  =   $8A     ;F1
            0270 F2  =   $8B     ;F2
            0280 F3  =   $8C     ;F3
            0290 F4  =   $8D     ;F4
            0300 IC  =   $FF     ;insert char
            0310 IL  =   $9D     ;insert line
            0320 IN  =   $81     ;inverse
            0330 KC  =   $89     ;key click
            0340 NU  =   $80     ;not used
            0350 RT  =   $9B     ;return
            0360 ST  =   $9F     ;set TAB
            0370 TB  =   $7F     ;tabulate
            0380 ;
            0390     *=  $FB51
            0400 ;
            0410     .BYTE 'l,'j,';,F1
            0420     .BYTE F2,'k,'+,'*
            0430     .BYTE 'o,NU,'p,'u
            0440     .BYTE RT,'i,'-,'=
            0450     .BYTE 'v,NU,'c,F3
            0460     .BYTE F4,'b,'x,'z
            0470     .BYTE '4,NU,'3,'6
            0480     .BYTE ES,'5,'2,'1
            0490     .BYTE ',,' ,'.,'n
            0500     .BYTE NU,'m,'/,IN
            0510     .BYTE 'r,NU,'e,'y
            0520     .BYTE TB,'t,'w,'q
            0530     .BYTE '9,NU,'0,'7
            0540     .BYTE BS,'8,'<,'>
            0550     .BYTE 't,'h,'d,NU
            0560     .BYTE CP,'g,'s,'a
            0570 ;with SHIFT
            0580     .BYTE 'L,'J,':,F1
            0590     .BYTE F2,'K,'\,'^
            0600     .BYTE 'O,NU,'P,'U
            0610     .BYTE RT,'I,'_,'|
            0620     .BYTE 'V,NU,'C,F3
            0630     .BYTE F4,'B,'X,'Z
            0640     .BYTE '$,NU,'#,'&
            0650     .BYTE ES,'%,'",'!
            0660     .BYTE '[,' ,'],'N
            0670     .BYTE NU,'M,'?,IN
            0680     .BYTE 'R,NU,'E,'Y
            0690     .BYTE ST,'T,'W,'Q
            0700     .BYTE '(,NU,'),''
            0710     .BYTE DL,'@,CS,IL
            0720     .BYTE 'T,'H,'D,NU
            0730     .BYTE CP+1,'G,'S,'A
            0740 ;with CONTROL
            0750     .BYTE $0C,$0A,$7B,NU
            0760     .BYTE NU,$0B,CL,CR
            0770     .BYTE $0F,NU,$10,$15
            0780     .BYTE RT,$09,CU,CD
            0790     .BYTE $16,NU,$03,KC
            0800     .BYTE NU,$02,$18,$1A
            0810     .BYTE NU,NU,EF,NU
            0820     .BYTE ES,NU,BL,NU
            0830     .BYTE $00,' ,$60,$0E
            0840     .BYTE NU,$0D,NU,IN
            0850     .BYTE $12,NU,$05,$19
            0860     .BYTE CT,$14,$17,$11
            0870     .BYTE NU,NU,NU,NU
            0880     .BYTE DC,NU,CS,IC
            0890     .BYTE $06,$08,$04,NU
            0900     .BYTE CK,$07,$13,$01
    Kod znaku odczytany z tabeli KEYDEF jest umieszczany w rejestrze ATACHR. Wartość kodu większa lub równa $80 oznacza specjalny klawisz (lub kombinację klawiszy). W takim przypadku procedura rozpoznaje jego znaczenie, ewentualnie wykonuje konieczną operację i ponownie oczekuje na naciśnięcie klawisza.

    Kod $80 oznacza zabronioną kombinację klawiszy i jest po prostu ignorowany, a procedura przechodzi do początkowej etykiety IGNORE.

    Kod $81 oznacza klawisz "inverse" (zwany także w starszych publikacjach Atari Logo Key). Powoduje on wykonanie operacji EOR #$FF na zawartości rejestru INVFLG (INVerse FLaG) przełączając tryb wyprowadzania znaków z normalnych na negatywy lub odwrotnie.

    Kod $82 oznacza klawisz CAPS i powoduje przełączenie klawiatury z małych liter na duże lub odwrotnie. W pierwszym przypadku w rejestrze SHFLOK jest umieszczana wartość $40, a w drugim - $00.

    Kod $83 oznacza kombinację SHIFT-CAPS i powoduje ustawienie klawiatury na pisanie dużymi literami przez wpisanie wartości $40 do rejestru SHFLOK.

    Kod $84 oznacza kombinację CONTROL-CAPS i powoduje, przez wpisanie wartości $80 do rejestru SHFLOK, uzyskiwanie znaków pseudograficznych bez naciskania klawisza CONTROL. Tryb ten jest kasowany zarówno przez klawisz CAPS, jak i przez kombinację SHIFT-CAPS.

    Kod $85 oznacza znak EOF (End Of File), który jest uzyskiwany przez naciśnięcie CONTROL-3. W tym przypadku kod błędu EOF ($88) jest wpisywany do rejestru DSTAT (Display STATus) oraz do IRQSTAT (Interrupt ReQuest STATus), a w ATACHR umieszczany jest kod $9B (RETURN). Teraz, zamiast oczekiwania na następny znak, procedura jest przerywana skokiem do KBOPN.

    Kod $89 oznacza naciśnięcie klawiszy CONTROL-F3 i powoduje włączenie lub wyłączenie dźwięku klawiatury. W tym celu na zawartości rejestru NOCLIK jest wykonywana operacja EOR #$FF. Jeśli w jej wyniku NOCLIK ma wartość zero, to poprzednio ominięta procedura KEYCLK jest teraz wywoływana.

    Kody od $8A do $8D oznaczają klawisze funkcyjne F1-F4 (1200XL), zarówno naciśnięte oddzielnie, jak i razem z SHIFT. W celu ich odróżnienia właściwy kod jest odczytywany z tabeli FKDEF z uwzględnieniem kodu klawiatury (z rejestru HOLDCH). Po odczycie kodu następuje powrót do etapu rozpoznawania znaku.
            0100 ;Function Key DEFinitions table
            0110 ;
            0120 CB  =   $8F     ;cursor bottom
            0130 CD  =   $1D     ;cursor down
            0140 CH  =   $8E     ;cursor home
            0150 CL  =   $1E     ;cursor left
            0160 CR  =   $1F     ;cursor right
            0170 CU  =   $1C     ;cursor up
            0180 LM  =   $90     ;cursor to left margin
            0190 RM  =   $91     ;cursor to right margin
            0200 ;
            0210     *=  $FC11
            0220 ;
            0230     .BYTE CU,CD,CL,CR
            0240     .BYTE CH,CB,LM,LR
    Tabela FKDEF jest dostępna przez wektor FKDEFP, podobnie jak KEYDEF. Zmiana tego wektora stosowana jest jednak bardzo sporadycznie, ze względu na brak klawiszy funkcyjnych we wszyskich modelach XL/XE poza 1200XL.

    Kody z zakresu od $8E do $91 oznaczają kombinację klawisza SHIFT z jednym z klawiszy funkcyjnych (F1-F4). Rozpoznanie takiego kodu powoduje zmniejszenie go o $72, zwiększenie znacznika SUPERF i po zapisaniu kodu w rejestrze ATACHR skok do procedury KBOPN.
            0100 ;TeST CoNTrols
            0110 ;
            0120 ATACHR = $02FB
            0130 CNTRLS = $FB0D
            0140 ;
            0150     *=  $F93C
            0160 ;
            0170     LDX #$2D
            0180 NEXT LDA CNTRLS,X
            0190     CMP ATACHR
            0200     BEQ EXIT
            0210     DEX
            0220     DEX
            0230     DEX
            0240     BPL NEXT
            0250 EXIT RTS

            0100 ;CoNTRoLS table
            0110 ;
            0120 BELL =  $F556
            0130 CLRSCR = $F420
            0140 CRSBS = $F450
            0150 CRSCTB = $F49A
            0160 CRSDWN = $F3F3
            0170 CRSLFT = $F400
            0180 CRSRGT = $F411
            0190 CRSSTB = $F495
            0200 CRSTAB = $F47A
            0210 CRSUP = $F3E6
            0220 DELCHR = $F4D5
            0230 DELLIN = $F520
            0240 ESCAPE = $F3E0
            0250 INSCHR = $F49F
            0260 INSLIN = $F50C
            0270 RTWSCR = $F661
            0280 ;
            0290     *=  $FB0D
            0300 ;
            0310     .BYTE $1B
            0320     .WORD ESCAPE
            0330     .BYTE $1C
            0340     .WORD CRSUP
            0350     .BYTE $1D
            0360     .WORD CRSDWN
            0370     .BYTE $1E
            0380     .WORD CRSLFT
            0390     .BYTE $1F
            0400     .WORD CRSRGT
            0410     .BYTE $7D
            0420     .WORD CLRSCR
            0430     .BYTE $7E
            0440     .WORD CRSBS
            0450     .BYTE $7F
            0460     .WORD CRSTAB
            0470     .BYTE $9B
            0480     .WORD RTWSCR
            0490     .BYTE $9C
            0500     .WORD DELLIN
            0510     .BYTE $9D
            0520     .WORD INSLIN
            0530     .BYTE $9E
            0540     .WORD CRSCTB
            0550     .BYTE $9F
            0560     .WORD CRSSTB
            0570     .BYTE $FD
            0580     .WORD BELL
            0590     .BYTE $FE
            0600     .WORD DELCHR
            0610     .BYTE $FF
            0620     .WORD INSCHR
    Jeżeli dotąd nie został rozpoznany żaden ze znaków specjalnych, to znaczy, że został naciśnięty normalny klawisz (lub kombinacja). Teraz następuje ostatnia seria sprawdzeń. Jeśli kod klawisza jest większy lub równy $40 (naciśnięty dowolny klawisz razem z CONTROL lub SHIFT) albo kod ATASCII jest mniejszy od $61 lub większy od $7A (znak nie jest małą literą z zakresu od "a" do "z") albo znacznik SHFLOK ma wartość zero (tryb pisania małymi literami), to wywoływana jest procedura TSTCNT, która rozpoczyna końcową fazę KBGBYT. W przeciwnym razie po ustawieniu w rejestrze HOLDCH bitów, które są ustawione w SHFLOK, procedura powraca do odczytu z tabeli KEYDEF (do etykiety KEY).

    Procedura TSTCNT przeszukuje tabelę znaków kontrolnych edytora porównując zawarte w niej wpisy z zawartością rejestru ATACHR. Ponieważ poszukiwanie znaku odbywa się od końca, to gdy nie zostanie znaleziony, bit Zero jest skasowany. Znalezienie znaku powoduje ustawienie bitu Zero przez rozkaz CMP.

    Jeśli po zakończeniu TSTCNT bit zero jest ustawiony, to procedura odczytu kończy się bezpośrednio skokiem do KBOPN. W przeciwnym razie, przed opuszczeniem procedury KBGBYT, najstarszy bit znaku w rejestrze ATACHR jest ustawiany według zawartości znacznika INVFLG.

3.1.2. Pozostałe procedury klawiatury

    Wektory operacji OPEN, CLOSE i STATUS dla klawiatury wskazują na procedurę KBOPN. Nie jest ona samodzielnym elementem systemu, lecz stanowi część procedury RETURM. W tej części do rejestru Y pobierany jest z DSTAT status edytora i wpisywana jest tam wartość 1 (SUCCESS), a do akumulatora przenoszona jest zawartość rejestru ATACHR. Dokładny opis procedury RETURM znajduje się w rozdziale 3.2.1. (Procedura otwarcia ekranu - str. 58).

    UWAGA! System operacyjny zawiera dwie procedury o bardzo zbliżonych nazwach: RETUNM i RETURN. Nie należy ich ze sobą mylić.

3.2. Procedury obsługi ekranu

    Ekran jest w zasadzie urządzeniem wyjścia, lecz możliwy jest również odczyt z niego. Ponieważ ekran w trybie 0 jest częścią edytora, to procedury obsługujące te urządzenia są ze sobą mocno powiązane. W tym rozdziale opisane zostały wszystkie procedury dotyczące ekranu, a ich elementy dotyczące edytora zostały wyjaśnione w następnym rozdziale (3.3.).

    Tabela adresowa ekranu SCRVEC zawiera następujące wektory:
         OPEN     - SCOPN
         CLOSE    - SCRFIN
         GET      - GETCH
         PUT      - OUTCH
         STATUS   - KBOPN
         SPECIAL  - DRAW
    W komputerach serii XL/XE tworzeniem obrazu zajmuje sie drugi, dodatkowy mikroprocesor (tzw. ANTIC - zob. rozdział 7). Posiada on własną listę rozkazów i własny program. ANTIC umożliwia uzyskanie 14 trybów graficznych, z których jeden (tryb 3 ANTIC-a) jest niedostępny dla systemu operacyjnego. Dodatkowe trzy tryby tworzy specjalny układ graficzny GTIA. Razem mamy więc 16 trybów (a z kombinacjami 64). Tryby te są inaczej numerowane przez ANTIC, a inaczej przez OS. W tym i następnym rozdziale używana jest numeracja trybów stosowana przez system operacyjny (identyczna jak w Atari Basic), a ewentualne odstępstwa od tej zasady są odpowiednio zaznaczone.

3.2.1. Procedura otwarcia ekranu

    Procedura otwarcia jest wspólna dla ekranu i edytora. Różnica występuje jedynie na początku, gdyż ekran może być otwarty w dowolnym trybie graficznym. Przy otwieraniu ekranu w trybie 0 przebieg ich jest identyczny.

    Znaczna długość procedury wynika z dwóch powodów. Seria XL/XE obejmuje komputery o różnej wielkości pamięci RAM, a od tego zależy położenie pamięci obrazu, ponadto zajmowany przez nią obszar zależy od wybranego trybu. Konieczne jest więc obliczenie wielkości i adresu pamięci obrazu. Zastosowanie do tworzenia obrazu drugiego procesora wymaga ułożenia dla niego programu. Ze względu na dużą liczbę trybów programy dla nich zajęłyby kilka kilobajtów pamięci, nie mogą więc znajdować się w ROM-ie. Program ANTIC-a jest każdorazowo tworzony od nowa podczas procedury otwarcia i zapisywany w pamięci RAM bezpośrednio przed obszarem pamięci obrazu. Czynność ta zajmuje dużą część procedury.

    Przed wywołaniem procedury CIO w celu otwarcia ekranu należy w rejestrach ICAX1 i ICAX2 umieścić parametry określające sposób dostępu, tryb graficzny i inne elementy obrazu. W rejestrze ICAX1 znaczenie mają tylko cztery bity (pozostałe są niewykorzystane):
       bit 2 - odczyt
       bit 3 - zapis
       bit 4 - brak okna tekstowego
       bit 5 - zawartość pamięci obrazu bez zmian
    Wymienione opcje są aktywne, gdy odpowiadające im bity są ustawione.
        < EDOPN >             < SCOPN >
              |                     |
              v                     v
     +------------------+   tak /--------\
     |    kasowanie     |<-----< tryb 0 ? >
     | trybów +16 i +32 |       \--------/
     +------------------+           | nie
              |                     |
              +--------->+<---------+
                         |
                         v
                    /---------\ tak
                   < tryb > 15 >---->------------+
                    \---------/                  |
                         | nie                   |
                         v                       |
            +-------------------------+          |
            | ustawienie rejestrów OS |          |
            +-------------------------+          |
                         |                       |
                         v                       |
        +----------------------------------+     |
        | ustalenie adresu okna tekstowego |     |
        +----------------------------------+     |
                         |                       |
                         v                       |
      +-------------------------------------+    |
      | obliczenie wielkości pamięci obrazu |    |
      +-------------------------------------+    |
                         |                       |
                         v                       |
     +---------------------------------------+   |
     | obliczenie wielkości programu ANTIC-a |   |
     +---------------------------------------+   |
                         |                       |
                         v                       |
          +----------------------------+         |
          | zapisanie programu ANTIC-a |         |
          +----------------------------+         |
                         |                       |
                         v                       |
             +----------------------+            |
             | uaktualnienie MEMTOP |            |
             +----------------------+            |
                         |                       |
                         v                       |
                      /-----\ tak                |
                     < błąd? >------------>+<----+
                      \-----/              |
                         | nie             v
                         |            ++-------++
                         |            || EDOPN ||
                          \          ++-------++
                           \               |
                            \              v
                             |          < RTS >
                             |
                             v
                tak /-----------------\
               +---< kasowanie obrazu? >
               |    \-----------------/
               v             | nie
         ++--------++        |
         || CLRSCR ||        |
         ++--------++        |
               |             v
               +------------>+
                             |
                             v
                     +----------------+
                     | ustawienie DMA |
                     +----------------+
                             |
                             v
                         < RETURM >

              Rys.9. Otwarcie ekranu i edytora

              
0100 ADRESS = $64             0390 MEMTOP = $02E5
0110 BOTSCR = $02BF           0400 MLTTMP = $66
0120 CHACT = $02F3            0410 NMIEN = $D40E
0130 CHARSET1 = $E000         0420 RAMTOP = $6A
0140 CHARSET2 = $CC00         0430 RETURM = $F20B
0150 CHBAS = $02F4            0440 SAVADR = $68
0160 CHSPTR = $026B           0450 SAVMSC = $58
0170 CLRSCR = $F420           0460 SGDEC = $F578
0180 COLBAKS = $02C8          0470 SSDLE = $F5A0
0190 COLPF0S = $02C4          0480 STDDSP = $F570
0200 COLTAB = $FB08           0490 STDFS = $F569
0210 CRSINH = $02F0           0500 SWPFLG = $7B
0220 DBDEC = $F565            0510 TABMAP = $02A3
0230 DCUSAC = $F57A           0520 TAGRM = $EE4D
0240 DERRF = $03EC            0530 TDLEC = $EE2D
0250 DINDEX = $57             0540 TDLVL = $EE5D
0260 DLIV =  $0200            0550 TINDEX = $0293
0270 DLPTRS = $0230           0560 TSMAL = $EE1D
0280 DMACTLS = $022F          0570 TXTCOL = $0291
0290 DSTAT = $4C              0580 TXTMSC = $0294
0300 FINE =  $026E            0590 TXTROW = $0290
0310 FSDL =  $FCC4            0600 VCOUNT = $D40B
0320 GTICTLS = $026F          0610 ;
0330 HOLD1 = $51              0620     *=  $EF8E
0340 ICAX1Z = $2A             0630 ;
0350 ICAX2Z = $2B             0640 ;SCreen OPeN
0360 IRQENS = $10             0650 ;
0370 IRQST = $D20E            0660 SCOPN LDA ICAX2Z
0380 LMARGN = $52             0670     AND #$0F

0680     BNE SMD              1240     LDX DINDEX
0690 ;                        1250     LDA TAGRM,X
0700 ;EDitor OPeN             1260     STA HOLD1
0710 ;                        1270     LDA RAMTOP
0720 EDOPN LDA ICAX1Z         1280     STA ADRESS+1
0730     AND #$0F             1290     LDY TSMAL,X
0740     STA ICAX1Z           1300 LOOP3 LDA #$28
0750     LDA #$00             1310     JSR DCUSAC
0760 SMD STA DINDEX           1320     DEY
0770     CMP #$10             1330     BNE LOOP3
0780     BCC OPN              1340     LDA GTICTLS
0790     LDA #$91             1350     AND #$3F
0800     JMP DERR             1360     STA MLTTMP+1
0810 OPN LDA # >CHARSET1      1370     TAY
0820     STA CHBAS            1380     CPX #$08
0830     LDA # >CHARSET2      1390     BCC SMS
0840     STA CHSPTR           1400     CPX #$0F
0850     LDA #$02             1410     BEQ LSM
0860     STA CHACT            1420     CPX #$0C
0870     STA DMACTLS          1430     BCS SMS
0880     LDA #$01             1440     TXA
0890     STA DSTAT            1450     ROR A
0900     LDA #$C0             1460     ROR A
0910     ORA IRQENS           1470     ROR A
0920     STA IRQENS           1480     AND #$C0
0930     STA IRQST            1490     ORA MLTTMP+1
0940     LDA #$40             1500     TAY
0950     STA NMIEN            1510 LSM LDA #$10
0960     BIT FINE             1520     JSR DCUSAC
0970     BPL NFS              1530     CPX #$0B
0980     LDA # <FSDL          1540     BNE SMS
0990     STA DLIV             1550     LDA #$06
1000     LDA # >FSDL          1560     STA COLBAKS
1010     STA DLIV+1           1570 SMS STY GTICTLS
1020     LDA #$C0             1580     LDA ADRESS
1030 NFS STA NMIEN            1590     STA SAVMSC
1040     LDA #$00             1600     LDA ADRESS+1
1050     STA TINDEX           1610     STA SAVMSC+1
1060     STA ADRESS           1620 WAIT LDA VCOUNT
1070     STA SWPFLG           1630     CMP #$7A
1080     STA CRSINH           1640     BNE WAIT
1090     LDY #$0E             1650     JSR SGDEC
1100     LDA #$01             1660     LDA TDLVL,X
1110 LOOP1 STA TABMAP,Y       1670     BEQ SKIP
1120     DEY                  1680     LDA #$FF
1130     BPL LOOP1            1690     STA ADRESS
1140     LDX #$04             1700     DEC ADRESS+1
1150 LOOP2 LDA COLTAB,X       1710 SKIP JSR DBDEC
1160     STA COLPF0S,X        1720     LDA ADRESS
1170     DEX                  1730     STA SAVADR
1180     BPL LOOP2            1740     LDA ADRESS+1
1190     LDY RAMTOP           1750     STA SAVADR+1
1200     DEY                  1760     LDA #$41
1210     STA TXTMSC+1         1770     JSR STDDSP
1220     LDA #$60             1780     STX MLTTMP
1230     STA TXTMSC           1790     LDA #$18

1800     STA BOTSCR           2360     SBC #$10
1810     LDA DINDEX           2370     JSR STDDSP
1820     CMP #$0C             2380     LDA #$00
1830     BCS DL               2390     JSR STDDSP
1840     CMP #$09             2400     LDA HOLD1
1850     BCS SDL              2410     ORA #$40
1860 DL  LDA ICAX1Z           2420     JSR STDDSP
1870     AND #$10             2430 LOOP4 LDA HOLD1
1880     BEQ SDL              2440     JSR STDDSP
1890     LDA #$04             2450     DEX
1900     STA BOTSCR           2460     BNE LOOP4
1910     LDX #$02             2470 CDL LDA SAVMSC+1
1920     LDA FINE             2480     JSR STDDSP
1930     BEQ EDL              2490     LDA SAVMSC
1940     JSR SSDLE            2500     JSR STDDSP
1950 EDL LDA #$02             2510     LDA HOLD1
1960     JSR STDFS            2520     ORA #$40
1970     DEX                  2530     JSR STDDSP
1980     BPL EDL              2540     LDA #$70
1990     LDY RAMTOP           2550     JSR STDDSP
2000     DEY                  2560     LDA #$70
2010     TYA                  2570     JSR STDDSP
2020     JSR STDDSP           2580     LDA ADRESS
2030     LDA #$60             2590     STA DLPTRS
2040     JSR STDDSP           2600     LDA ADRESS+1
2050     LDA #$42             2610     STA DLPTRS+1
2060     JSR STDFS            2620     LDA #$70
2070     CLC                  2630     JSR STDDSP
2080     LDA #$10             2640     LDA ADRESS
2090     ADC MLTTMP           2650     STA MEMTOP
2100     TAY                  2660     LDA ADRESS+1
2110     LDX TDLEC,Y          2670     STA MEMTOP+1
2120     BNE ACMD             2680     LDY #$01
2130 SDL LDY MLTTMP           2690     LDA DLPTRS
2140     LDX TDLEC,Y          2700     STA (SAVADR),Y
2150     LDA DINDEX           2710     INY
2160     BNE ACMD             2720     LDA DLPTRS+1
2170     LDA FINE             2730     STA (SAVADR),Y
2180     BEQ ACMD             2740     LDA DSTAT
2190     JSR SSDLE            2750     BPL NERR
2200     LDA #$22             2760 DERR STA DERRF
2210     STA HOLD1            2770     JSR EDOPN
2220 ACMD LDA HOLD1           2780     LDA DERRF
2230     JSR STDDSP           2790     LDY #$00
2240     DEX                  2800     STY DERRF
2250     BNE ACMD             2810     TAY
2260     LDA DINDEX           2820     RTS
2270     CMP #$08             2830 NERR LDA ICAX1Z
2280     BCC CDL              2840     AND #$20
2290     CMP #$0F             2850     BNE END
2300     BEQ DL2              2860     JSR CLRSCR
2310     CMP #$0C             2870     STA TXTROW
2320     BCS CDL              2880     LDA LMARGN
2330 DL2 LDX #$5D             2890     STA TXTCOL
2340     LDA RAMTOP           2900 END LDA #$22
2350     SEC                  2910     ORA DMACTLS

2920     STA DMACTLS          2930     JMP RETURM
    Do rejestru ICAX2 należy natomiast wpisać numer trybu graficznego, w którym ma zostać otwarty ekran. Przy otwieraniu edytora wartość ta zostanie zignorowana. Ponieważ informacja o oknie tekstowym i kasowaniu zawartości ekranu są już zawarte w rejestrze ICAX1, to wpisana tu wartość określa tylko tryb bez wyżej wymienionych wariantów.

    Procedura otwarcia ekranu najpierw sprawdza wybrany tryb graficzny i zapisuje go w rejestrze DINDEX (Display INDEX). W trybie zero kasowane są bity 4 i 5 rejestru ICAX1, gdyż w tym trybie nie ma okna tekstowego, a obraz musi być wyczyszczony. Jeśli numer trybu jest większy od $0F, to po umieszczeniu w rejestrze Y kodu błędu $91 (BAD SCREEN MODE - zły tryb graficzny) następuje skok do końcowej części procedury (DERR).

    Drugim etapem jest ustalenie wartości zmiennych systemowych w rejestrach RAM. Starsze bajty adresów zestawów znaków są umieszczane w wektorach CHBAS i CHSPTR. Rejestry sterujące wyglądem znaków (CHACT - CHAracter ConTrol) i dostępem do pamięci (DMACTLS - DMA ConTroL Shadow register) otrzymują wartość 2, a status ekranu (DSTAT - Display STATus) wartość 1. Następnie ustawiane są rejestry zezwolenia przerwań IRQEN i NMIEN oraz sprawdzany jest znacznik delikatnego przesuwu obrazu FINE. Zawartość $FF oznacza włączenie delikatnego przesuwu i powoduje ustawienie wektora DLIV (Display List Interrupt Vector) na adres procedury przerwania FSDL (zob. "Mapa pamięci Atari. Podstawowe procedury systemu", str. 50).

    Teraz zerowane są rejestry TINDEX (Text window INDEX), SWPFLG (SWap FLaG) i CRSINH (CuRSor INHibition) oraz rejestr pomocniczy ADRESS. Mapa pozycji tabulacji (TABMAP) jest wypełniana wartościami $01, a rejestry koloru otrzymują wartości z tabeli COLTAB.
            0100 ;COLor TABle
            0110 ;
            0120     *=  $FB08
            0130 ;
            0140     .BYTE $28,$CA,$94,$46,$00
    Na podstawie wartości RAMTOP ustalany jest adres obszaru pamięci dla okna tekstowego (TXTMSC - TeXT Memory SCreen). Ma on zawsze takie samo położenie: starszy bajt mniejszy o jeden od RAMTOP, a młodszy równy $60.

    Teraz rozpoczyna się obliczanie wielkości pamięci obrazu w zależności od wybranego trybu. Najpierw numer trybu ANTIC-a jest odczytywany z tabeli TAGRM i umieszczany w pomocniczym rejestrze HOLD1.
0100 ;Table: ANTIC GRaphics Modes 0110 ; 0120 *= $EE4D 0130 ; 0140 .BYTE $02,$06,$07,$08 0150 .BYTE $09,$0A,$0B,$0D 0160 .BYTE $0F,$0F,$0F,$0F 0170 .BYTE $04,$05,$0C,$0E     Następnie wartość RAMTOP jest przepisywana do starszego bajtu pomocniczego rejestru ADRESS, a z tabeli TSMAL odczytywana jest wielkość przemieszczenia pamięci obrazu.
            0100 ;Table: Screen Memory ALlocation
            0110 ;
            0120     *=  $EE1D
            0130 ;
            0140     .BYTE $18,$10,$0A,$0A
            0150     .BYTE $10,$1C,$34,$64
            0160     .BYTE $C4,$C4,$C4,$C4
            0170     .BYTE $1C,$10,$64,$C4
    Służy ona jako licznik pętli obliczającej rzeczywisty adres pamięci obrazu. Obliczenie to jest dokonywane przez procedurę DCUSAC, która stanowi część większej procedury obliczeniowej. Zostanie ona w całości opisana teraz, ponieważ jest szeroko wykorzystywana w procedurze SCOPN. Posiada ona pięć punktów początkowych (DBDEC, STDFSC, STDDSP, SGDEC i DCUSAC), co umożliwia uzyskanie wielu różnych funkcji.
            0100 ADRESS = $64
            0110 APPMHI = $0E
            0120 DSTAT = $4C
            0130 FINE =  $026E
            0140 SUBTMP = $029E
            0150 ;
            0160     *=  $F565
            0170 ;
            0180 ;DouBle DECreasing
            0190 ;
            0200     LDA #$02
            0210     BNE DCUSAC
            0220 ;
            0230 ;STore Data for Fine Scroll
            0240 ;
            0250     LDY FINE
            0260     BEQ STDDSP
            0270     ORA #$20
            0280 ;
            0290 ;STore Data for DiSPlay
            0300 ;
            0310 STDDSP LDY DSTAT
            0320     BMI EXIT
            0330     LDY #$00
            0340     STA (ADRESS),Y
            0350 ;
            0360 ;SinGle DECreasing
            0370 ;
            0380     LDA #$01
            0390 ;
            0400 ;DeCrease USing ACumulator
            0410 ;
            0420 DCUSAC STA SUBTMP
            0430     LDA DSTAT
            0440     BMI EXIT
            0450     LDA ADRESS
            0460     SEC
            0470     SBC SUBTMP
            0480     STA ADRESS
            0490     BCS BPS
            0500     DEC ADRESS+1
            0510 BPS LDA APPMHI+1
            0520     CMP ADRESS+1
            0530     BCC EXIT
            0540     BNE ERR
            0550     LDA APPMHI
            0560     CMP ADRESS
            0570     BCC EXIT
            0580 ERR LDA #$93
            0590     STA DSTAT
            0600 EXIT RTS
    Po wejściu od etykiety STDFSC sprawdzany jest znacznik FINE i, gdy jest różny od zera, w akumulatorze ustawiany jest bit 5. Następnie (od STDDSP) sprawdzany jest status ekranu (DSTAT) i, gdy wskazuje błąd, procedura się kończy. W przeciwnym razie zawartość akumulatora jest umieszczana w miejscu wskazanym wektorem ADRESS i następuje przejście do SGDEC.

    Pozostałe części procedury służą do zmniejszenia wartości wektora ADRESS. Rozpoczęcie procedury od DBDEC zmniejsza ADRESS o 2, od SGDEC ADRESS jest zmniejszany o jeden, a od DCUSAC - o aktualną zawartość akumulatora. Podczas operacji zmniejszania sprawdzany jest jeszcze status ekranu (DSTAT), a po niej otrzymany wynik jest porównywany z wektorem APPMHI (APPlication Memory HIgh), który wskazuje najwyższy adres zajęty przez program użytkownika. Jeżeli ADRESS jest mniejszy od APPMHI, to w rejestrze DSTAT umieszczany jest kod błędu $93 (INSUFFICIENT SCREEN MEMORY - niewystarczająca pamięć obrazu).

    Ponieważ trzy tryby uzyskiwane są poprzez układ GTIA, to po ich rozpoznaniu odpowiednia wartość jest wpisywana do dwóch najstarszych bitów rejestru GTICTLS (GTIA ConTroL Shadow register). Ponadto tryby $09, $0A, $0B i $0F wymagają jeszcze zwiększenia obszaru pamięci obrazu, więc ponownie wywoływana jest procedura DCUSAC.

    Ostatecznie obliczony adres początkowy pamięci obrazu jest przepisywany z rejestru pomocniczego ADRESS do właściwego wektora SAVMSC (SAVe Memory SCreen). Wywołanie procedury SGDEC daje nam teraz w rezultacie adres końcowy programu ANTIC-a. Po pobraniu z tabeli TDLVL wartości określającej podział programu ANTIC-a (zob. rozdział 7) obliczany jest adres jego ostatniej instrukcji i przez wywołanie STDDSP zostaje ona umieszczona na właściwym miejscu.
            0100 ;Table: Display List VuLnerability
            0110 ;
            0120     *=  $EE5D
            0130 ;
            0140     .BYTE $00,$00,$00,$00
            0150     .BYTE $00,$00,$00,$01
            0160     .BYTE $01,$01,$01,$01
            0170     .BYTE $00,$00,$01,$01
    Kolejna faza procedury służy do określenia parametrów okna tekstowego. Najpierw do rejestru BOTSCR (BOTtom SCreen Rows) jest wpisywana liczba wierszy w trybie 0 ($18). Jeśli wybrany został jeden z trybów 9-11 lub bit 4 w ICAX1 jest skasowany, to etap ten jest pomijany. W przeciwnym razie w BOTSCR umieszczana jest wartość $04, która określa liczbę wierszy w oknie tekstowym. Gdy znacznik FINE zezwala na delikatny przesuw obrazu, to wywoływana jest procedura SSDLE.
            0100 ;Set Scrolling DL Entry
            0110 ;
            0120 STDDSP = $F570
            0130 ;
            0140     *=  $F5A0
            0150 ;
            0160     LDA #$02
            0170     JSR STDDSP
            0180     LDA #$A2
            0190     JSR STDDSP
            0200     DEX
            0210     RTS
    Wpisuje ona w przedostatnim rozkazie tworzenia linii obrazu wartość, która powoduje wywołanie procedury przerwania FSDL. Pozostałe rozkazy tworzenia linii obrazu są wpisywane przez wywołanie STDFS. Ostatnim rozkazem programu ANTIC-a ustalanym w tej fazie jest rozkaz ładowania licznika obrazu (w AMTIC-u) wartością adresu okna tekstowego.

    Pozostała część programu ANTIC-a jest wypełniana rozkazami tworzenia linii obrazu w wybranym trybie. Długość programu jest pobierana z tabeli TDLEC, przy czym pierwsze 16 pozycji w tej tabeli dotyczy trybów bez okna tekstowego, a reszta - trybów z oknem. Przy wpisywaniu programu jest także uwzględniany delikatny przesuw obrazu w trybie 0.
            0100 ;Table: Display List Entry Counts
            0110 ;
            0120     *=  $EE2D
            0130 ;
            0140     .BYTE $17,$17,$0B,$17
            0150     .BYTE $2F,$2F,$5F,$5F
            0160     .BYTE $61,$61,$61,$61
            0170     .BYTE $17,$0B,$BF,$61
            0180     .BYTE $13,$13,$09,$13
            0190     .BYTE $27,$27,$4F,$4F
            0200     .BYTE $41,$41,$41,$41
            0210     .BYTE $13,$09,$9F,$41
    Zapisywanie programu ANTIC-a kończy się po wpisaniu rozkazu ładującego licznik obrazu i rozkazów tworzących puste linie w górnej części ekranu. Teraz rejestr pomocniczy ADRESS zawiera adres ostatniej wolnej komórki pamięci RAM. Adres tej jest przepisywany do rejestru MEMTOP w celu zabezpieczenia obrazu przed zniszczeniem przez program użytkownika. Adres programu ANTIC-a jest natomiast umieszczany w rejestrze DLPTRS (Display List PoinTeR Shadow register) oraz po rozkazie skoku kończącym ten program (adres tego rozkazu jest przechowywany w rejestrze SAVADR).

    W tym momencie ekran jest już otwarty i pozostaje tylko sprawdzenie, czy podczas SCOPN nie wystąpił żaden błąd. Informację o tym zawiera rejestr DSTAT. W przypadku wykrycia błędu wykonywana jest procedura EDOPN, która otwiera edytor, aby umożliwić systemowi zasygnalizowanie błędu.

    Jeśli otwarcie przebiegło bezbłędnie, to sprawdzany jest bit 5 rejestru ICAX1. Gdy jest on skasowany, to zawartość pamięci obrazu jest kasowana przez wywołanie procedury CLRSCR (zob. str. 86), a kursor jest ustawiany w lewym, górnym rogu ekranu (z uwzględnieniem marginesu). Ostatnią czynnością jest ustawienie w rejestrze DMACTLS bitów 1 (normalna szerokość obrazu) i 5 (bezpośredni dostęp do pamięci dla programu ANTIC-a). Procedura SCOPN nie kończy się rozkazem RTS, lecz skokiem do RETURM.

    Procedura RETURM zawiera w sobie (od etykiety KBOPN) procedurę otwarcia i zamknięcia klawiatury oraz procedurę statusu dla klawiatury, ekranu i edytora.
            0100 ;RETURn from Monitor
            0110 ;
            0120 ATACHR = $02FB
            0130 CRSINH = $02F0
            0140 DINDEX = $57
            0150 DISPLY = $F1E9
            0160 DSTAT = $4C
            0170 GETPLT = $F18F
            0180 OLDCHR = $5D
            0190 ;
            0200     *=  $F20B
            0210 ;
            0220     JSR GETPLT
            0230     STA OLDCHR
            0240     LDX DINDEX
            0250     BNE KBOPN
            0260     LDX CRSINH
            0270     BNE KBOPN
            0280     EOR #$80
            0290     JSR DISPLY
            0300 ;
            0310 ;KeyBoard OPeN
            0320 ;
            0330 KBOPN LDY DSTAT
            0340     JMP SKIP
            0350 ;
            0360     *=  $F226
            0370 ;
            0380 SKIP LDA #$01
            0390     STA DSTAT
            0400     LDA ATACHR
            0410 ;
            0420 ;EDitor SPecial
            0430 ;
            0440     RTS
    Znajdujący się w środku RETURM skok służy do ominięcia instrukcji skoku do procedury testującej (TESTROM). Jest to pozostałość systemu Atari 400/800, który korzystał z tego adresu.

    RETURM najpierw odczytuje znak znajdujący się na pozycji kursora poprzez wywołanie procedury GETPLT. Jeżeli obraz jest w trybie 0 i kursor jest widoczny, to zamienia najstarszy bit tego znaku, co zmienia znak z normalnego na negatywowy lub odwrotnie. Następnie znak ten poprzez procedurę DISPLY jest ponownie umieszczany na ekranie.

    Dalszy przebieg procedury (od etykiety KBOPN) był już opisywany. Przypomnijmy, że w rejestrze Y umieszczany jest status ekranu, a w akumulatorze ostatnio użyty znak ASCII i status (DSTAT) otrzymuje wartość 1. KBOPN stanowi także procedurę odczytu statusu ekranu i edytora, zaś na jej ostatnią instrukcję (oznaczoną EDSP) wskazują wektory procedur specjalnych klawiatury i edytora oraz zapisu na klawiaturę.

3.2.2. Procedura zamknięcia ekranu

    Procedura zamykająca jest także wspólna dla ekranu i edytora. Służy ona właściwie jedynie do wyłączenia delikatnego przesuwu obrazu. Na początku procedury jest bowiem sprawdzany znacznik FINE i, gdy wskazuje on wyłączenie delikatnego przesuwu, następuje skok do procedury KBOPN.
            0100 ;SCRolling FINe
            0110 ;
            0120 DLIV =  $0200
            0130 EDOPN = $EF94
            0140 FINE =  $026E
            0150 KBOPN = $F21E
            0160 NMIEN = $D40E
            0170 RTI =   $C0CE
            0180 ;
            0190     *=  $F22E
            0200 ;
            0210     BIT FINE
            0220     BPL KBOPN
            0230     LDA #$40
            0240     STA NMIEN
            0250     LDA #$00
            0260     STA FINE
            0270     LDA # <RTI
            0280     STA DLIV
            0290     LDA # >RTI
            0300     STA DLIV+1
            0310     JMP EDOPN
    Jeżeli delikatny przesuw jest włączony, to najpierw blokowane są w rejestrze NMIEN przerwania wywoływane przez program ANTIC-a. Następnie znacznik FINE jest zerowany, a wektor DLIV otrzymuje wartość wskazującą na instrukcję RTI (powrót z przerwania). Ponieważ wyjście na ekran musi być stale czynne, to procedura kończy się bezpośrednio skokiem do EDOPN.

3.2.3. Zapis na ekranie

    znak przeznaczony do zapisania na ekranie jest umieszczany w akumulatorze i poprzez GOHAND wywoływana jest procedura OUTCH. Na jej początku znak jest przepisywany z akumulatora do rejestru ATACHR, a następnie dokonywane jest sprawdzenie jego kodu.
            0100 ;OUTput CHaracter
            0110 ;
            0120 ATACHR = $02FB
            0130 CLRSCR = $F420
            0140 EOLSUB = $F60E
            0150 OUTPLT = $F1CA
            0160 RANGE = $F6CA
            0170 RETURM = $F20B
            0180 RTWSCR = $F661
            0190 ;
            0200     *=  $F1A4
            0210 ;
            0220     STA ATACHR
            0230     CMP #$7D
            0240     BNE PT2
            0250     JSR CLRSCR
            0260     JMP RETURM
            0270 PT2 JSR RANGE
            0280 ;TeST for RETurn
            0290 TSTRET LDA ATACHR
            0300     CMP $9B
            0310     BNE PT3
            0320     JSR RTWSCR
            0330     JMP RETURM
            0340 PT3 JSR OUTPLT
            0350     JSR EOLSUB
            0360     JMP RETURM
    Jeżeli znak do zapisu oznacza czyszczenie ekranu ($7D), to po wywołaniu procedury CLRSCR, która przeprowadza tę operację, wykonywany jest skok do RETURM. W innym przypadku wywoływana jest procedura RANGE, której zadaniem jest sprawdzenie, czy kursor mieści się na ekranie.

    Jeżeli aktualna pozycja kursora mieści się w dozwolonym zakresie, to kod znaku jest porównywany z $9B (RETURN). Pozytywny wynik powoduje wywołanie procedury RTWSCR, a następnie przejście do RETURM. W przeciwnym razie wywoływane są procedury OUTPLT i SUBEND umieszczające znak na ekranie, a dopiero po tym następuje skok do RETURM.

    RANGE jest punktem wejścia do nieco większej procedury ERANGE, która służy do obsługi ekranu i edytora. Jeżeli ekran jest otwarty w trybie 0 lub posiada okno tekstowe, to obie procedury są identyczne. W przeciwnym razie najpierw otwierany jest edytor (przez EDOPN) i dopiero dalszy przebieg procedur (od RANGE) jest wspólny. Przy rozpoczęciu od RANGE pierwsza faza kontroli jest pomijana.
            0100 ;Editor RANGE
            0110 ;
            0120 BOTSCR = $02BF
            0130 COLCRS = $55
            0140 CRSHOM = $F440
            0150 DINDEX = $57
            0160 DSTAT = $4C
            0170 EDOPN = $EF94
            0180 IRQSTAT = $11
            0190 KBOPN = $F21E
            0200 RMARGN = $53
            0210 ROWCRS = $54
            0220 SWAP =  $F962
            0230 SWPFLG = $7B
            0240 TMCCN = $EE7D
            0250 TMRCN = $EE8D
            0260 ;
            0270     *=  $F6BC
            0280 ;
            0290     LDA BOTSCR
            0300     CMP #$04
            0310     BEQ RANGE
            0320     LDA DINDEX
            0330     BEQ RANGE
            0340     JSR EDOPN
            0350 RANGE LDA #$27
            0360     CMP RMARGN
            0370     BCS ROW
            0380     STA RMARGN
            0390 ROW LDX DINDEX
            0400     LDA TMRCN,X
            0410     CMP ROWCRS
            0420     BCC ERR
            0430     BEQ ERR
            0440     CPX #$08
            0450     BNE HCC
            0460     LDA COLCRS+1
            0470     BEQ SUC
            0480     CMP #$01
            0490     BNE ERR
            0500     BEQ COL
            0510 HCC LDA COLCRS+1
            0520     BNE ERR
            0530 COL LDA TMCCN,X
            0540     CMP COLCRS
            0550     BCC ERR
            0560     BEQ ERR
            0570 SUC LDA #$01
            0580     STA DSTAT
            0590     LDA #$80
            0600     LDX IRQSTAT
            0610     STA IRQSTAT
            0620     BEQ SWP
            0630     RTS
            0640 ERR JSR CRSHOM
            0650     LDA #$8D
            0660     STA DSTAT
            0670     PLA
            0680     PLA
            0690 SWP LDA SWFLG
            0700     BPL KOP
            0710     JMP SWAP
            0720 KOP JMP KBOPN
    Najpierw sprawdzany jest prawy margines ekranu. Jeżeli przekracza on $27, to jest sprowadzany do tej wartości. Następnie według zawartości DINDEX jest pobierana z tabeli TMRCN dopuszczalna liczba wierszy w danym trybie graficznym. Gdy aktualna pionowa pozycja kursora (w rejestrze ROWCRS - ROW CuRSor) przekracza tą liczbę, sygnalizowany jest błąd.
            0100 ;Table: Mode Row CouNts
            0110 ;
            0120     *=  $EE8D
            0130 ;
            0140     .BYTE $18,$18,$0C,$18
            0150     .BYTE $30,$30,$60,$60
            0160     .BYTE $C0,$C0,$C0,$C0
            0170     .BYTE $18,$0C,$C0,$C0
    Przed sprawdzeniem poziomego położenia kursora kontrolowany jest tryb graficzny. Ponieważ tryb 8 ma rozdzielczość poziomą 320 punktów, to w tym przypadku wystarczy sprawdzić, czy starszy bajt rejestru COLCRS (COLumn CuRSor) jest równy 0 lub 1. Inna wartość powoduje błąd. Błąd wystąpi także wtedy, gdy w pozostałych trybach starszy bajt COLCRS jest różny od zera. Ostateczna kontrola następuje po pobraniu z tabeli TMCCN dopuszczalnej liczby kolumn w danym trybie i porównaniu jej z młodszym bajtem COLCRS.
            0100 ;Table: Mode Column CouNts
            0110 ;
            0120     *=  $EE7D
            0130 ;
            0140     .BYTE $28,$14,$14,$28
            0150     .BYTE $50,$50,$A0,$A0
            0160     .BYTE $40,$50,$50,$50
            0170     .BYTE $28,$28,$A0,$A0
    Wykrycie błędu powoduje umieszczenie kursora w lewym, górnym rogu ekranu (przez CRSHOM), wpisanie do rejestru DSTAT kodu $8D (CURSOR OVERRANGE - kursor poza zakresem) oraz zdjęcie ze stosu adresu powrotnego do procedury bezpośrednio wywołującej RANGE (lub ERANGE). Przy poprawnym przebiegu procedury ta faza jest omijana, a rejestr DSTAT otrzymuje wartość 1.

    Sposób zakończenia procedury zależy od wartości znacznika SWPFLG (SWaP FLaG). Zero oznacza, że kursor znajduje się w oknie tekstowym i procedura kończy się skokiem do KBOPN. Odczytanie wartości $FF powoduje natomiast skok do procedury SWAP.
0100 ;SWAP cursor 0110 ; 0120 BOTSCR = $02BF 0130 KBOPN = $F21E 0140 ROWCRS = $54 0150 SWPFLG = $7B 0160 TXTROW = $0290 0170 ; 0180 *= $F962 0190 ; 0200 LDA BOTSCR 0210 CMP #$18 0220 BEQ EXIT 0230 LDX #$0B 0240 NEXT LDA ROWCRS,X 0250 PHA 0260 LDA TXTROW,X 0270 STA ROWCRS,X 0280 PLA 0290 STA TXTROW,X 0300 DEX 0310 BPL NEXT 0320 LDA SWPFLG 0330 EOR #$FF 0340 STA SWPFLG 0350 EXIT JMP KBOPN     Procedura SWAP przenosi kursor pomiędzy dwoma obszarami: ekranu i okna tekstowego. Przedtem jednak sprawdzany jest rejestr BOTSCR. Zapisana w nim wartość $18 oznacza, że ekran nie jest podzielony i przerywa procedurę.

    Każda inna wartość powoduje wymianę zawartości między dwoma obszarami po 12 bajtów rozpoczynającymi się od ROWCRS i TXTROW. Następnie znacznik SWPFLG jest zmieniany z $FF na zero lub odwrotnie i procedura jest opuszczana skokiem do KBOPN.

    Procedura RTWSCR wywoływana po rozpoznaniu znaku RETURN ma za zadanie umieszczenie kursora w następnej linii obrazu. Jeśli spowoduje to przekroczenie dopuszczalnego zakresu pozycji kursora, wykonywane jest przesunięcie zawartości ekranu w górę o jeden wiersz logiczny.
            0100 BUFSTR = $6C
            0110 COLCRS = $55
            0120 COMLOG = $F88E
            0130 DINDEX = $57
            0140 DOSCR = $F7F7
            0150 HOLD3 = $029D
            0160 INSDAT = $7D
            0170 LOGMAP = $02B2
            0180 ROWCRS = $54
            0190 SCLED = $F997
            0200 SCRFLG = $02BB
            0210 SWPFLG = $7B
            0220 TMRCN = $EE8D
            0230 ;
            0240     *=  $F661
            0250 ;
            0260 ;ReTurn With SCRoll
            0270 ;
            0280 RTWSCR LDA #$9B
            0290     STA INSDAT
            0300 ;
            0310 ;RETURN routine
            0320 ;
            0330 RETURN JSR SCLED
            0340     LDA #$00
            0350     STA COLCRS+1
            0360     INC ROWCRS
            0370     LDX DINDEX
            0380     LDY #$18
            0390     BIT SWPFLG
            0400     BPL ROW
            0410     LDY #$04
            0420     TYA
            0430     BNE CRS
            0440 ROW LDA TMRCN,X
            0450 CRS CMP ROWCRS
            0460     BNE EXIT
            0470     STY HOLD3
            0480     TXA
            0490     BNE EXIT
            0500     LDA INSDAT
            0510     BEQ EXIT
            0520     CMP #$9B
            0530     BEQ SCR
            0540     CLC
            0550 SCR JSR DOSCR
            0560     INC SCRFLG
            0570     DEC BUFSTR
            0580     BPL BPS
            0590     INC BUFSTR
            0600 BPS DEC HOLD3
            0610     LDA LOGMAP
            0620     SEC
            0630     BPL SCR
            0640     LDA HOLD3
            0650     STA ROWCRS
            0660 EXIT JMP COMLOG
    Na początku kod znaku RETURN ($9B) jest umieszczany w pomocniczym rejestrze INSDAT. Następnie kursor jest przesuwany na lewą krawędź obrazu przy pomocy procedury SCLED. Dla trybu 0 oraz dla okna tekstowego oznacza to ustawienie kursora na pozycji określonej przez zawartość rejestru LMARGN (Left MARGiN), w pozostałych przypadkach na pozycji 0.
            0100 ;Set Cursor at Left EDge
            0110 ;
            0120 COLCRS = $55
            0130 DINDEX = $57
            0140 LMARGN = $52
            0150 SWPFLG = $7B
            0160 ;
            0170     *=  $F997
            0180 ;
            0190     LDA #$00
            0200     LDX SWPFLG
            0210     BNE MRG
            0220     LDX DINDEX
            0230     BNE STR
            0240 MRG LDA LMARGN
            0250 STR STA COLCRS
            0260     RTS
    Teraz numer wiersza zawierającego kursor jest porównywany z dopuszczalną ich liczbą pobraną z tabeli TMRCN (dla okna tekstowego przyjmowana jest wartość 4). Jeśli liczby te są różne, tryb jest inny niż 0 lub w INSDAT jest wartość zero, to procedura się kończy. W przeciwnym razie wywoływana jest procedura DOSCR, która przesuwa obraz. Wywołanie to następuje w pętli, która jest przerywana po usunięciu z górnej części ekranu całego wiersza logicznego. Dopiero wtedy do rejestru ROWCRS wpisywana jest pionowa pozycja kursora i wykonywany jest skok do procedury COMLOG.

    Zadaniem procedury DOSCR jest przemieszczenie danych w pamięci obrazu w ten sposób, aby zawartość ekranu przesunęła się o jedną linię w górę. Choć czynność ta jest prosta, to procedura ma znaczną długość, gdyż konieczna jest duża ilość obliczeń.
            0100 ;DO SCRolling
            0110 ;
            0120 ADRESS = $64
            0130 BITROL = $F732
            0140 BOTSCR = $02BF
            0150 COLCRS = $55
            0160 COUNTR = $7E
            0170 FINE =  $026E
            0180 HOLD1 = $51
            0190 LGET2 = $F75A
            0200 LOGCOL = $63
            0210 PUTMSC = $F9A6
            0220 RAMTOP = $6A
            0230 ROWCRS = $54
            0240 VCOUNT = $D40B
            0250 VSFLAG = $026C
            0260 ;
            0270     *=  $F7F7
            0280 ;
            0290     JSR BITROL
            0300     LDA FINE
            0310     BEQ NSC
            0320 WT1 LDA VSFLAG
            0330     BNE WT1
            0340     LDA #$08
            0350     STA VSFLAG
            0360 WT2 LDA VSFLAG
            0370     CMP #$01
            0380     BNE WT2
            0390 WT3 LDA VCOUNT
            0400     CMP #$40
            0410     BCS WT3
            0420     LDX #$0D
            0430     LDA BOTSCR
            0440     CMP #$04
            0450     BNE WT4
            0460     LDX #$70
            0470 WT4 CPX VCOUNT
            0480     BCS WT4
            0490 NSC JSR PUTMSC
            0500 ;
            0510 ;COMpute ADdRess
            0520 ;
            0530 COMADR LDA ADRESS
            0540     LDX ADRESS+1
            0550 LOOP1 INX
            0560     CPX RAMTOP
            0570     BEQ NLN
            0580     SEC
            0590     SBC #$10
            0600     JMP LOOP1
            0610 NLN ADC #$27
            0620     BNE SCN
            0630     LDX ADRESS+1
            0640     INX
            0650     CPX RAMTOP
            0660     BEQ STCN
            0670     CLC
            0680     ADC #$10
            0690 SCN TAY
            0700     STA COUNTR
            0710     SEC
            0720     LDA ADRESS
            0730     SBC COUNTR
            0740     STA ADRESS
            0750     BCS IAD
            0760     DEC ADRESS+1
            0770 IAD LDA ADRESS
            0780     CLC
            0790     ADC #$28
            0800     STA COUNTR
            0810     LDA ADRESS+1
            0820     ADC #$00
            0830     STA COUNTR+1
            0840 NXT1 LDA (COUNTR),Y
            0850     STA (ADRESS),Y
            0860     INY
            0870     BNE NXT1
            0880     LDY #$10
            0890     LDA ADRESS
            0900     CMP #$D8
            0910     BEQ STCN
            0920     CLC
            0930     ADC #$F0
            0940     STA ADRESS
            0950     BCC IAD
            0960     INC ADRESS+1
            0970     BNE IAD
            0980 STCN LDX RAMTOP
            0990     DEX
            1000     STX COUNTR+1
            1010     LDX #$D8
            1020     STX COUNTR
            1030     LDA #$00
            1040     LDY #$27
            1050 NXT2 STA (COUNTR),Y
            1060     DEY
            1070     BPL NXT2
            1080 ;
            1090 ;COMpute LOGical line
            1100 ;
            1110 COMLOG LDA #$00
            1120     STA LOGCOL
            1130     LDA ROWCRS
            1140     STA HOLD1
            1150 LOOP2 LDA HOLD1
            1160     JSR LGET2
            1170     BCS EXIT
            1180     LDA LOGCOL
            1190     CLC
            1200     ADC #$28
            1210     STA LOGCOL
            1220     DEC HOLD1
            1230     JMP LOOP2
            1240 EXIT CLC
            1250     LDA LOGCOL
            1260     ADC COLCRS
            1270     STA LOGCOL
            1280     RTS
    Najpierw wywoływana jest procedura BITROL, która przesuwa o jeden bit w lewo trzy bajty rejestru LOGMAP (LOGical line MAP) zawierających mapę wierszy logicznych ekranu. Gdy włączony jest delikatny przesuw ekranu (wartość $FF w rejestrze FINE), to jego realizację umożliwiają teraz cztery petle opóźniające. Długość ostatniej z nich zależy od tego, czy przesuwany jest cały obraz, czy tylko okno tekstowe.
            0100 ;BIT ROtate Left
            0110 ;
            0120 LOGMAP = $02B2
            0130 ;
            0140     *=  $F732
            0150 ;
            0160     ROL LOGMAP+2
            0170     ROL LOGMAP+1
            0180     ROL LOGMAP
            0190     RTS
    Następnie wywoływana jest krótka procedura PUTMSC, która przepisuje adres pamięci obrazu z SAVMSC do pomocniczego rejestru ADRESS.
            0100 ;PUT Memory SCreen
            0110 ;
            0120 ADRESS = $64
            0130 SAVMSC = $58
            0140 ;
            0150     *=  $F9A6
            0160 ;
            0170     LDA SAVMSC
            0180     STA ADRESS
            0190     LDA SAVMSC+1
            0200     STA ADRESS+1
            0210     RTS
    Teraz rozpoczyna się najdłuższa część procedury oznaczona etykietą COMADR. Kolejno obliczane sa rzeczywiste adresy linii obrazu w pamięci i każda linia jest przepisywana (w pętli NXT1) o 40 bajtów niżej (w pamięci - na ekranie wyżej). Na końcu ostatnia linia jest wypełniana zerami (pętla NXT2).

    Ostatnia faza rozpoczynająca się od COMLOG służy do obliczenia wiersza logicznego ekranu. Jest ona także wywoływana osobno jako oddzielna procedura. Na początku adres kursora w wierszu logicznym LOGCOL (LOGical line COLumn) jest ustawiany na zero, a pionowa pozycja kursora na ekranie jest przepisywana z ROWCRS do tymczasowego rejestru HOLD1. Następnie z wartością odczytaną z HOLD1 wywoływana jest procedura LOGGET, lecz nie od początku, a od etykiety LGET2.
            0100 ;LOGical line GET
            0110 ;
            0120 BITCON = $F723
            0130 BITMSK = $6E
            0140 ROWCRS = $54
            0150 TABMAP = $02A3
            0160 ;
            0170     *=  $F758
            0180 ;
            0190     LDA ROWCRS
            0200 LGET2 CLC
            0210 LGET3 ADC #$78
            0220 ;
            0230 ;BIT GET
            0240 ;
            0250    JSR BITCON
            0260    CLC
            0270    LDA TABMAP,X
            0280    AND BITMSK
            0290    BEQ EXIT
            0300    SEC
            0310 EXIT RTS
    Wywołanie to jest powtarzane tak długo, dopóki po zakończeniu procedury LOGGET bit Carry nie będzie ustawiony, przy czym przed każdym kolejnym wywołaniem zawartość LOGCOL jest zwiększana o 40, a HOLD1 zmniejszana o jeden. Po tym jeszcze do adresu kursora w linii logicznej LOGCOL dodawana jest jego pozycja pozioma COLCRS i procedura się kończy.

    Procedura LOGGET według pionowego położenia kursora (lub według zawartości akumulatora - zależnie od punktu początkowego) odczytuje poprzez BITCON wzór bitowy wiersza logicznego i porównuje go z mapą tabulacji TABMAP. Jeżeli ich wartości są różne, to przed opuszczeniem procedury bit Carry jest ustawiany, w przeciwnym przypadku pozostaje skasowany.
            0100 ;BIT CONversion
            0110 ;
            0120 MSKTAB = $EEB4
            0130 BITMSK = $6E
            0140 ;
            0150     *=  $F723
            0160 ;
            0170     PHA
            0180     AND #$07
            0190     TAX
            0200     LDA MSKTAB,X
            0210     STA BITMSK
            0220     PLA
            0230     LSR A
            0240     LSR A
            0250     LSR A
            0260     TAX
            0270     RTS
    Procedura BITCON oddziela najpierw cztery młodsze bity akumulatora i według nich pobiera wartość maski bitowej z tabeli MSKTAB. Wartość ta jest zapisywana do rejestru BITMSK (BIT MaSK). Następnie poprzednia zawartość akumulatora jest trzykrotnie przesuwana w prawo (dzielona przez osiem) i przepisywana do rejestru X.
            0100 ;MaSK TABle
            0110 ;
            0120     *=  $EEB4
            0130 ;
            0140     .BYTE $80,$40,$20,$10
            0150     .BYTE $08,$04,$02,$01
    W celu umieszczenia znaku na ekranie z OUTCHR jest wywoływana procedura OUTPLT. Jeśli znacznik SSFLAG (Start/Stop FLAG) wskazuje zatrzymanie wyprowadzania danych na ekran, to procesor oczekuje na zezwolenie (np. przez naciśnięcie CONTROL-1). Następnie aktualna pozycja kursora na ekranie jest przepisywana z ROWCRS i COLCRS do OLDROW i OLDCOL oraz odczytywana jest zawartość rejestru ATACHR. Uzyskany znak w kodzie ATASCII jest zamieniany przy pomocy tabeli AINCC na znak w kodzie wewnętrznym komputera. Wymaga to odczytania bitów 5 i 6 znaku oraz dodania według nich wartości z tabeli.
            0100 ;OUTput PLoTted
            0110 ;
            0120 AINCC = $FB49
            0130 ADRESS = $64
            0140 ATACHR = $02FB
            0150 CHAR =  $02FA
            0160 CONVRT = $F5AC
            0170 DMASK = $02A0
            0180 OLDROW = $5A
            0190 ROWCRS = $54
            0200 SHFAMT = $6F
            0210 SSFLAG = $02FF
            0220 TEMP = $50
            0230 ;
            0240     *=  $F1CA
            0250 ;
            0260 OUTPLT LDA SSFLAG
            0270     BNE OUTPLT
            0280     LDX #$02
            0290 NXT LDA ROWCRS,X
            0300     STA OLDROW,X
            0310     DEX
            0320     BPL NXT
            0330     LDA ATACHR
            0340     TAY
            0350     ROL A
            0360     ROL A
            0370     ROL A
            0380     ROL A
            0390     AND #$03
            0400     TAX
            0410     TYA
            0420     AND #$9F
            0430     ORA AINCC,X
            0440 DISPLY STA CHAR
            0450     JSR CONVRT
            0460     LDA CHAR
            0470 JUSTP LSR SHFAMT
            0480     BCS MSK
            0490     ASL A
            0500     JMP JUSTP
            0510 MSK AND DMASK
            0520     STA TEMP
            0530     LDA DMASK
            0540     EOR #$FF
            0550     AND (ADRESS),Y
            0560     ORA TEMP
            0570     STA (ADRESS),Y
            0580     RTS

            0100 ;Atascii to INternal
            0110 ;Conversion Constans
            0120 ;
            0130     *=  $FB49
            0140 ;
            0150     .BYTE $40,$00,$20,$60
    Obliczony w ten sposób znak jest zapisywany do CHAR i przez wywołanie procedury CONVRT współrzędne kursora są zamieniane na rzeczywisty adres w pamięci obrazu. Następnie zawartość rejestru SHFAMT (SHiFt AMounT) jest przesuwana w prawo, aż do ustawienia bitu Carry. Po skasowaniu zbędnych bitów przy pomocy maski DMASK (Display MASK) uzyskana wartość jest dodawana do zawartości pamięci obrazu.

    Wspomniana już procedura CONVRT odczytuje współrzędne kursora z rejestrów ROWCRS oraz COLCRS i przelicza je na adres kursora w pamięci obrazu. W tym celu najpierw numer wiersza z ROWCRS jest mnożony przez pięć i zapisywany do ADRESS.
            0100 ;CONVeRT position to address
            0110 ;
            0120 ADRESS = $64
            0130 COLCRS = $55
            0140 DINDEX = $57
            0150 DMASK = $02A0
            0160 MLTTMP = $66
            0170 OLDADR = $5E
            0180 ROWCRS = $54
            0190 SAVADR = $68
            0200 SAVMSC = $58
            0210 SHFAMT = $6F
            0220 TBMSK = $FB04
            0230 TDMSK = $EEAD
            0240 TLSHC = $EE6D
            0250 TRSHC = $EE9D
            0260 ;
            0270     *=  $F5AC
            0280 ;
            0290     LDX #$01
            0300     STX MLTTMP
            0310     DEX
            0320     STX ADRESS+1
            0330     LDA ROWCRS
            0340     ASL A
            0350     ROL ADRESS+1
            0360     ASL A
            0370     ROL ADRESS+1
            0380     ADC ROWCRS
            0390     STA ADRESS
            0400     BCC LSH
            0410     INC ADRESS+1
            0420 LSH LDY DINDEX
            0430     LDX TLSHC,Y
            0440 NXT ASL ADRESS
            0450     ROL ADRESS+1
            0460     DEX
            0470     BNE NXT
            0480     LDA COLCRS+1
            0490     LSR A
            0500     LDA COLCRS
            0510     LDX TRSHC,Y
            0520     BEQ BPS
            0530 LOP ROR A
            0540     ASL MLTTMP
            0550     DEX
            0560     BNE LOP
            0570 BPS ADC ADRESS
            0580     BCC NHI
            0590     INC ADRESS+1
            0600 NHI CLC
            0610     ADC SAVMSC
            0620     STA ADRESS
            0630     STA OLDADR
            0640     LDA ADRESS+1
            0650     ADC SAVMSC+1
            0660     STA ADRESS+1
            0670     STA OLDADR+1
            0680     LDX TRSHC,Y
            0690     LDA TBMSK,X
            0700     AND COLCRS
            0710     ADC MLTTMP
            0720     TAY
            0730     LDA TDMSK-1,Y
            0740     STA DMASK
            0750     STA SHFAMT
            0760     LDY #$00
            0770     RTS
    Zawartość ADRESS jest z kolei mnożona przez 2 do potęgi pobranej z tabeli TLSHC. Wartość z tabeli jest wybierana według numeru trybu przechowywanego w rejestrze DINDEX. Teraz z numeru kolumny najstarsze bity są przepisywane do pomocniczego rejestru MLTTMP. Liczba wydzielonych bitów jest określana na podstawie tabeli TRSHC.
            0100 ;Table Left SHift Columns
            0110 ;
            0120     *=  $EE6D
            0130 ;
            0140     .BYTE $03,$02,$02,$01
            0150     .BYTE $01,$02,$02,$03
            0160     .BYTE $03,$03,$03,$03
            0170     .BYTE $03,$03,$02,$03

            0100 ;Table Right SHift Columns
            0110 ;
            0120     *=  $EE9D
            0130 ;
            0140     .BYTE $00,$00,$00,$02
            0150     .BYTE $03,$02,$03,$02
            0160     .BYTE $03,$01,$01,$01
            0170     .BYTE $00,$00,$03,$02
    Obliczone w ten sposób miejsce w kolumnie jest dodawane do ADRESS i w rezultacie otrzymujemy adres punktu liczony od początku pamięci obrazu. Adres bezwzględny uzyskiwany jest po dodaniu do ADRESS wektora SAVMSC. Wynik ten jest zapisywany jednocześnie w rejestrze OLDADR. Ponieważ jeden bajt pamięci obrazu może odpowiadać kilku punktom na ekranie, to według TRSHC jest odczytywany z tabeli TBMSK numer maski bitowej.
            0100 ;Table Bit MaSK
            0110 ;
            0120     *=  $FB04
            0130 ;
            0140     .BYTE $00,$01,$03,$07
    Po poprawieniu według zawartości COLCRS i MLTTMP numer ten służy do odczytania z tabeli TDMSK odpowiedniej maski bitowej. Pobrana maska jest przed zakończeniem procedury zapisywana do rejestrów DMASK i SHFAMT.
            0100 ;Table Display MaSK
            0110 ;
            0120     *=  $EEAD
            0130 ;
            0140     .BYTE $FF,$F0,$0F,$C0
    Po umieszczeniu znaku na ekranie wywoływana jest jeszcze z OUTCH procedura EOLSUB. Ma ona trzy punkty początkowe: EOLSUB, INCRSB i SCRIBT. Różnią się one tylko wprowadzonym znakiem. Przy rozpoczęciu od EOLSUB jest to znak RETURN ($9B), od INCRSB - znak $00, a od SCRIBT znak umieszczony uprzednio w rejestrze INSDAT.
            0100 BITGET = $F75D
            0110 COLCRS = $55
            0120 COMLOG = $F88E
            0130 DINDEX = $57
            0140 INSDAT = $7D
            0150 INSLN2 = $F50D
            0160 LOGCOL = $63
            0170 RETURN = $F665
            0180 RMARGN = $53
            0190 ROWCRS = $54
            0200 RTWSCR = $F661
            0210 TMCCN = $EE7D
            0220 ;
            0230     *=  $F609
            0240 ;
            0250 END RTS
            0260 ;
            0270 ;INcrease CuRsor SuBroutine
            0280 ;
            0290 INCRSB LDA #$00
            0300     BEQ SKIP
            0310 ;
            0320 ;End Of Line SUBroutine
            0330 ;
            0340 EOLSUB LDA #$9B
            0350 SKIP STA INSDAT
            0360 ;
            0370 ;SCRoll If BoTtom
            0380 ;
            0390 SCRIBT INC LOGCOL
            0400     INC COLCRS
            0410     BNE BPS
            0420     INC COLCRS+1
            0430 BPS LDA COLCRS
            0440     LDX DINDEX
            0450     CMP TMCCN,X
            0460     BEQ GRC
            0470     CPX #$00
            0480     BNE END
            0490     CMP RMARGN
            0500     BEQ END
            0510     BCC END
            0520 GRC CPX #$08
            0530     BNE LGC
            0540     LDA COLCRS+1
            0550     BEQ END
            0560 LGC LDA DINDEX
            0570     BNE RETURN
            0580     LDA LOGCOL
            0590     CMP #$51
            0600     BCC NLN
            0610     LDA INSDAT
            0620     BEQ RETURN
            0630     JSR RTWSCR
            0640     JMP EXIT
            0650 NLN JSR RETURN
            0660     LDA ROWCRS
            0670     CLC
            0680     ADC #$78
            0690     JSR BITGET
            0700     BCC EXIT
            0710     LDA INSDAT
            0720     BEQ EXIT
            0730     CLC
            0740     JSR INSLN2
            0750 EXIT JMP COMLOG
    Najpierw zwiększana jest pozioma pozycja kursora i jego adres w wierszu logicznym. Gdy kursor nie osiągnął jeszcze końca linii, procedura kończy się rozkazem RTS; w przeciwnym razie, jeśli nie jest to tryb 0, przez skok do RETURN (wewnątrz RTWSCR). W trybie 0, jeśli kursor znajduje się w trzeciej linii wiersza logicznego i w INSDAT zapisany jest znak zero, także następuje skok do RETURN. Każdy inny znak powoduje wywołanie procedury RTWSCR i potem skok do COMLOG.

    Jeżeli kursor nie znajduje się jeszcze w ostatniej linii wiersza logicznego, to poprzez wywołanie BITGET sprawdza się, czy jest to początek następnego wiersza logicznego. Jeżeli nie lub gdy znak w INSDAT jest zero, to następuje skok do COMLOG. Gdy kursor znalazł się w nowym wierszu logicznym, przez wywołanie procedury INSLIN (ale od etykiety INSLN2) do aktualnego wiersza dodawana jest następna linia fizyczna.

3.2.4. Odczyt z ekranu

    Żądanie odczytu z ekranu powoduje wywołanie przez CIO procedury GETCH. Poprzez serię wywołań innych procedur kolejno jest sprawdzany zakres pozycji kursora na ekranie (RANGE), punkt jest odczytywany z ekranu (GETPLT) i zamieniany na kod ASCII (INATAC). Po przesunięciu kursora na następną pozycję ekranu przez INCRSB procedura kończy się skokiem do KBOPN.
            0100 ;GET CHaracter
            0110 ;
            0120 GETPLT = $F18F
            0130 INATAC = $F76A
            0140 INCRSB = $F60A
            0150 KBOPN = $F21E
            0160 RANGE = $F6CA
            0170 ;
            0180     *=  $F180
            0190 ;
            0200     JSR RANGE
            0210     JSR GETPLT
            0220     JSR INATAC
            0230     JSR INCRSB
            0240     JMP KBOPN
    Pobierająca znak z ekranu procedura GETPLT najpierw wywołuje CONVRT w celu obliczenia adresu kursora w pamięci. Odczytany bajt jest następnie zamieniany na znak przy pomocy maski bitowej DMASK i rejestru przesunięć SHFAMT. Uzyskany w ten sposób znak jest zapisywany do rejestru CHAR.
            0100 ;GET PLoTted
            0110 ;
            0120 ADRESS = $64
            0130 CHAR =  $02FA
            0140 CONVRT = $F5AC
            0150 DMASK = $02A0
            0160 SHFAMT = $6F
            0170 ;
            0180     *=  $F18F
            0190 ;
            0200     JSR CONVRT
            0210     LDA (ADRESS),Y
            0220     AND DMASK
            0230 NEXT LSR SHFAMT
            0240     BCS EXIT
            0250     LSR A
            0260     BPL NEXT
            0270 EXIT STA CHAR
            0280     CMP #$00
            0290     RTS
    Następna procedura zamienia znak zapisany w CHAR z kodu wewnętrznego na kod ASCII. Najpierw jednak dokonywane jest sprawdzenie trybu graficznego. Jeżeli jest to tryb bitowy (od $03 do $0B oraz $0E i $0F), to znak bez żadnej zmiany jest przepisywany do rejestru ATACHR i procedura się kończy (przez RTS - powrót z procedury).
            0100 ;INternal to ATAscii Conversion
            0110 ;
            0120 ATACHR = $02FB
            0130 CHAR =  $02FA
            0140 DINDEX = $57
            0150 INACC = $FB4D
            0160 ;
            0170     *=  $F76A
            0180 ;
            0190     LDA CHAR
            0200     LDY DINDEX
            0210     CPY #$0E
            0220     BCS EXIT
            0230     CPY #$0C
            0240     BCS CNV
            0250     CPY #$03
            0260     BCS EXIT
            0270 CNV ROL A
            0280     ROL A
            0290     ROL A
            0300     ROL A
            0310     AND #$03
            0320     TAX
            0330     LDA CHAR
            0340     AND #$9F
            0350     ORA INACC,X
            0360 EXIT STA ATACHR
            0370     RTS
    W trybach tekstowych współczynnik zamiany kodu jest odczytywany z tabeli INACC według bitów 5 i 6 znaku. Po dodaniu tego współczynnika do wartości znaku, wynik umieszczany jest w ATACHR.
            0100 ;INternal to Atascii
            0110 ;Conversion Constans
            0120 ;
            0130     *=  $FB4D
            0140 ;
            0150     .BYTE $20,$40,$00,$60
    Ponieważ procedura GETCH kończy się skokiem do KBOPN, to znak znajdujący się w ATACHR jest tam przepisywany do akumulatora i w ten sposób przekazywany do CIO.
Zientara Wojciech: Mapa pamięci Atari XL/XE. Procedury wejścia-wyjścia, SOETO, Warszawa, 1988.