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.
|