3.2.5. Operacje specjalne na ekranie
Poza procedurami standardowymi na ekranie można jeszcze
wykonać dwie operacje specjalne: DRAW (kod $11) i FILL (kod
$12). Pierwsza z nich służy do rysowania linii, druga dodatkowo
wypełnia kolorem obraz w prawo od rysowanej linii. Dla
realizacji tych funkcji trzeba przed wywołaniem procedury CIO
umieścić kursor na pozycji docelowej (do której ma być
narysowana linia), a w przypadku FILL dodatkowo w rejestrze
FILDAT (FILl DATa) należy umieścić numer koloru (wzoru
bitowego) do wypełniania obrazu. Procedura CIOMAIN po
rozpoznaniu kodu operacji specjalnej wywołuje procedurę DRAW.
Jest ona stosunkowo długa ze względu na dużą ilość obliczeń.
Najpierw sprawdzany jest kod operacji. Gdy jest równy $11
(DRAW), to rejestr FILFLG otrzymuje wartość 0, gdy $12, to
wartość 1. Inne kody powodują umieszczenie w rejestrze Y kodu
błędu $84 (INVALID COMMAND) i przerwanie procedury.
0100 ;DRAW routine 0570 STA NEWCOL+1
0110 ; 0580 LDA #$01
0120 ATACHR = $02FB 0590 STA ROWINC
0130 COLAC = $72 0600 STA COLINC
0140 COLCRS = $55 0610 SEC
0150 COLINC = $02F9 0620 LDA NEWROW
0160 COUNTR = $7E 0630 SBC OLDROW
0170 DELTAC = $77 0640 STA DELTAR
0180 DELTAR = $76 0650 BCS DLC
0190 ENDPT = $74 0660 LDA #$FF
0200 FILDAT = $02FD 0670 STA ROWINC
0210 FILFLG = $02B7 0680 LDA DELTAR
0220 GETPLT = $F18F 0690 EOR #$FF
0230 HOLD4 = $02BC 0700 CLC
0240 ICCOMZ = $22 0710 ADC #$01
0250 KBOPN = $F21E 0720 STA DELTAR
0260 NEWCOL = $02F6 0730 DLC SEC
0270 NEWROW = $02F5 0740 LDA NEWCOL
0280 OLDCOL = $5B 0750 SBC OLDCOL
0290 OLDROW = $5A 0760 STA DELTAC
0300 OUTPLT = $F1CA 0770 LDA NEWCOL+1
0310 PHACRS = $F94C 0780 SBC OLDCOL+1
0320 PLACRS = $F957 0790 STA DELTAC+1
0330 RANGE = $F6CA 0800 BCS SAV
0340 ROWAC = $70 0810 LDA #$FF
0350 ROWCRS = $54 0820 STA C0LINC
0360 ROWINC = $02F8 0830 LDA DELTAC
0370 SCRIBT = $F612 0840 EOR #$FF
0380 SUBEND = $F6AE 0850 STA DELTAC
0390 ; 0860 LDA DELTAC+1
0400 *= $F9AF 0870 EOR #$FF
0410 ; 0880 STA DELTAC+1
0420 LDX #$00 0890 INC DELTAC
0430 LDA ICCOMZ 0900 BNE SAV
0440 CMP #$11 0910 INC DELTAC+1
0450 BEQ DRW 0920 SAV LDX #$02
0460 CMP #$12 0930 LDY #$00
0470 BEQ FIL 0940 STY COLAC+1
0480 LDY #$84 0950 NXT TYA
0490 RTS 0960 STA ROWAC,Y
0500 FIL INX 0970 LDA OLDROW,X
0510 DRW STX FILFLG 0980 STA ROWCRS,X
0520 LDA ROWCRS 0990 DEX
0530 STA NEWROW 1000 BPL NXT
0540 LDA COLCRS 1010 LDA DELTAC
0550 STA NEWCOL 1020 INX
0560 LDA COLCRS+1 1030 TAY
1040 LDA DELTAC+1 1550 BNE CRS
1050 STA COUNTR+1 1560 LDA COLAC
1060 STA ENDPT+1 1570 CMP ENDPT
1070 BNE CKE 1580 BCC PLOT
1080 LDA DELTAC 1590 CRS BIT COLINC
1090 CMP DELTAR 1600 BPL ICC
1100 BCS CKE 1610 DEC COLCRS
1110 LDA DELTAR 1620 LDA COLCRS
1120 LDX #$02 1630 CMP #$FF
1130 TAY 1640 BNE POINT
1140 CKE TYA 1650 LDA COLCRS+1
1150 STA COUNTR 1660 BEQ POINT
1160 STA ENDPT 1670 DEC COLCRS+1
1170 PHA 1680 BPL POINT
1180 LDA ENDPT+1 1690 ICC INC COLCRS
1190 LSR A 1700 BNE POINT
1200 PLA 1710 INC COLCRS+1
1210 ROR A 1720 POINT LDX #$02
1220 STA ROWAC,X 1730 JSR SUBEND
1230 LOOP LDA COUNTR 1740 PLOT JSR RANGE
1240 ORA COUNTR+1 1750 JSR OUTPLT
1250 BNE CONT 1760 LDA FILFLG
1260 JMP EXIT 1770 BEQ NPT
1270 CONT CLC 1780 JSR PHACRS
1280 LDA ROWAC 1790 LDA ATACHR
1290 ADC DELTAR 1800 STA HOLD4
1300 STA ROWAC 1810 LOOP2 LDA ROWCRS
1310 BCC SKIP 1820 PHA
1320 INC ROWAC+1 1830 JSR SCRIBT
1330 SKIP LDA ROWAC+1 1840 PLA
1340 CMP ENDPT+1 1850 STA ROWCRS
1350 BCC COL 1860 JSR RANGE
1360 BNE ROW 1870 JSR GETPLT
1370 LDA ROWAC 1880 BNE FIN
1380 CMP ENDPT 1890 LDA FILDAT
1390 BCC COL 1900 STA ATACHR
1400 ROW CLC 1910 JSR OUTPLT
1410 LDA ROWCRS 1920 JMP LOOP2
1420 ADC ROWINC 1930 FIN LDA HOLD4
1430 STA ROWCRS 1940 STA ATACHR
1440 LDX #$00 1950 JSR PLACRS
1450 JSR SUBEND 1960 NPT SEC
1460 COL CLC 1970 LDA COUNTR
1470 LDA COLAC 1980 SBC #$01
1480 ADC DELTAC 1990 STA COUNTR
1490 STA COLAC 2000 LDA COUNTR+1
1500 LDA COLAC+1 2010 SBC #$00
1510 ADC DELTAC+1 2020 STA COUNTR+1
1520 STA COLAC+1 2030 BMI EXIT
1530 CMP ENDPT+1 2040 JMP LOOP
1540 BCC PLOT 2050 EXIT JMP KBOPN
Przed rozpoczęciem rysowania linii muszą zostać określone
jej parametry. W tym celu aktualna pozycja kursora (na końcu
rysowanej linii) jest przepisywana z rejestrów ROWCRS i COLCRS
do NEWROW i NEWCOL. Następnie przez odjęcie poprzedniej pozycji
(na początku linii) przechowywanej w rejestrach OLDROW i OLDCOL
obliczany jest przyrost obu współrzędnych, który jest
zapisywany odpowiednio do DELTAR (DELTA Row) i DELTAC (DELTA
Column). Z kolei według znaku przyrostu ustalane są kroki
zmiany wiersza i kolumny (ROWINC - ROW INCrement i COLINC -
COLumn INCrement). Dla przyrostów dodatnich mają one wartość
$01, a dla ujemnych $FF.
W dalszej części zerowane są liczniki rysowanej linii COLAC
(COLumn ACtual) i ROWAC (ROW ACtual) oraz odtwarzana jest
poprzednia pozycja kursora z rejestrów OLD... . Większa z
wartości przyrostów (DELTAR lub DELTAC) jest następnie
umieszczana w liczniku COUNTR i rejestrze ENDPT (END PoinTer)
oraz, po podzieleniu przez dwa w rejestrze ROWAC lub COLAC.
Teraz rozpoczyna się rysowanie linii w pętli, która jest
przerywana po całkowitym wyzerowaniu licznika COUNTR. Po
opuszczeniu pętli następuje skok do KBOPN i zakończenie
procedury.
Najpierw do rejestrów aktualnej pozycji kursora na
rysowanej linii (ROWAC i COLAC) dodawany jest przyrost (DELTAR
i DELTAC), a wynik jest porównywany ze wskaźnikiem końca
rysowania (ENDPT). Znalezienie większej z różnic powoduje
zwiększenie odpowiedniego rejestru pozycji kursora (ROWCRS lub
COLCRS) i uaktualnienie wartości w COLAC lub ROWAC poprzez
wywołanie procedury SUBEND. Przedtem do rejestru X wpisywana
jest wartość określająca aktualizowany rejestr. $00 oznacza
rejestr ROWAC, a $02 - COLAC.
0100 ;SUBtract END point
0110 ;
0120 ENDPT = $74
0130 ROWAC = $70
0140 ;
0150 *= $F6AE
0160 ;
0170 SEC
0180 LDA ROWAC,X
0190 SBC ENDPT
0200 STA ROWAC,X
0210 LDA ROWAC+1,X
0220 SBC ENDPT+1
0230 STA ROWAC+1,X
0240 RTS
Teraz przez wywołanie RANGE sprawdzane jest, czy obliczona
pozycja kursora mieści się na ekranie. Z kolei wywołanie OUTPLT
umieszcza punkt na pozycji kursora. Jeżeli znacznik FILFLG jest
równy zero, to po zmniejszeniu o jeden licznika COUNTR
następuje powrót do początku pętli rysującej.
Znacznik FILFLG różny od zera powoduje rozpoczęcie
wewnętrznej pętli, której zadaniem jest wypełnienie obrazu w
prawo do najbliższego punktu. Pętla ta w ogólnym zarysie jest
podobna do pętli rysującej linię. Na jej początku aktualna
pozycja kursora jest zapisywana przez procedurę PHACRS do
tymczasowych rejestrów TMPROW i TMPCOL, a znak z rejestru
ATACHR przepisywany jest do HOLD4. Teraz kolejno wywoływane są
procedury SCRIBT, RANGE i GETPLT.
0100 ;PusH A CuRSor
0110 ;
0120 ROWCRS = $54
0130 TMPROW = $02B8
0140 ;
0150 *= $F94C
0160 ;
0170 LDX #$02
0180 NEXT LDA ROWCRS,X
0190 STA TMPROW,X
0200 DEX
0210 BPL NEXT
0220 RTS
Jeżeli punkt odczytany z ekranu przez GETPLT jest zerem, to
zostaje wypełniony. Zawartość FILDAT jest w tym celu
przepisywana do ATACHR i poprzec procedurę OUTPLT umieszczana
na ekranie. Potem następuje skok do początku pętli wewnętrznej
i operacja się powtarza.
Odczytanie przez GETPLT punktu różnego od zera kończy pętlę
wypełniającą. Przed powrotem do rysowania linii odtwarzany jest
z rejestru HOLD4 znak w ATACHR, a procedura PLACRS odtwarza
pozycję kursora. Taki sposób postępowania pozwala na
wypełnienie obszaru kolorem innym niż kolor rysowanej linii.
0100 ;PulL A CuRSor
0110 ;
0120 ROWCRS = $54
0130 TMPROW = $02B8
0140 ;
0150 *= $F957
0160 ;
0170 LDX #$02
0180 NEXT LDA TMPROW,X
0190 STA ROWCRS,X
0200 DEX
0210 BPL NEXT
0220 RTS
3.3. Procedury obsługi edytora
Edytor jest urządzeniem wejścia i wyjścia będącym
połączeniem klawiatury i ekranu w trybie 0. Z tego względu
większość procedur obsługi edytora jest wspólna w całości lub
znacznej części z procedurami obsługi tych dwóch urządzeń.
Wektory edytora w tabeli EDTVEC wskazują następujące procedury:
OPEN - EDOPN
CLOSE - SCRFIN
GET - EGETCH
PUT - EOUTCH
STATUS - KBOPN
SPECIAL - EDSP
Z tego wykazu widać od razu, że procedura zamknięcia
edytora jest identyczna z procedurą zamknięcia ekranu (SCRFIN),
a procedura odczytu statusu jest wspólna dla klawiatury i
edytora (KBOPN). Etykietą EDSP jest natomiast oznaczony rozkaz
RTS, bowiem tej funkcji edytor nie posiada.
3.3.1. Procedura otwarcia edytora
Procedura otwarcia edytora jest identyczna z procedurą
otwarcia ekranu w trybie 0 (SCOPN). Są one opisane razem w
rozdziale 3.2.1. (str. 49). Przy rozpatrywaniu tej i innych
procedur trzeba pamiętać, że otwarcie edytora zawsze kasuje
zawartość ekranu. Edytor nie może również posiadać okna
tekstowego. Natomiast w trybach graficznych z oknem tekstowym
zawsze obraz należy do ekranu, a okno do edytora.
3.3.2. Zapis do edytora
Kod rozkazu PUT powoduje wywołanie przez CIO procedury
EOUTCH. Przed jej wywołaniem w akumulatorze umieszczany jest
znak do zapisu na ekranie. Na początku procedury znak ten jest
wpisywany do rejestru ATACHR. Następnie wywoływana jest
procedura SWAP, której zadaniem jest przenoszenie kursora z
ekranu do okna tekstowego (jeśli istnieje) i odwrotnie. Po niej
wywoływana jest procedura ERANGE, która z kolei sprawdza, czy
pozycja kursora mieści się w dopuszczalnych granicach. Etap
początkowy kończy się wyzerowaniem znacznika SUPERF.
Od tego miejsca, które jest oznaczone etykietą PRCCHR i
wykorzystywane także przy odczycie znaku, rozpoczyna się
właściwa obsługa znaku wyprowadzanego na ekran.
Najpierw wywoływana jest procedura OFFCRS, która odczytuje
znak znajdujący się pod kursorem i umieszcza go na pozycji
kursora. Następnie procedura TSTCNT sprawdza, czy jest to znak
kontrolny edytora, przy czym po znalezieniu znaku jego numer w
tabeli CNTRLS znajduje się w rejestrze X. Jeżeli nie jest to
znak kontrolny, to po skasowaniu zawartości rejestru ESCFLG i
wywołaniu TSTRET sprawdzającej, czy jest to znak RETURN,
procedura kończy się skokiem do SWAP. Jeśli znak został
znaleziony w CNTRLS, to sprawdzane są znaczniki ekranu DSPFLG
(DiSPlay FLaG) i znaku Escape ESCFLG (ESCape FLaG). Gdy oba są
równe zero, również procedura kończy się poprzez TSTRET i SWAP.
0100 ;Editor OUTput CHaracter
0110 ;
0120 ADRESS = $64
0130 ATACHR = $02FB
0140 CNTRLS = $FB0D
0150 DSPFLG = $02FE
0160 ERANGE = $F6BC
0170 ESCFLG = $02A2
0180 JSRIND = $F2AD
0190 OFFCRS = $F718
0200 RETURM = $F20B
0210 SUPERF = $03E8
0220 SWAP = $F962
0230 TSTCNT = $F93C
0240 TSTRET = $F1B4
0250 ;
0260 *= $F2B0
0270 ;
0280 STA ATACHR
0290 JSR SWAP
0300 JSR ERANGE
0310 LDA #$00
0320 STA SUPERF
0330 ;
0340 ;PRoCeed CHaRacter
0350 ;
0360 PRCCHR JSR OFFCRS
0370 JSR TSTCNT
0380 BEQ TCN
0390 CHR ASL ESCFLG
0400 JSR TSTRET
0410 JMP SWAP
0420 TCN LDA DSPFLG
0430 ORA ESCFLG
0440 BEQ CHR
0450 ASL ESCFLG
0460 INX
0470 LDA SUPERF
0480 BEQ CNT
0490 TXA
0500 CLC
0510 ADC #$2D
0520 TAX
0530 CNT LDA CNTRLS,X
0540 STA ADRESS
0550 LDA CNTRLS+1,X
0560 STA ADRESS+1
0570 JSR JSRIND
0580 JSR RETURM
0590 JMP SWAP
Po rozpoznaniu znaku kontrolnego i możliwości jego
wykonania jest kasowany znacznik ESCFLG i sprawdzany rejestr
SUPERF. Jest to potrzebne jedynie w przypadku rozpoczęcia
procedury od PRCCHR, gdyż po wywołaniu od EOUTCH jest on
skasowany. Jeśli SUPERF jest różny od zera, to numer znaku
kontrolnego jest zwiększany o $2D. Przyczyna tej operacji
będzie oczywista po analizie procedury KBGBYT (str. 39).
Następnie według numeru znaku z tabeli CNTRLS jest
pobierany adres jego procedury. Zostaje on umieszczony w
rejestrze ADRESS i procedura ta jest wywoływana poprzez JSRIND.
Po jej zakończeniu i wywołaniu RETURM procedura EOUTCH kończy
się skokiem do SWAP.
Procedura OFFCRS w celu odtworzenia znaku znajdującego się
pod kursorem pobiera jego kod z rejestru OLDCHR (OLD CHaRacter)
i umieszcza go w miejscu określonym przez wektor OLDADR (OLD
ADdRess).
0100 ;OFF CuRSor
0110 ;
0120 OLDADR = $5E
0130 OLDCHR = $5D
0140 ;
0150 *= $F718
0160 ;
0170 LDY #$00
0180 LDA OLDADR+1
0190 BEQ EXIT
0200 LDA OLDCHR
0210 STA (OLDADR),Y
0220 EXIT RTS
Do wywoływania procedur znaków kontrolnych została
wykorzystana możliwość wykonywania skoków pośrednich według
adresu zapisanego w dowolnym miejscu pamięci. Funkcję tą pełni
w tym przypadku rejestr ADRESS, do którego EOUTCH wpisuje
wektor odpowiedniej procedury.
0100 ;Jump SubRoutine INDirect
0110 ;
0120 ADRESS = $64
0130 ;
0140 *= $F2AD
0150 ;
0160 JMP (ADRESS)
Pierwszym rozkazem wykonywanym po wywołaniu JSRIND jest
więc skok do adresu zawartego w rejestrze ADRESS. Teraz zostaną
opisane w kolejności umieszczenia w CNTRLS procedury
poszczególnych znaków kontrolnych.
3.3.3. Znaki kontrolne
Znaki kontrolne są to znaki, które normalnie nie są
wyświetlane na ekranie, lecz powodują wykonanie przez edytor
jakiejś czynności. Umieszczenie znaku kontrolnego na ekranie
(zamiast wykonywania) jest możliwe, gdy znacznik ESCFLG ma
wartość $80 lub znacznik DSPFLG jest różny od zera.
Pierwszym znakiem w tabeli CNTRLS jest właśnie znak Escape
uzyskiwany przez naciśnięcie klawisza ESC. Powoduje on wpisanie
wartości $80 do rejestru ESCFLG, czyli wyświetlenie następnego
znaku nawet wtedy, gdy będzie to znak kontrolny.
0100 ;ESCAPE key
0110 ;
0120 ESCFLG = $02A2
0130 ;
0140 *= $F3E0
0150 ;
0160 LDA #$80
0170 STA ESCFLG
0180 RTS
Naciśnięcie klawiszy CONTROL i - przesuwa kursor o jeden
wiersz w górę (CRSUP), a klawiszy CONTROL i = o jeden w dół
(CRSDWN). Jeżeli przedtem kursor znajdował się na krawędzi
ekranu, to po tej operacji pojawia się na przeciwległej
krawędzi. Procedura CRSUP zmniejsza rejestr pionowej pozycji
kursora (ROWCRS), a gdy wynik jest ujemny, to wpisuje do niego
liczbę wierszy ekranu (BOTSCR) zmniejszoną o jeden. Procedura
CRSDWN zwiększa natomiast ROWCRS oraz porównuje go z BOTSCR i,
gdy kursor znalazł się poza ekranem, to umieszcza go w wierszu
zerowym. Oba warianty kończą się skokiem do procedury STRBEG.
0100 BOTSCR = $02BF
0110 ROWCRS = $54
0120 STRBEG = $F90C
0130 ;
0140 *= $F3E6
0150 ;
0160 ;CuRSor UP
0170 ;
0180 DEC ROWCRS
0190 BPL EXIT
0200 LDX BOTSCR
0210 DEX
0220 STORE STX ROWCRS
0230 EXIT JMP STRBEG
0240 ;
0250 ;CuRSor DoWN
0260 ;
0270 INC ROWCRS
0280 LDA ROWCRS
0290 CMP BOTSCR
0300 BCC EXIT
0310 LDX #$00
0320 BEQ STORE
STRBEG oblicza aktualny wiersz logiczny, w którym znajduje
się kursor, przez wywołanie procedury COMLOG i zapisuje
współrzędne jego początku do rejestru BUFSTR.
0100 ;SToRe BEGin
0110 ;
0120 BUFSTR = $6C
0130 COMLOG = $F88E
0140 HOLD1 = $51
0150 LMARGN = $52
0160 ;
0170 *= $F90C
0180 ;
0190 JSR COMLOG
0200 LDA HOLD1
0210 STA BUFSTR
0220 LDA LMARGN
0230 STA BUFSTR+1
0240 RTS
Naciśnięcie klawiszy CONTROL i + przesuwa kursor o jedno
miejsce w lewo (CRSLFT), a klawiszy CONTROL i * o jedno w prawo
(CRSRGT). Jeżeli przedtem kursor znajdował się na marginesie
ekranu, to po tej operacji pojawia się na przeciwległym
marginesie (niekoniecznie na krawędzi ekranu).
0100 COLCRS = $55
0110 COMLOG = $F88E
0120 LMARGN = $52
0130 RMARGN = $53
0140 ;
0150 *= $F400
0160 ;
0170 ;CuRSor LeFT
0180 ;
0190 DEC COLCRS
0200 LDA COLCRS
0210 BMI CRSRMR
0220 CMP LMARGN
0230 BCS EXIT
0240 ;
0250 ;CuRSor to Right MaRgin
0260 ;
0270 CRSRMR LDA RMARGN
0280 STORE STA COLCRS
0290 EXIT JMP COMLOG
0300 ;
0310 ;CuRSor RiGhT
0320 ;
0330 INC COLCRS
0340 LDA COLCRS
0350 CMP RMARGN
0360 BCC EXIT
0370 BEQ EXIT
0380 ;
0390 ;CuRSor to Left MaRgin
0400 ;
0410 CRSLMR LDA LMARGN
0420 JMP STORE
Procedura CRSLFT zmniejsza rejestr poziomej pozycji kursora
(COLCRS) oraz porównuje go z lewym marginesem ekranu (LMARGN).
Gdy wartość marginesu jest większa od pozycji kursora, to jest
on przenoszony na prawy margines. Natomiast CRSRGT zwiększa
COLCRS i umieszcza kursor na lewym marginesie, gdy przekroczy
on prawy (RMARGN). Dodatkowe dwa punkty wejścia do procedury
oznaczają odpowiednio ustawienie kursora na lewym i prawym
marginesie (jest to osiągane przez odpowiednią kombinację
klawiszy w modelu 1200XL). We wszystkich przypadkach procedura
kończy się skokiem do COMLOG.
Kombinacja klawiszy CONTROL-CLEAR lub SHIFT-CLEAR oznacza
czyszczenie ekranu i powoduje wywołanie procedury CLRSCR. Po
odczytaniu adresu pamięci obrazu poprzez PUTMSC wypełnia ona
zerami cały obszar od tego adresu do RAMTOP (dokładnie).
Następnie kasowana jest mapa wierszy logicznych przez nadanie
czterem bajtom LOGMAP wartości $FF.
0100 ;CLeaR SCReen
0110 ;
0120 ADRESS = $64
0130 BUFSTR = $6C
0140 COLCRS = $55
0150 LOGCOL = $63
0160 LOGMAP = $02B2
0170 PUTMSC = $F9A6
0180 RAMTOP = $6A
0190 ROWCRS = $54
0200 SCLED = $F997
0210 ;
0220 *= $F420
0230 ;
0240 JSR PUTMSC
0250 LDY ADRESS
0260 LDA #$00
0270 STA ADRESS
0280 LOOP STA (ADRESS),Y
0290 INY
0300 BNE LOOP
0310 INC ADRESS+1
0320 LDX ADRESS+1
0330 CPX RAMTOP
0340 BCC LOOP
0350 LDA #$FF
0360 NEXT STA LOGMAP,Y
0370 INY
0380 CPY #$04
0390 BCC NEXT
0400 ;
0410 ;CuRSor HOMe
0420 ;
0430 JSR SCLED
0440 STA LOGCOL
0450 STA BUFSTR+1
0460 LDA #$00
0470 STA ROWCRS
0480 STA COLCRS+1
0490 STA BUFSTR
0500 RTS
Procedura CLRSCR nie kończy się przez RTS, lecz przechodzi
bezpośrednio do procedury CRSHOM, która powoduje umieszczenie
kursora w lewym, górnym rogu ekranu.
Procedura CRSBS jest wywoływana po naciśnięciu klawisza
Back Space. Jeżeli kursor znajduje się na pierwszym miejscu
wiersza logicznego, to procedura jest przerywana skokiem do
COMLOG. Jeśli jest to lewy margines, ale nie początek wiersza
logicznego, to najniższa linia wiersza jest kasowana przez
procedurę DELEML.
0100 ;CuRSor BackSpace
0110 ;
0120 ATACHR = $02FB
0130 COLCRS = $55
0140 COMLOG = $F88E
0150 CRSLFT = $F400
0160 CRSUP = $F3E6
0170 DELEML = $F923
0180 LMARGN = $52
0190 LOGCOL = $63
0200 OUTPLT = $F1CA
0210 RMARGN = $53
0220 ROWCRS = $54
0230 ;
0240 *= $F450
0250 ;
0260 LDA LOGCOL
0270 CMP LMARGN
0280 BEQ EXIT
0290 LDA COLCRS
0300 CMP LMARGN
0310 BNE LFT
0320 JSR DELEML
0330 LFT JSR CRSLFT
0340 LDA COLCRS
0350 CMP RMARGN
0360 BNE SPC
0370 LDA ROWCRS
0380 BEQ SPC
0390 JSR CRSUP
0400 SPC LDA #$20
0410 STA ATACHR
0420 JSR OUTPLT
0430 EXIT JMP COMLOG
Następnie wywoływana jest procedura CRSLFT, a gdy
przeniesie ona kursor na prawy margines, to przez wywołanie
CRSUP kursor przesuwany jest o jedną linię do góry. Na końcu w
miejscu, w którym poprzednio znajdował się kursor umieszczona
jest spacja (przez OUTPLT).
Procedura CRSTAB realizująca naciśnięcie klawisza TAB
wywołuje w pętli procedurę CRSRGT. Pętla jest przerywana po
ustawieniu kursora na lewym marginesie lub po natrafieniu na
ustawiony bit w mapie tabulacji (jest to sprawdzane przez
procedurę BITGET). W pierwszym przypadku sprawdzany jest
jeszcze poprzez RETURN i LOGGET początek nowego wiersza
logicznego. Gdy kursor nie znajduje się na początku wiersza, to
pętla jest kontynuowana. W przeciwnym razie oraz w drugim
przypadku przerwania pętli następuje skok do COMLOG.
0100 ;CuRSor TABulate
0110 ;
0120 BITGET = $F75D
0130 COLCRS = $55
0140 COMLOG = $F88E
0150 CRSRGT = $F411
0160 LMARGN = $52
0170 LOGCOL = $63
0180 LOGGET = $F758
0190 RETURN = $F665
0200 ;
0210 *= $F47A
0220 ;
0230 CRSTAB JSR CRSRGT
0240 LDA COLCRS
0250 CMP LMARGN
0260 BNE BGT
0270 JSR RETURN
0280 JSR LOGGET
0290 BCS EXIT
0300 BGT LDA LOGCOL
0310 JSR BITGET
0320 BCC CRSTAB
0330 EXIT JMP COMLOG
Procedura DELLIN jest wywoływana przez naciśnięcie klawiszy
SHIFT i DELETE. Usuwa ona z ekranu wiersz logiczny, w którym
aktualnie znajduje się kursor. W tym celu wiersz jest
przeliczany i kasowana jest odpowiednia liczba linii
fizycznych. Procedura DELLIN kończy się skokiem do CRSLMR.
0100 ;DELete LINe
0110 ;
0120 BITPUT = $F73C
0130 COLCRS = $55
0140 COMADR = $F82A
0150 COMLOG = $F88E
0160 CONVRT = $F5AC
0170 CRSLMR = $F41B
0180 HOLD1 = $51
0190 LGET3 = $F75B
0200 LOGGET = $F758
0210 LOGMAP = $02B2
0220 ROWCRS = $54
0230 ;
0240 *= $F520
0250 ;
0260 JSR COMLOG
0270 LDY HOLD1
0280 STY ROWCRS
0290 DELROW LDY ROWCRS
0300 NEXT TYA
0310 SEC
0320 JSR LGET3
0330 PHP
0340 TYA
0350 CLC
0360 ADC #$78
0370 PLP
0380 JSR BITPUT
0390 INY
0400 CPY #$18
0410 BNE NEXT
0420 LDA LOGMAP+2
0430 ORA #$01
0440 STA LOGMAP+2
0450 LDA #$00
0460 STA COLCRS
0470 JSR CONVRT
0480 JSR COMADR
0490 JSR LOGGET
0500 BCC DELROW
0510 JMP CRSLMR
Do dokonania zmian w mapie tabulacji TABMAP wykorzystywana
jest procedura BITPUT. Po zamianie znaku na wzór bitowy przez
BITCON umieszcza ona określony bit w rejestrze TABMAP.
0100 ;BIT PUT
0110 ;
0120 BITCLR = $F74A
0130 BITCON = $F723
0140 BITMSK = $6E
0150 TABMAP = $02A3
0160 ;
0170 *= $F73C
0180 ;
0190 BCC BITCLR
0200 BITPT2 JSR BITCON
0210 LDA TABMAP,X
0220 ORA BITMSK
0230 STA TABMAP,X
0240 RTS
Jeżeli przed rozpoczęciem procedury BITPUT zostanie
skasowany bit Carry, to zamiast ustawiania bitu jest on
kasowany przez procedurę BITCLR. Przebieg obu procedur jest
podobny, z tą różnicą, że jedna dodaje bit do maski tabulacji,
a druga odejmuje.
0100 ;BIT CLeaR
0110 ;
0120 BITCON = $F723
0130 BITMSK = $6E
0140 TABMAP = $02A3
0150 ;
0160 *= $F74A
0170 ;
0180 JSR BITCON
0190 LDA BITMSK
0200 EOR #$FF
0210 AND TABMAP,X
0220 STA TABMAP,X
0230 RTS
Procedura INSLIN dokonuje operacji odwrotnej do DELLIN -
wstawia wiersz logiczny na aktualnej pozycji kursora (klawisze
SHIFT i INSERT). Przeprowadzane jest to prawie wyłącznie przez
wywołania innych procedur.
0100 ;INSert LINe
0110 ;
0120 CLRLIN = $F7E2
0130 COLCRS = $55
0140 COMLOG = $F88E
0150 CONVRT = $F5AC
0160 EXTEND = $F7C2
0170 LININS = $F78E
0180 LMARGN = $52
0190 ;
0200 *= $F50C
0210 ;
0220 SEC
0230 INSLN2 JSR EXTEND
0240 LDA LMARGN
0250 STA COLCRS
0260 JSR CONVRT
0270 JSR LININS
0280 JSR CLRLIN
0290 JMP COMLOG
Najpierw wywoływana jest procedura EXTEND, która dokonuje
zmian w mapie tabulacji (przez BITPUT) i mapie wierszy
logicznych (przez LOGGET).
0100 ;EXTEND logical line
0110 ;
0120 BITPUT = $F73C
0130 LGET2 = $F75A
0140 ROWCRS = $54
0150 ;
0160 *= $F7C2
0170 ;
0180 PHP
0190 LDY #$16
0200 LOOP TYA
0210 JSR LGET2
0220 PHP
0230 TYA
0240 CLC
0250 ADC #$79
0260 PLP
0270 JSR BITPUT
0280 DEY
0290 BMI EXIT
0300 CPY ROWCRS
0310 BCS LOOP
0320 EXIT LDA ROWCRS
0330 CLC
0340 ADC #$78
0350 PLP
0360 JMP BITPUT
Następnie procedura LININS przesuwa zawartość pamięci
obrazu o jeden wiersz, tworząc na pozycji kursora miejsce na
nową linię.
0100 ;LINe INSert
0110 ;
0120 BOTSCR = $02BF
0130 MLTTMP = $66
0140 RAMTOP = $6A
0150 ROWCRS = $54
0160 SAVADR = $68
0170 ;
0180 *= $F78D
0190 ;
0200 EXIT RTS
0210 LININS LDX RAMTOP
0220 DEX
0230 STX SAVADR+1
0240 STX MLTTMP+1
0250 LDA #$B0
0260 STA SAVADR
0270 LDA #$D8
0280 STA MLTTMP
0290 LDX ROWCRS
0300 LOOP INX
0310 CPX BOTSCR
0320 BEQ EXIT
0330 LDY #$27
0340 NXT2 LDA (SAVADR),Y
0350 STA (MLTTMP),Y
0360 DEY
0370 BPL NXT2
0380 SEC
0390 LDA SAVADR
0400 STA MLTTMP
0410 SBC #$28
0420 STA SAVADR
0430 LDA SAVADR+1
0440 STA MLTTMP+1
0450 SBC #$00
0460 STA SAVADR+1
0470 JMP LOOP
Na zakończenie procedura CLRLIN wypełnia nowoutworzoną
linię zerami. Ponieważ zerowanie jest wykonywane od lewego do
prawego marginesu, to na ekranie pozostaną znaki znajdujące się
poza marginesami.
0100 ;CLeaR LINe
0110 ;
0120 ADRESS = $64
0130 COLCRS = $55
0140 CONVRT = $F5AC
0150 LMARGN = $52
0160 RMARGN = $53
0170 ;
0180 *= $F7E2
0190 ;
0200 LDA LMARGN
0210 STA COLCRS
0220 JSR CONVRT
0230 SEC
0240 LDA RMARGN
0250 SBC LMARGN
0260 TAY
0270 LDA #$00
0280 NEXT STA (ADRESS),Y
0290 DEY
0300 BPL NEXT
0310 RTS
Procedura CRSCTB obsługuje kombinację klawiszy CONTROL i
TAB. Powoduje ona skasowanie punktu tabulacji na aktualnej
pozycji kursora.
0100 ;CuRSor Clear TaBulate
0110 ;
0120 BITCLR = $F74A
0130 LOGCOL = $63
0140 ;
0150 *= $F49A
0160 ;
0170 LDA LOGCOL
0180 JMP BITCLR
Operacja odwrotna - ustawienie tabulacji na pozycji kursora
(klawisze SHIFT i TAB) jest wykonywana przez procedurę CRSSTB.
0100 ;CuRSor Set TaBulate
0110 ;
0120 BITPT2 = $F73E
0130 LOGCOL = $63
0140 ;
0150 *= $F495
0160 ;
0170 LDA LOGCOL
0180 JMP BITPT2
Kombinacja klawiszy CONTROL-2 powoduje wywołanie procedury
BELL. Jest ona także wywoływana dla zasygnalizowania końca
wiersza logicznego. Przez wywołanie 32 razy procedury KEYCLK
uzyskiwany jest tu dźwięk brzęczyka.
0100 ;BELL
0110 ;
0120 KEYCLK = $F983
0130 ;
0140 *= $F556
0150 ;
0160 LDY #$20
0170 LOOP JSR KEYCLK
0180 DEY
0190 BPL LOOP
0200 RTS
Procedura DELCHR usuwa znak znajdujący się pod kursorem i
przesuwa o jedno miejsce w lewo wszystkie znaki z prawej strony
kursora w danym wierszu logicznym. W miejscu ostatniego znaku
wstawiana jest przez procedurę GETPLT wartość zero. Na czas
wykonywania tych operacji pozycja kursora jest zapamiętywana
poprzez wywołanie PHACRS i potem odtwarzana przez PLACRS.
0100 ;DELete CHaRacter
0110 ;
0120 ADRESS = $64
0130 BOTSCR = $02BF
0140 CONVRT = $F5AC
0150 COMLOG = $F88E
0160 DELTIE = $F918
0170 GETPLT = $F18F
0180 INCRSB = $F60A
0190 LOGCOL = $63
0200 PHACRS = $F94C
0210 PLACRS = $F957
0220 ROWCRS = $54
0230 SAVADR = $68
0240 ;
0250 *= $F4D5
0260 ;
0270 JSR PHACRS
0280 LOOP JSR CONVRT
0290 LDA ADRESS
0300 STA SAVADR
0310 LDA ADRESS+1
0320 STA SAVADR+1
0330 LDA LOGCOL
0340 PHA
0350 JSR INCRSB
0360 PLA
0370 CMP LOGCOL
0380 BCS EXIT
0390 LDA ROWCRS
0400 CMP BOTSCR
0410 BCS EXIT
0420 JSR GETPLT
0430 LDY #$00
0440 STA (SAVADR),Y
0450 BEQ LOOP
0460 EXIT LDY #$00
0470 TYA
0480 STA (SAVADR),Y
0490 JSR DELTIE
0500 JSR PLACRS
0510 JMP COMLOG
Ponieważ przesunięcie znaków w lewo może spowodować
opróżnienie ostatniej linii wiersza logicznego, to wywoływana
jest procedura DELTIE, która sprawdza ten przypadek. Jeżeli
ostatnia linia jest pusta, to zostaje skasowana i procedura
kończy się skokiem do DELROW. W przeciwnym wypadku po RTS
następuje powrót do DELCHR. Procedura ta jest także
wykorzystywana przez CRSBS, lecz od etykiety DELEML.
0100 ;DELeTe If Empty
0110 ;
0120 ADRESS = $64
0130 COMLOG = $F88E
0140 CONVRT = $F5AC
0150 DELROW = $F527
0160 LMARGN = $52
0170 LOGCOL = $63
0180 RMARGN = $53
0190 ROWCRS = $54
0200 ;
0210 *= $F917
0220 ;
0230 EXIT RTS
0240 DELTIE LDA LOGCOL
0250 CMP LMARGN
0260 BNE BPS
0270 DEC ROWCRS
0280 BPS JSR COMLOG
0290 ;
0300 ;DELete EMpty Line
0310 ;
0320 DELEML LDA LOGCOL
0330 CMP LMARGN
0340 BEQ EXIT
0350 JSR CONVRT
0360 LDA RMARGN
0370 SEC
0380 SBC LMARGN
0390 TAY
0400 LOOP LDA (ADRESS),Y
0410 BNE EXIT
0420 DEY
0430 BPL LOOP
0440 JMP DELROW
Odwrotną operację - wstawienia znaku na pozycji kursora i
przesunięcia pozostałych znaków o jedno miejsce w prawo -
wykonuje procedura INSCHR. Jest to uzyskiwane przez naciśnięcie
klawiszy CONTROL i INSERT.
0100 ;INSert CHaRacter
0110 ;
0120 COMLOG = $F88E
0130 DISPLY = $F1E9
0140 GETPLT = $F18F
0150 INSDAT = $7D
0160 LOGCOL = $63
0170 PHACRS = $F94C
0180 PLACRS = $F957
0190 ROWCRS = $54
0200 SCRFLG = $02BB
0210 SCRIBT = $F612
0220 ;
0230 *= $F49F
0240 ;
0250 JSR PHACRS
0260 JSR GETPLT
0270 STA INSDAT
0280 LDA #$00
0290 STA SCRFLG
0300 LOOP JSR DISPLY
0310 LDA LOGCOL
0320 PHA
0330 JSR SCRIBT
0340 PLA
0350 CMP LOGCOL
0360 BCS FND
0370 LDA INSDAT
0380 PHA
0390 JSR GETPLT
0400 STA INSDAT
0410 PLA
0420 JMP LOOP
0430 FND JSR PLACRS
0440 NEXT DEC SCRFLG
0450 BMI EXIT
0460 DEC ROWCRS
0470 BNE EXIT
0480 EXIT JMP COMLOG
System operacyjny zawiera jeszcze jedną procedurę - BTMLIN,
której nie odpowiada żaden znak kontrolny. Jedynie w modelu
1200XL wywołuje ją kombinacja SHIFT-F2. Składa się ona tylko z
wywołania CRSHOM i skoku do CRSUP.
0100 ;BoTtoM LINe
0110 ;
0120 CRSHOM = $F440
0130 CRSUP = $F3E6
0140 ;
0150 *= $F55F
0160 ;
0170 JSR CRSHOM
0180 JMP CRSUP
3.3.4. Odczyt z edytora
Odczyt znaku z edytora jest przeprowadzany przez procedurę
EGETCH. Oczywiście na początku przełącza ona kursor przez
wywołanie SWAP i sprawdza jego pozycję poprzez ERANGE.
Następnie sprawdzany jest licznik bufora BUFCNT (BUFfer
CouNTer). Jeśli jest on różny od zera, to wykonywany jest skok
do końcowej fazy procedury.
W przeciwnym razie do rejestru wskazującego początek bufora
(BUFSTR) przepisywane są wartości z ROWCRS i COLCRS. Teraz
rozpoczyna się pętla odczytu z klawiatury. Po wywołaniu
procedury KBGBYT zwrócony przez nią status operacji jest
zapisywany do DSTAT, a odczytany znak jest porównymany z $9B
(kod RETURN). Wykrycie znaku RETURN przerywa pętlę odczytu.
Każdy inny znak powoduje kolejno wywołanie procedur PRCCHR i
SWAP. Jeżeli został przy tym przekroczony 114 znak wiersza
logicznego, to wywoływana jest procedura BELL w celu
wygenerowania sygnału ostrzegawczego. Dalej pętla odczytu jest
powtarzana.
Po przerwaniu odczytu przez znak RETURN, kursor wyłączany
jest procedurą OFFCRS i wywoływana jest procedura DOBUFC. Po
obliczeniu przez nią chwilowej długości bufora bajty BUFSTR są
przepisywane ponownie do ROWCRS i COLCRS. Następnie długość
bufora jest zmniejszana i jeśli status (w DSTAT) jest mniejszy
od $80, to po wywołaniu GETCH i zapisaniu odczytanego znaku do
rejestru ATACHR procedura kończy się skokiem do SWAP. Przy
statusie większym od $7F długość bufora jest zmniejszana do
zera.
Zerowa długość bufora powoduje wywołanie procedury RTWSCR i
zapisanie do rejestru ATACHR znaku RETURN ($9B). Następnie
wywoływana jest procedura RETURM i, po zapisaniu uzyskanego
przez nią statusu do DSTAT, wykonywany jest skok do procedury
SWAP.
0100 ;Editor GET CHaracter
0110 ;
0120 ADRESS = $64
0130 ATACHR = $02FB
0140 BELL = $F556
0150 BUFCNT = $6B
0160 BUFSTR = $6C
0170 COLCRS = $55
0180 DOBUFC = $F8B1
0190 DSTAT = $4C
0200 ERANGE = $F6BC
0210 GETCH = $F180
0220 KBGBYT = $F2FD
0230 LOGCOL = $63
0240 OFFCRS = $F718
0250 PRCCHR = $F2BE
0260 RETURM = $F20B
0270 ROWCRS = $54
0280 RTWSCR = $F661
0290 SWAP = $F962
0300 ;
0310 *= $F24A
0320 ;
0330 JSR SWAP
0340 JSR ERANGE
0350 LDA BUFCNT
0360 BNE CBF
0370 LDA ROWCRS
0380 STA BUFSTR
0390 LDA COLCRS
0400 STA BUFSTR+1
0410 GET JSR KBGBYT
0420 STY DSTAT
0430 LDA ATACHR
0440 CMP #$9B
0450 BEQ EOL
0460 JSR PRCCHR
0470 JSR SWAP
0480 LDA LOGCOL
0490 CMP #$71
0500 BNE BPS
0510 JSR BELL
0520 BPS JMP GET
0530 EOL JSR OFFCRS
0540 JSR DOBUFC
0550 LDA BUFSTR
0560 STA ROWCRS
0570 LDA BUFSTR+1
0580 STA COLCRS
0590 CBF LDA BUFCNT
0600 BEQ RET
0610 NXT DEC BUFCNT
0620 BEQ RET
0630 LDA DSTAT
0640 BMI NXT
0650 JSR GETCH
0660 STA ATACHR
0670 JMP SWAP
0680 RET JSR RTWSCR
0690 LDA #$9B
0700 STA ATACHR
0710 JSR RETURM
0720 STY DSTAT
0730 JMP SWAP
Wywoływana przez EGETCH procedura DOBUFC służy do
obliczenia chwilowej długości aktualnego bufora edytora, a więc
wiersza, w którym znajduje się kursor. W tym celu najpierw
przez procedurę PHACRS zapamiętywana jest pozycja kursora, a
zawartość rejestru LOGCOL jest odkładana na stos. Następnie do
rejestrów ROWCRS i COLCRS przepisywana jest zawartość BUFSTR,
licznik bufora BUFCNT otrzymuje wartość 1 i rozpoczyna się
pętla obliczająca.
Do rejestru X wpisywany jest maksymalny numer wiersza - 23
dla całego ekranu lub 3 dla okna tekstowego. Jeżeli kursor
znajduje się na prawym marginesie ostatniej linii, to licznik
jest zwiększany o jeden i pętla jest opuszczana. W przeciwnym
razie licznik jest zwiększany dopiero po wywołaniu procedury
INCRSB. Jeśli teraz adres kursora w wierszu logicznym jest
różny od lewego marginesu, to następuje powtórzenie pętli.
Jeśli nie, to kursor jest przesuwany na koniec poprzedniej
linii fizycznej i pętla się kończy.
0100 ;DO BUFfer Count
0110 ;
0120 BUFCNT = $6B
0130 BUFSTR = $6C
0140 COLCRS = $55
0150 CRSLFT = $F400
0160 GETPLT = $F18F
0170 INCRSB = $F60A
0180 LMARGN = $52
0190 LOGCOL = $63
0200 PHACRS = $F94C
0210 PLACRS = $F957
0220 RMARGN = $53
0230 ROWCRS = $54
0240 SWPFLG = $7B
0250 ;
0260 *= $F8B1
0270 ;
0280 JSR PHACRS
0290 LDA LOGCOL
0300 PHA
0310 LDA BUFSTR
0320 STA ROWCRS
0330 LDA BUFSTR+1
0340 STA COLCRS
0350 LDA #$01
0360 STA BUFCNT
0370 LOOP LDX #$17
0380 LDA SWPFLG
0390 BPL ROW
0400 LDX #$03
0410 ROW CPX ROWCRS
0420 BNE ISB
0430 LDA COLCRS
0440 CMP RMARGN
0450 BNE ISB
0460 INC BUFCNT
0470 JMP GET
0480 ISB JSR INCRSB
0490 INC BUFCNT
0500 LDA LOGCOL
0510 CMP LMARGN
0520 BNE LOOP
0530 DEC ROWCRS
0540 JSR CRSLFT
0550 GET JSR GETPLT
0560 BNE EXIT
0570 DEC BUFCNT
0580 LDA LOGCOL
0590 CMP LMARGN
0600 BEQ EXIT
0610 JSR CRSLFT
0620 LDA COLCRS
0630 CMP RMARGN
0640 BNE LBC
0650 DEC ROWCRS
0660 LBC LDA BUFCNT
0670 BNE GET
0680 EXIT PLA
0690 STA LOGCOL
0700 JMP PLACRS
Teraz rozpoczyna się druga pętla, w której wywoływana jest
procedura GETPLT i zmniejsza się stan licznika. Jest ona
przerywana po znalezieniu znaku innego niż spacja, po
osiągnięciu początku wiersza logicznego lub po wyzerowaniu
licznika. Procedura DOBUFC kończy się odtworzeniem ze stosu
wartości LOGCOL i skokiem do PLACRS dla odtworzenia pozycji
kursora.
3.4. Procedury obsługi drukarki
Drukarka jest urządzeniem wyjścia, z którym komunikacja
odbywa się przez złącze szeregowe komputera, a więc za
pośrednictwem procedur SIO. Tabela adresowa PRTVEC zawiera
następujące wektory procedur obsługi:
OPEN - PROPN
CLOSE - PRCLS
GET - PRRDSP
PUT - PRWRT
STATUS - PRSTAT
SPECIAL - PRRDSP
Kolejność opisu przyjęta dla tych procedur odbiega zarówno
od porządku powyższej listy, jak i od kolejności ich
wykorzystywania. Umożliwia to jednak łatwiejsze ich zrozumienie
i upraszcza analizę.
3.4.1. Zapis na drukarkę
Podstawową czynnością wykonywaną na drukarce jest zapis
danych. Procedura CIO wywołuje do przeprowadzenia tej operacji
procedurę PRWRT.
Na początku, po umieszczeniu na stosie znaku do zapisania,
odtwarzany jest numer urządzenia z odpowiedniego rejestru
ICDNO. Następnie wywoływana jest procedura PRMODE ustalająca
tryb pracy drukarki. Teraz zawartość licznika PBPNT (PRinter
Buffer PoiNTer) przepisywana jest do rejestru X i według niej
odtworzony ze stosu znak jest umieszczany w buforze drukarki
PRNBUF (PRiNter BUFfer). Po zwiększeniu licznika jest on
porównywany z zapisaną w rejestrze PBUFSZ (Printer BUFfer SiZe)
długością bufora.
Gdy bufor nie został jeszcze zapełniony, to sprawdzany jest
kod zapisywanego znaku. Jeśli nie jest to RETURN ($9B), to po
wpisaniu do rejestru Y wartości 1 (SUCCESS) procedura się
kończy rozkazem RTS. Znak RETURN powoduje natomiast wypełnienie
całej pozostałej części bufora znakiem spacji.
Po zapełnieniu bufora licznik PBPNT jest zerowany, a do
rejestrów X i Y wpisywany jest odpowiednio młodszy i starszy
bajt adresu bufora. Adres ten jest oznaczony etykietą PRCHAR i
zapisany w pamięci ROM. Z tego powodu przeniesienie bufora
drukarki jest możliwe tylko po zmianie procedury PRWRT. Teraz
procedura kończy się wywołaniem SETDCB, która ustala parametry
dla operacji SIO i skokiem do głównej procedury SIO poprzez
JSIOINT.
0100 ;PRinter WRiTe
0110 ;
0120 ICDNO = $0341
0130 ICDNOZ = $21
0140 JSIOINT = $E459
0150 PBPNT = $02DE
0160 PBUFSZ = $02DF
0170 PRMODE = $FF4B
0180 PRNBUF = $03C0
0190 SETDCB = $FF14
0200 ;
0210 *= $FEA1
0220 ;
0230 PRCHAR .WORD PRNBUF
0240 ;
0250 *= $FECB
0260 ;
0270 PRWRT PHA
0280 LDA ICDNO,X
0290 STA ICDNOZ
0300 JSR PRMODE
0310 LDX PBPNT
0320 PLA
0330 STA PRNBUF,X
0340 INX
0350 CPX PBUFSZ
0360 BEQ PPPUT
0370 STX PBPNT
0380 CMP #$9B
0390 BEQ SPC
0400 LDY #$01
0410 RTS
0420 SPC LDA #$20
0430 ;
0440 ;Fill Printer BUFfre
0450 ;
0460 FPBUF STA PRNBUF,X
0470 INX
0480 CPX PBUFSZ
0490 BNE FPBUF
0500 PPPUT LDA #$00
0510 STA PBPNT
0520 LDX PRCHAR
0530 LDY PRCHAR+1
0540 JSR SETDCB
0550 JMP JSIOINT
Procedura PRMODE służy do ustalenia trybu pracy drukarki i
związanej z nim długości bufora. Najpierw do rejestru Y
wpisywana jest wartość $57, która oznacza rozkaz PUT WITH
VERIFY (zapis z weryfikacją). Następnie odczytywana jest
zawartość rejestru ICAX2 i kolejno porównywana z ustalonymi
wartościami. Gdy jest ona równa $4E (78), to do rejestru X
wpisywane jest $28. Gdy jest równa $44 (68), to rejestr X
otrzymuje wartość $14, a gdy $53 (83), to wartość $1D. Jeśli
zawartość ICAX2 nie odpowiada żadnej z wymienionych liczb, to
przyjmowana jest wartość $4E.
Teraz zawartość rejestru X zostaje przepisana do PBUFSZ,
rejestru Y do DCMND (Device CoMmaND), a akumulatora do DAUX1
(Device AUXiliary 1) i procedura się kończy.
Wyjaśnienia wymagają jeszcze kontrolowane wartości z
rejestru ICAX2. Określają one rodzaj druku, który ma być
zastosowany przez drukarkę. Wartość $4E oznacza druk normalny
(10 znaków na cal), $44 - druk szeroki (5 znaków na cal), a $53
- druk znakami obróconymi o 90°. Niestety wszystkie te
parametry dotyczą drukarki Atari 1020 i nie są rozpoznawane
przez drukarkę Atari 1029. Jako ciekawostkę można natomiast
dodać, że Atari 1029 reaguje na wywołanie jako urządzenia "P1:"
(lub po prostu "P:") oraz jako "P6:"!
0100 ;PRinter MODE
0110 ;
0120 DAUX1 = $030A
0130 DCMND = $0302
0140 ICAX2Z = $2B
0150 PBUFSZ = $02DF
0160 ;
0170 *= $FF4B
0180 ;
0190 LDY #$57
0200 LDA ICAX2Z
0210 NRM CMP #$4E
0220 BNE WID
0230 LDX #$28
0240 BNE EXIT
0250 WID CMP #$44
0260 BNE SDW
0270 LDX #$14
0280 BNE EXIT
0290 SDW CMP #$53
0300 BNE STN
0310 LDX #$1D
0320 EXIT STX PBUFSZ
0330 STY DCMND
0340 STA DAUX1
0350 RTS
0360 STN LDA #$4E
0370 BNE NRM
Procedury PRWRT i PRSTAT (opisana dalej) wywołują procedurę
SETDCB. Służy ona do ustalenia parametrów w bloku kontroli
urządzeń DCB (Device Control Block). Jest to konieczne przed
wywołaniem procedury SIO, tak jak przed wywołaniem CIO trzeba
ustawić parametry w IOCB. Dokładny opis bloku DCB oraz
znaczenia poszczególnych jego rejestrów znajduje się w
rozdziale 4.1. (str. 115). Tu zajmiemy się tylko procedurą
SETDCB bez rozpatrywania szczegółowego znaczenia przekazywanych
wartości.
0100 ;SET Device Control Block
0110 ;
0120 DBUFA = $0304
0130 DBYT = $0308
0140 DCMND = $0302
0150 DDEVIC = $0300
0160 DSTATS = $0303
0170 DTIMLO = $0306
0180 DUNIT = $0301
0190 ICDNOZ = $21
0200 PBUFSZ = $02DF
0210 PTIMOT = $0314
0220 ;
0230 *= $FF14
0240 ;
0250 STX DBUFA
0260 STY DBUFA+1
0270 LDA #$40
0280 STA DDEVIC
0290 LDA ICDNOZ
0300 STA DUNIT
0310 LDA #$80
0320 LDX DCMND
0330 CPX #$53
0340 BNE NST
0350 LDA #$40
0360 NST STA DSTATS
0370 LDA PBUFSZ
0380 STA DBYT
0390 LDA #$00
0400 STA DBYT+1
0410 LDA PTIMOT
0420 STA DTIMLO
0430 RTS
Umieszczony przed wywołaniem SETDCB w rejestrach X i Y
adres bufora jest najpierw przepisywany do DBUFA (Device BUFfer
Address). Potem kolejno: w DDEVIC umieszczany jest kod drukarki
($40); w DUNIT - jej numer z ICDNOZ, w DSTATS kod zapisu $80, a
przy żądaniu statusu - kod odczytu $40; w DBYT - długość bufora
z PBUFSZ i w DTIMLO - czas oczekiwania na odpowiedź z PTIMOT.
3.4.2. Odczyt statusu drukarki
Odczyt statusu drukarki jest jedyną operacją, podczas
której komputer otrzymuje dane od drukarki. Status drukarki
jest zawarty w czterech bajtach umieszczanych po odczycie w
rejestrze DVSTAT (DeVice STATus). Wykonywane jest to przez
procedurę PRSTAT. Jest ona w ogólnym zarysie podobna do PRWRT.
Najpierw ustawia na cztery bajty długość bufora i umieszcza w
rejestrach X i Y jego adres (również pobrany z pamięci ROM).
Potem po wpisaniu do DCMND i DAUX1 kodu $53 (odczyt statusu)
wywołuje kolejno procedury SETDCB i SIOINT.
Gdy po zakończeniu procedury SIO sygnalizowany jest błąd,
to PRSTAT się kończy. W przeciwnym razie wywoływana jest
jeszcze procedura PRPUT.
0100 ;PRinter STATus
0110 ;
0120 DAUX1 = $030A
0130 DCMND = $0302
0140 DVSTAT = $03EA
0150 JSIOINT = $E459
0160 PBUFSZ = $02DF
0170 PRPUT = $FF44
0180 SETDCB = $FF14
0190 ;
0200 *= $FE9F
0210 ;
0220 PRSTAD .WORD DVSTAT
0230 ;
0240 *= $FEA3
0250 ;
0260 PRSTAT LDA #$04
0270 STA PBUFSZ
0280 LDX PRSTAD
0290 LDY PRSTAD+1
0300 LDA #$53
0310 STA DCMND
0320 STA DAUX1
0330 JSR SETDCB
0340 JSR JSIOINT
0350 BMI PRRDSP
0360 JSR PRPUT
0370 ;
0380 ;PRinter ReaD/SPecial
0390 ;
0400 PRRDSP RTS
Trzeci bajt odczytanego adresu (DVTMOT - DeVice TiMe OuT)
zawiera rzeczywistą wartość czasu oczekiwania na odpowiedź (dla
konkretnego typu drukarki). Procedura PRPUT przepisuje tą
wartość do rejestru PTIMOT (Printer TIMeOuT) zastępując w nim
wartość ustaloną podczas inicjowania drukarki.
0100 ;PRinter PUT
0110 ;
0120 DVTMOT = $02EC
0130 PTIMOT = $0314
0140 ;
0150 *= $FF44
0160 ;
0170 LDA DVTMOT
0180 STA PTIMOT
0190 RTS
Kończący procedurę odczytu statusu rozkaz RTS jest
oznaczony etykietą PRRDSP. System operacyjny nie przewiduje dla
drukarki operacji odczytu i operacji specjalnych. Wywołanie
którejkolwiek z nich powoduje więc natychmiastowy powrót do
CIO. W rezultacie rejestr Y zawiera kod błędu $92 (zob. opis
procedury GOHAND - str. 24).
3.4.3. Pozostałe procedury drukarki
Nie zostały jeszcze opisane dwie procedury rozpoczynające
(PROPN) i kończące (PRCLS) współpracę komputera z drukarką.
Wykorzystują one wcześniej opisane procedury i z tego powodu
zostały umieszczone na końcu.
Procedura PROPN otwierająca kanał komunikacji z drukarką
wywołuje jedynie procedurę PRSTAT i zeruje licznik bufora
PBPNT. Dzięki temu uaktualniona zostaje wartość Timeout. Warto
zauważyć, że otwarcie drukarki zawsze zeruje jej bufor. Przy
jednoczesnej pracy z dwoma drukarkami (lub drukarką i
plotterem) należy kanały dla obu urządzeń otwierać przed
rozpoczęciem transmisji, gdyż inaczej można utracić część
informacji.
0100 ;PRinter OPeN
0110 ;
0120 PBPNT = $02DE
0130 PRSTAT = $FEA3
0140 ;
0150 *= $FEC2
0160 ;
0170 JSR PRSTAT
0180 LDA #$00
0190 STA PBPNT
0200 RTS
Procedura zamykająca kanał komunikacji z drukarką (PRCLS)
musi zapewniać wydrukowanie wszystkich danych umieszczonych
przedtem w buforze. W tym celu, po wywołaniu PRMODE, w
akumulatorze umieszczany jest kod RETURN i wykonywany jest skok
do procedury FPBUF (jest to część PRWRT). Powoduje to
wypełnienie pustej części bufora znakami RETURN i wysłanie
całej jego zawartości do drukarki. Jeżeli licznik PBPNT
wskazywał pusty bufor, to zamiast skoku do FPBUF w rejestrze Y
umieszczana jest wartość 1 i procedura się kończy.
0100 ;PRinter CLoSe
0110 ;
0120 FPBUF = $FEED
0130 PBPNT = $02DE
0140 PRMODE = $FF4B
0150 ;
0160 *= $FE07
0170 ;
0180 JSR PRMODE
0190 LDA #$9B
0200 LDX PBPNT
0210 BNE FPBUF
0220 LDY #$01
0230 RTS
3.5. Procedury obsługi magnetofonu
Magnetofon jest urządzeniem wejścia i wyjścia służącym jako
pamięć masowa, to znaczy do przechowywania dużej ilości
informacji (programów i danych). Komunikacja z magnetofonem
odbywa się przez złącze szeregowe, a więc także za
pośrednictwem SIO. Tabela adresowa CASVEC zawiera wektory,
które wskazują na następujące procedury:
OPEN - CASOPN
CLOSE - CASCLS
GET - CASRDBT
PUT - CASWRT
STATUS - CASST
SPECIAL - CASSP
Dla magnetofonu nie przewiduje się operacji specjalnych,
Etykietą CASSP jest oznaczony tylko rozkaz RTS w procedurze
CASINIT. W wyniku wywołania tej operacji otrzymamy więc jedynie
kod błędu FUNCTION NOT IMPLEMENTED.
Ponieważ magnetofon nie jest urządzeniem "inteligentnym",
tj. nie posiada własnego układu sterującego (procesora), to
procedury obsługi nie mogą żądać żadnych sygnałów dodatkowych.
System operacyjny zakłada więc, że magnetofon jest stale
dołączony i gotowy do pracy. Z takiego założenia wynika
procedura CASST, która na żądanie statusu zawsze zwraca w
rejestrze Y wartość 1 (SUCCESS).
0100 ;CASsette STatus
0110 ;
0120 *= $FDCC
0130 ;
0140 LDY #$01
0150 RTS
3.5.1. Otwarcie magnetofonu
Przed otwarciem kanału dla magnetofonu należy określić w
rejestrze ICAX1 sposób dostępu ($04 - odczyt, $08 zapis) oraz w
rejestrze ICAX2 rodzaj przerw między rekordami na kasecie ($00
- długie, $80 - krótkie). Następnie po przejściu do CIO
wywoływana jest procedura CASOPN.
Na początku, po przeniesieniu zawartości ICAX2 do rejestru
GAPTYP, sprawdzany jest sposób dostępu. Wartość $04 powoduje
skok do etykiety CASOPIN, $08 - do COPOUT, a każda inna kończy
procedurę przez RTS - wynikiem jest więc błąd FUNCTION NOT
IMPLEMENTED.
Schemat przebiegu obu wariantów procedury jest bardzo
zbliżony. Różnice występują przede wszystkim w wartościach
wpisywanych do rejestrów. Dokładnie będzie więc opisany odczyt
z magnetofonu, a następnie podane zostaną różnice występujące
przy zapisie.
W fazie przygotowawczej ustawiane są na zero znaczniki
WMODE i FEOF. Potem z wartością $01 w akumulatorze wywoływana
jest procedura BPWT, która oczekuje na naciśnięcie klawisza.
Negatywny wynik tej procedury powoduje przerwanie CASOPN.
0100 ;CASsette OPeN
0110 ;
0120 AUDF3 = $D204
0130 AUDF4 = $D206
0140 BLIM = $028A
0150 BPTR = $3D
0160 BPWT = $FDFC
0170 DDEVIC = $0300
0180 FEOF = $3F
0190 GAPTYP = $3E
0200 ICAX1Z = $2A
0210 ICAX2Z = $2B
0220 IRQSTAT = $11
0230 JSETVBV = $E45C
0240 JSNDENB = $E468
0250 PACTL = $D302
0260 PALNTS = $62
0270 TABCAS = $FE8D
0280 TIMFLG3 = $022A
0290 WMODE = $0289
0300 ;
0310 *= $FCE6
0320 ;
0330 LDA ICAX2Z
0340 STA GAPTYP
0350 LDA ICAX1Z
0360 AND #$0C
0370 CMP #$04
0380 BEQ CASOPIN
0390 CMP #$08
0400 BEQ COPOUT
0410 RTS
0420 CASOPIN LDA #$00
0430 STA WMODE
0440 STA FEOF
0450 LDA #$01
0460 JSR BPWT
0470 BMI ER2
0480 LDA #$34
0490 STA PACTL
0500 LDX PALNTS
0510 LDY TABCAS+6,X
0520 LDA TABCAS+4,X
0530 TAX
0540 LDA #$03
0550 STA TIMFLG3
0560 JSR JSETVBV
0570 WAIT LDA TIMFLG3
0580 BNE WAIT
0590 LDA #$80
0600 STA BPTR
0610 STA BLIM
0620 JMP SUC
0630 ERR LDY #$80
0640 DEC IRQSTAT
0650 ER2 LDA #$00
0660 STA WMODE
0670 RTS
0680 COPOUT LDA #$80
0690 STA WMODE
0700 LDA #$02
0710 JSR BPWT
0720 BMI ER2
0730 LDA #$CC
0740 STA AUDF3
0750 LDA #$05
0760 STA AUDF4
0770 LDA #$60
0780 STA DDEVIC
0790 JSR JSNDENB
0800 LDA #$34
0810 STA PACTL
0820 LDX PALNTS
0830 LDY TABCAS+2,X
0840 LDA TABCAS,X
0850 TAX
0860 LDA #$03
0870 JSR JSETVBV
0880 LDA #$FF
0890 STA TIMFLG3
0900 WT2 LDA IRQSTAT
0910 BEQ ERR
0920 LDA TIMFLG3
0930 BNE WT2
0940 LDA #$00
0950 STA BPTR
0960 SUC LDY #$01
0970 RTS
Teraz do rejestru PACTL wpisywana jest wartość $34, która
powoduje uruchomienie silnika magnetofonu. Według znacznika
PALNTS pobierane są z tabeli TABCAS wartości, które po
wywołaniu procedury SETVBLV ustalają stan początkowy licznika
TIMCNT3 (TIMer CouNTer 3).
0100 ;TABle for CASsette
0110 ;
0120 *= $FE8D
0130 ;
0140 .BYTE $04,$03,$80,$C0
0150 .BYTE $02,$01,$40,$E0
0160 .BYTE $1E,$19,$0A,$08
Procedura czeka teraz w pętli WAIT na wyzerowanie tego
licznika sygnalizowane w TIMFLG3 (TIMer FLaG 3). Po upływie
ustalonego czasu oraz ustawieniu długości bufora i jego
licznika na $80 procedura kończy się przez RTS.
Podczas zapisu do rejestru WMODE wpisywana jest wartość
$80, a procedura BPWT jest wywoływana z wartością $02 w
akumulatorze. W tym miejscu występuje największa różnica między
odczytem i zapisem. Do rejestrów AUDF3 i AUDF4 wpisywane są
wartości określające częstotliwość pracy generatorów sygnału.
Rejestr DDEVIC uzyskuje wartość $60, która oznacza magnetofon i
wywoływana jest procedura SNDENBL. Kończąca tą fazę pętla WT2
oprócz znacznika TIMFLG3 sprawdza także rejestr IRQSTAT.
Zadaniem procedury BPWT jest wygenerowanie odpowiedniego
sygnału dźwiękowego i oczekiwanie na naciśnięcie przez
użytkownika dowolnego klawisza (oprócz BREAK). Liczba dźwięków
jest umieszczana w akumulatorze przed wywołaniem procedury.
0100 ;BeeP and WaiT
0110 ;
0120 CONSOL = $D01F
0130 FREQ = $40
0140 PALNTS = $62
0150 PHVRT = $FE36
0160 RTCLOCK = $12
0170 TABCAS = $FE8D
0180 ;
0190 *= $FDFC
0200 ;
0210 STA FREQ
0220 LP1 LDA RTCLOCK+2
0230 CLC
0240 LDX PALNTS
0250 ADC TABCAS+8,Y
0260 TAX
0270 LP2 LDA #$FF
0280 STA CONSOL
0290 LDA #$00
0300 LDY #$F0
0310 WT1 DEY
0320 BNE WT1
0330 STA CONSOL
0340 LDY #$F0
0350 WT2 DEY
0360 BNE WT2
0370 CPX RTCLOCK+2
0380 BNE LP2
0390 DEC FREQ
0400 BEQ KEY
0410 TXA
0420 CLC
0430 LDX PALNTS
0440 ADC TABCAS+10,X
0450 TAX
0460 WT3 CPX RTCLOCK+2
0470 BNE WT3
0480 BEQ LP1
0490 KEY JSR PHVRT
0500 TYA
0510 RTS
Dźwięk jest uzyskiwany przez naprzemienne wpisywanie do
rejestru CONSOL wartości $00 i $FF, a czas jego trwania
określany jest według zegara RTCLOCK (Real Time CLOCK) na
podstawie wartości odczytanych z TABCAS. Po emisji dźwięku
(jednego lub dwóch sygnałów - zależnie od zawartości FREQ)
wywoływana jest procedura PHVRT, a po jej zakończeniu kończy
się także BPWT.
0100 ;PusH Vector & ReTurn
0110 ;
0120 KBDVEC = $E420
0130 ;
0140 *= $FE36
0150 ;
0160 LDA KBDVEC+5
0170 PHA
0180 LDA KBDVEC+4
0190 PHA
0200 RTS
Działanie procedury PHVRT jest identyczne jak opisywanej
wcześniej procedury GOHAND. Odczytuje ona z tabeli adresowej
KBDVEC wektor odczytu z klawiatury i umieszcza go na stosie.
Teraz po rozkazie RTS jest wykonywana ta procedura, a po jej
zakończeniu następuje powrót bezpośrednio do BPWT.
Przez CASOPN wywoływana jest jeszcze procedura SNDENBL.
Stanowi ona część SIO (szeregowego wejścia/wyjścia - Serial
Input/Output) i jest opisana razem z nim w rozdziale 4.
3.5.2. Odczyt z magnetofonu
Dla dokonania odczytu z magnetofonu wywoływana jest
procedura CASRDBT. Sprawdza ona najpierw znacznik FEOF (Flag
End Of File) i gdy jest on ustawiony ($80), to procedura jest
przerywana po umieszczeniu w rejestrze Y kodu błędu $88 (END OF
FILE - koniec zbioru).
Jeżeli licznik bufora BPTR (Buffer PoinTeR) jest różny od
jego długości BLIM (Buffer LIMit), oznacza to odczyt bajtu. Do
akumulatora pobierany jest więc z bufora magnetofonu bajt
wskazany przez BPTR. Po zwiększeniu BPTR i wpisaniu 1 do
rejestru Y procedura się kończy.
Równe wartości BPTR i BLIM oznaczają odczyt całego bloku
(rekordu). Następuje wtedy skok do drugiej części procedury
oznaczonej etykietą CASRDBL. Tam, po zapisaniu w akumulatorze
wartości $52 (kod rozkazu GET RECORD), wywoływana jest
procedura SYSBUF, która przygotowuje blok DCB do współpracy z
magnetofonem i przeprowadza odczyt rekordu.
0100 ;CASsette ReaD
0110 ;
0120 BLIM = $028A
0130 BPTR = $3D
0140 CASBEN = $047F
0150 CASBUF = $0400
0160 CRCB = $03FF
0170 FEOF = $3F
0180 SYSBUF = $FE3F
0190 ;
0200 *= $FD7A
0210 ;
0220 ;CASsette ReaD ByTe
0230 ;
0240 CASRDBT LDA FEOF
0250 BMI ERR
0260 LDX BPTR
0270 CPX BLIM
0280 BEQ CASRDBL
0290 LDA CASBUF,X
0300 INC BPTR
0310 LDY #$01
0320 EXIT RTS
0330 ;
0340 ;CASsette ReaD BLock
0350 ;
0360 CASRDBL LDA #$52
0370 JSR SYSBUF
0380 TYA
0390 BMI EXIT
0400 LDA #$00
0410 STA BPTR
0420 LDX #$80
0430 LDA CRCB
0440 CMP #$FE
0450 BEQ EOF
0460 CMP #$FA
0470 BNE LIM
0480 LDX CASBEN
0490 LIM STX BLIM
0500 JMP CASRDBT
0510 EOF DEC FEOF
0520 ERR LDY #$88
0530 RTS
Odczytany z magnetofonu rekord jest umieszczany w
akumulatorze i według rejestru CRCB (Cassette Record Control
Byte) jest sprawdzany jego rodzaj. Wartość $FE oznacza rekord
końcowy zbioru i powoduje przerwanie procedury odczytu. Wartość
$FA oznacza niepełny rekord. Wtedy liczba bajtów w buforze jest
przenoszona z rejestru CASBEN (CAssette Buffer ENd) do rejestru
długości bufora BLIM i wykonywany jest skok do CASRDBT. Trzecią
wartością, która może wystąpić w rejestrze CRCB (lecz nie jest
sprawdzana), jest $FC. Oznacza ona pełny rekord (128 bajtów) i
powoduje jedynie skok do CASRDBT.
Procedura SYSBUF wywoływana przez CASRDBT i CASWRT pełni
dla magnetofonu taką rolę, jak SETDCB dla drukarki. Ustawia ona
odpowiednie wartości w bloku DCB i wywołuje procedurę SIOINT.
Przed rozpoczęciem SYSBUF do akumulatora musi być wpisany kod
wykonywanej operacji (zapisu lub odczytu).
Po przepisaniu kodu rozkazu z akumulatora do rejestru DCMND
kolejno ustalane są pozostałe wartości DCB: długość bufora DBYT
($83), adres bufora DBUFA (adres pierwszego bajtu zapisywanego
rekordu - CSCB), rodzaj urządzenia DDEVIC ($60), numer
urządzenia DUNIT ($00) i wartość Timeout DTIMLO ($23). Rejestr
DSTATS otrzymuje przy odczycie wartość $40, a przy zapisie -
$80. Na końcu jeszcze zawartość GAPTYP jest przepisywana do
DAUX2 i wywoływana jest procedura SIOINT.
0100 ;SYStem BUFfer
0110 ;
0120 CSCB = $03FD
0130 DAUX2 = $030B
0140 DBUFA = $0304
0150 DBYT = $0308
0160 DCMND = $0302
0170 DDEVIC = $0300
0180 DSTATS = $0303
0190 DTIMLO = $0306
0200 DUNIT = $0301
0210 GAPTYP = $3E
0220 JSIOINT = $E459
0230 ;
0240 *= $FE3F
0250 ;
0260 STA DCMND
0270 LDA #$00
0280 STA DBYT+1
0290 LDA #$83
0300 STA DBYT
0310 LDA # >CSCB
0320 STA DBUFA+1
0330 LDA # <SCSB
0340 STA DBUFA
0350 LDA #$60
0360 STA DDEVIC
0370 LDA #$00
0380 STA DUNIT
0390 LDA #$23
0400 STA DTIMLO
0410 LDA DCMND
0420 LDY #$40
0430 CMP #$52
0440 BEQ STS
0450 LDY #$80
0460 STS STY DSTATS
0470 LDA GAPTYP
0480 STA DAUX2
0490 JSR JSIOINT
0500 RTS
Szczegółowe informacje o DCB znajdują się w rozdziale 4.1.
- Blok kontroli urządzeń (str. 115).
3.5.3. Zapis na magnetofon
Procedura zapisu CASWRT jest znacznie krótsza od procedury
odczytu z magnetofonu. Wynika to przede wszystkim z "głupoty"
magnetofonu. Po prostu komputer nie może kontrolować przebiegu
transmisji i wysyła dane "w ciemno". Oczywiście znakomicie
upraszcza to procedurę transmisji.
Jak we wszystkich procedurach zapisu, także przed
wywołaniem CASWRT w akumulatorze musi być umieszczony
zapisywany znak. Jest on przepisywany do bufora magnetofonu
CASBUF (CASsette BUFfer) w miejsce wskazane przez licznik BPTR.
Jeżeli licznik nie osiągnął jeszcze wartości $7F, to po
ustawieniu statusu $01 (SUCCESS) procedura się kończy.
0100 ;CASsette WRiTe
0110 ;
0120 BPTR = $3D
0130 CASBUF = $0400
0140 WSIOSB = $FE7C
0150 ;
0160 *= $FDB4
0170 ;
0180 LDX BPTR
0190 STA CASBUF,X
0200 INC BPTR
0210 LDY #$01
0220 CPX #$7F
0230 BEQ FIN
0240 RTS
0250 FIN LDA #$FC
0260 JSR WSIOSB
0270 LDA #$00
0280 STA BPTR
0290 RTS
Zapełnienie bufora powoduje wpisanie do akumulatora
wartości $FC (bufor pełny) i wywołanie procedury WSIOSB, która
wysyła zawartość bufora do magnetofonu. W tym przypadku przed
zakończeniem CASWRT jest jeszcze zerowany licznik bufora BPTR.
0100 ;Write SIO System Buffer
0110 ;
0120 CRCB = $03FF
0130 CSCB = $03FD
0140 SYSBUF = $FE3F
0150 ;
0160 *= $FE7C
0170 ;
0180 STA CRCB
0190 LDA #$55
0200 STA CSCB
0210 STA CSCB+1
0220 LDA #$57
0230 JSR SYSBUF
0240 RTS
Procedura WSIOSB uzupełnia brakujące bajty w buforze
magnetofonu. Zawartość akumulatora (rodzaj rekordu) zapisuje do
rejestru CRCB, a oba bajty kontroli szybkości CSCB (Cassette
Speed Control Byte) ustawia na $55. Wartość ta służy później
przy odczycie do regulacji szybkości transmisji i stanowi po
prostu naprzemienny ciąg bitów 0 i 1 ($55 jest równe binarnie
01010101). Na końcu do akumulatora wpisywany jest kod rozkazu
zapisu $57 (PUT RECORD) i wywoływana jest procedura SYSBUF,
która wykonuje właściwy zapis.
3.5.4. Zamknięcie magnetofonu
Zakończenie współpracy z magnetofonem wymaga przede
wszystkim zatrzymania silnika. Ponadto podczas zapisu należy
zadbać, aby wszystkie dane umieszczone w buforze zostały
wysłane do magnetofonu. Zadania te wykonywane są przez
procedurę CASCLS.
0100 ;CASsette CLoSe
0110 ;
0120 BPTR = $3D
0130 CASBEN = $047F
0140 CASBUF = $0400
0150 PACTL = $D302
0160 WMODE = $0289
0170 WSIOSB = $FE7C
0180 ;
0190 *= $FDCF
0200 ;
0210 LDA WMODE
0220 BMI WRT
0230 LDY #$01
0240 MST LDA #$3C
0250 STA PACTL
0260 RTS
0270 WRT LDX BPTR
0280 BEQ FIL
0290 STX CASBEN
0300 LDA #$FA
0310 JSR WSIOSB
0320 BMI MST
0330 FIL LDX #$7F
0340 LDA #$00
0350 STB STA CASBUF,X
0360 DEX
0370 BPL STB
0380 LDA #$FE
0390 JSR WSIOSB
0400 JMP MST
Na początku procedury sprawdzany jest znacznik WMODE (Write
MODE). Gdy jest on równy zero, to w rejestrze Y umieszczana
jest wartość 1 i przez wpisanie $3C do rejestru PACTL (Port A
ConTroL) zatrzymywany jest silnik magnetofonu.
Wartość $80 w WMODE oznacza zapis. Sprawdzany jest więc
licznik bufora BPTR. Jeśli w buforze znajdują się jakieś dane,
to zawartość BPTR jest przepisywana do CASBEN i procedura
WSIOSB wywoływana jest z wartością $FA w akumulatorze. Po
ewentualnym zapisaniu pozostałych w buforze danych trzeba
jeszcze wysłać rekord końcowy zbioru. W tym celu bufor jest
wypełniany zerami i po umieszczeniu w akumulatorze wartości $FE
jest wywoływana procedura WSIOSB. Po zatrzymaniu silnika CASCLS
się kończy.
|