Rozdział 4
TRANSMISJA SZEREGOWA
Większość urządzeń zewnętrznych przyłączonych do systemu
komunikuje się z komputerem poprzez złącze szeregowe. Po
ustaleniu niezbędnych parametrów sterowniki poszczególnych
urządzeń wywołują procedury transmisji przez złącze szeregowe.
Ten zespół procedur zwany jest szeregowym wejściem/wyjściem
(SIO - Serial Input/Output). Z procedur SIO korzystają zarówno
wbudowane sterowniki drukarki, magnetofonu i stacji dysków
(DSKINT - zob. rozdział 5), jak i pozostałe sterowniki
instalowane podczas inicjowania systemu.
4.1. Blok kontroli urządzeń
Podobnie jak program użytkownika przesyła dane do CIO
poprzez bloki IOCB, a CIO do sterowników poszczególnych
urządzeń przez blok IOCBZ, tak do przesyłania parametrów
transmisji między sterownikami urządzeń i SIO jest wydzielony
specjalny obszar pamięci RAM. Nazywa się on blokiem kontroli
urządzeń - DCB (Device Control Block) - i zajmuje część
trzeciej strony pamięci od adresu $0300 do $030B. Struktura i
znaczenie poszczególnych rejestrów DCB również są podobne do
IOCB.
+------------+
$0300 | DDEVIC |
+------------+
$0301 | DUNIT |
+------------+
$0302 | DCMND |
+------------+
$0303 | DSTATS |
+------------+
$0304 | |
+-- DBUFA --+
$0305 | |
+------------+
$0306 | |
+-- DTIMLO --+
$0307 | |
+------------+
$0308 | |
+-- DBYT --+
$0309 | |
+------------+
$030A | DAUX1 |
+------------+
$030B | DAUX2 |
+------------+
Rys.10. Struktura DCB.
DDEVIC - kod identyfikacyjny urządzenia. Stosowane są
następujące identyfikatory: $30 - stacja dysków, $40 -
drukarka, $50 - interfejs RS-232 i $60 - magnetofon. Dla stacji
dysków i interfejsu RS-232 identyfikator może być dodatkowo
zwiększany o numer urządzenia (np. $31 - stacja dysków numer 1,
$52 - interfejs numer 2).
DUNIT - numer urządzenia. Dla magnetofonu równy zero, a dla
drukarki ustawiany według zawartości ICDNO. W przypadku stacji
dysków i RS-232 może być równy zero, jeśli numer urządzenia
został już dodany do kodu identyfikacyjnego.
DCMND - kod operacji do wykonania. OS Atari przewiduje pięć
różnych operacji:
READ (kod $52 - "R") - odczyt rekordu lub sektora
PUT (kod $50 - "P") - zapis rekordu lub sektora bez
weryfikacji
WRITE (kod $57 - "W") - zapis rekordu lub sektora z
weryfikacją
STATUS (kod $53 - "S") - żądanie statusu urządzenia
FORMAT (kod $21 - "!") - formatowanie dyskietki (tylko
dla stacji dysków)
DSTATS - rodzaj i status operacji. Przed wykonaniem
operacji zawiera jej rodzaj: $40 (odczyt) lub $80 (zapis). Po
operacji zawiera jej status.
DBUFA - adres bufora danych dla wykonywanej operacji.
DTIMLO - wartość Timeout. Oznacza maksymalny czas
wykonywania danej operacji, a więc czas oczekiwania na
odpowiedź od urządzenia.
DBYT - długość bufora danych. Dla operacji dyskowych
zawiera długość sektora, dla magnetofonu - długość rekordu
(razem z trzema bajtami kontrolnymi).
DAUX1 - pierwszy bajt pomocniczy. Przy operacjach dyskowych
zawiera starszy bajt numeru sektora, dla magnetofonu jest
ignorowany, a dla pozostałych urządzeń zawiera tryb pracy.
DAUX2 - drugi bajt pomocniczy. Przy operacjach dyskowych
zawiera młodszy bajt numeru sektora, dla magnetofonu rodzaj
przerw między rekordami ($80 - krótkie, $00 - długie), a przy
współpracy z drukarką jest ignorowany.
Niektóre źródła podają jeszcze dodatkowe kody operacji SIO
($51 - READ SPIN, $54 - READ ADDRESS, $55 - MOTOR ON i $56 -
VERIFY SECTOR), lecz stacje Atari 1050 oraz Top Drive ich nie
rozpoznają. Rezultatem tych operacji jest błąd $8B (DEVICE NACK
- negatywne potwierdzenie operacji).
4.2. Wstępna procedura SIO
Po ustaleniu parametrów transmisji sterowniki urządzeń
wywołują wstępną procedurę SIO - SIOINT. Sprawdza ona, czy
chodzi o komunikację z nowym urządzeniem i ewentualnie wywołuje
procedurę, która ją przeprowadza.
Najpierw numer urządzenia jest odkładany na stos, a
następnie sprawdzana jest zawartość rejestru PDVMSK (Parallel
DeVice MaSK). Jeżeli jest ona równa zero, to znaczy, że
transmisja nie dotyczy żadnego z urządzeń dołączonych do szyny
równoległej. W takim przypadku wywoływana jest główna procedura
SIO.
0100 ;SIO INTerface
0110 ;
0120 CRITIC = $42
0130 DSTATS = $0303
0140 DUNIT = $0301
0150 GETLOW = $C9AF
0160 PDIOR = $D805
0170 PDVMSK = $0247
0180 PDVREG = $D1FF
0190 PDVRS = $0248
0200 SIO = $E971
0210 ;
0220 *= $C933
0230 ;
0240 LDA #$01
0250 STA CRITIC
0260 LDA DUNIT
0270 PHA
0280 LDA PDVMSK
0290 BEQ FOUND
0300 LDX #$08
0310 NEXT JSR GETLOW
0320 BEQ FOUND
0330 TXA
0340 PHA
0350 JSR PDIOR
0360 PLA
0370 TAX
0380 BCC NEXT
0390 LDA #$00
0400 STA PDVRS
0410 STA PDVREG
0420 BEQ END
0430 FOUND JSR SIO
0440 END PLA
0450 STA DUNIT
0460 LDA #$00
0470 STA CRITIC
0480 STY DSTATS
0490 LDY DSTATS
0500 RTS
Jeśli komunikacja będzie prowadzona z nowym urządzeniem, to
po wpisaniu do rejestru X wartości $08 rozpoczyna się pętla
rozpoznająca urządzenie i wykonująca transmisję. Na początku
pętli wywoływana jest procedura GETLOW, która odszukuje
urządzenie o najmniejszym numerze. Gdy nie ma takiego
urządzenia, również wywoływana jest procedura SIO.
Znalezienie nowego urządzenia żądającego obsługi powoduje
zapamiętanie na stosie wartości rejestru X i wywołanie
procedury PDIOR (Parallel Device I/O Routine) z aktualnie
aktywnego urządzenia. Procedura ta umieszczona jest w pamięci
ROM urządzenia, a pod podanym tu adresem znajduje się tylko jej
właściwy adres poprzedzony rozkazem skoku JMP.
Po zakończeniu PDIOR odtwarzana jest wartość rejestru X i
pętla jest kontynuowana. Gdy zostaną sprawdzone wszystkie nowe
urządzenia, to są one odłączane przez wyzerowanie rejestrów
PDVRS i PDVREG.
Procedura SIOINT kończy się w każdym przypadku odtworzeniem
ze stosu numeru urządzenia DUNIT, skasowaniem znacznika CRITIC
i umieszczeniem w rejestrze Y oraz DSTATS rezultatu operacji.
Procedura GETLOW rozpoczyna się od zmniejszenia rejestru X.
Jeśli uzyskana wartość jest ujemna, to po wyzerowaniu rejestrów
PDVRS i PDVREG następuje powrót do SIOINT.
0100 ;GET LOWest
0110 ;
0120 PDVREG = $D1FF
0130 PDVMSK = $0247
0140 PDVRS = $0248
0150 BITMSK = $CA21
0160 ;
0170 *= $C9AF
0180 ;
0190 GETLOW DEX
0200 BPL CONT
0210 LDA #$00
0220 STA PDVRS
0230 STA PDVREG
0240 RTS
0250 CONT LDA PDVMSK
0260 AND BITMSK,X
0270 BEQ GETLOW
0280 STA PDVRS
0290 STA PDVREG
0300 RTS
W przeciwnym razie z zawartości rejestru PDVMSK jest
wydzielany bit określający urządzenie, które wymaga obsługi.
Wykonywane jest to przy pomocy maski bitowej pobranej z tabeli
BITMSK. Gdy bit ten jest skasowany, następuje powrót do
początku GETLOW i sprawdzane jest następne urządzenie.
Wartość różna od zera jest przepisywana do rejestrów PDVRS
i PDVREG. Tam ustawiony bit powoduje zaktywizowanie
odpowiadającego mu urządzenia (zob. "Mapa pamięci Atari XL/XE.
Podstawowe procedury systemu operacyjnego").
0100 ;BIT MaSK table
0110 ;
0120 *= $CA21
0130 ;
0140 .BYTE $80,$40,$20,$10
0150 .BYTE $08,$04,$02,$01
Każda maska bitowa zawarta w tej tabeli ma ustawiony jeden
bit. Ponieważ uszeregowane są one od najstarszego do
najmłodszego bitu, to przy odczycie przez GETLOW od końca
kolejno sprawdzane są urządzenia o numerze od 0 do 8.
4.3. Główna procedura SIO
Po stwierdzeniu braku transmisji z lub do nowego urządzenia
wywoływana jest główna procedura SIO. Przeprowadza ona całą
operację transmisji przez złącze szeregowe.
< SIO >
|
v
/------------\ tak ++--------++
< magnetofon ? >------>|| CASENT ||
\------------/ ++--------++
| nie
v
+-----------------------------+
+--------->| nadanie parametrów operacji |
| +-----------------------------+
| |
| v
| nie /-------\
| +----<----< udane ? >
| | \-------/
| v | tak
| nie /--------\ |
+<----< CRETRY<0 > |
^ \--------/ |
| | tak v
| +--------+ tak /-------\ nie
| | +<----< odczyt? >---->+
| | | \-------/ |
| | v v
| | +--------------------+ +--------------+
| | | ustawienie Timeout | | zapis bufora |
| | +--------------------+ +--------------+
| | | |
| | v v
| | +---------------+ +--------------------+
| | | odczyt bufora | | ustawienie Timeout |
| | +---------------+ +--------------------+
| | | |
| | +--------->+<---------+
| | |
| | v
| | nie /----------\ tak
| +--------->+<----< status = 1 >----+
| | \----------/ |
| v |
| nie /--------\ tak v
+--<----< DRETRY<0 >---->------------+
\--------/ |
v
< CPLSIO >
Rys.11. Struktura operacji SIO.
0100 ;SIO main routine 0660 ADC #$FF
0110 ; 0670 STA CDEVIC
0120 AUDF3 = $D204 0680 LDA DCMND
0130 AUDF4 = $D206 0690 STA CCMND
0140 BUFEN = $34 0700 LDA DAUX1
0150 BUFR = $32 0710 STA CAUX1
0160 CASENT = $EB9D 0720 LDA DAUX2
0170 CASFLG = $030F 0730 STA CAUX2
0180 CAUX1 = $023C 0740 CLC
0190 CAUX2 = $023D 0750 LDA # <CDEVIC
0200 CCMND = $023B 0760 STA BUFR
0210 CDEVIC = $023A 0770 ADC #$04
0220 CRETRY = $029C 0780 STA BUFEN
0230 CRITIC = $42 0790 LDA # >CDEVIC
0240 DAUX1 = $030A 0800 STA BUFR+1
0250 DAUX2 = $030B 0810 STA BUFEN+1
0260 DCMND = $0302 0820 LDA #$34
0270 DDEVIC = $0300 0830 STA PBCTL
0280 DRETRY = $02BD 0840 JSR SENDIN
0290 DSTATS = $0303 0850 LDA ERRFLG
0300 DUNIT = $0301 0860 BNE ERR
0310 ERRFLG = $023F 0870 TYA
0320 LODPTR = $EB87 0880 BNE STAT
0330 PBCTL = $D303 0890 ERR DEC CRETRY
0340 RECEIV = $EAFD 0900 BPL LOOP2
0350 SENDIN = $ECAF 0910 JMP NEXT
0360 SETTOT = $EC9A 0920 STAT LDA DSTATS
0370 SNDDIS = $EC84 0930 BPL TMOT
0380 STACKP = $0318 0940 LDA #$0D
0390 STATUS = $30 0950 STA CRETRY
0400 STIMWT = $ECC0 0960 JSR LODPTR
0410 TSTAT = $0319 0970 JSR SENDIN
0420 ; 0980 BEQ EXIT
0430 *= $E971 0990 TMOT JSR SETTOT
0440 ; 1000 LDA #$00
0450 TSX 1010 STA ERRFLG
0460 STX STACKP 1020 JSR STIMWT
0470 LDA #$01 1030 BEQ PRC
0480 STA CRITIC 1040 BIT DSTATS
0490 LDA DDEVIC 1050 BVS RCV
0500 CMP #$60 1060 LDA ERRFLG
0510 BNE DSK 1070 BNE NEXT
0520 JMP CASENT 1080 BEQ CPLSIO
0530 DSK LDA #$00 1090 RCV JSR LODPTR
0540 STA CASFLG 1100 JSR RECEIV
0550 LDA #$01 1110 PRC LDA ERRFLG
0560 STA DRETRY 1120 BEQ RES
0570 LOOP1 LDA #$0D 1130 LDA TSTAT
0580 STA CRETRY 1140 STA STATUS
0590 LOOP2 LDA #$28 1150 RES LDA STATUS
0600 STA AUDF3 1160 CMP #$01
0610 LDA #$00 1170 BEQ CPLSIO
0620 STA AUDF4 1180 NEXT DEC DRETRY
0630 CLC 1190 BMI CPLSIO
0640 LDA DDEVIC 1200 JMP LOOP1
0650 ADC DUNIT 1210 ;
1220 ;ComPLete SIO 1260 STA CRITIC
1230 ; 1270 LDY STATUS
1240 CPLSIO JSR SNDDIS 1280 STY DSTATS
1250 LDA #$00 1290 RTS
Przed przystąpieniem do transmisji w rejestrze STACKP
(STACK Pointer) zapamiętywany jest wskaźnik stosu procesora, a
znacznik CRITIC jest ustawiany na 1 (jest on sprawdzany przez
procedurę przerwania SYSVBL - zob. "Mapa pamięci Atari XL/XE.
Podstawowe procedury systemu operacyjnego"). Następnie
sprawdzany jest kod urządzenia w rejestrze DDEVIC. Jeżeli
oznacza on magnetofon, to następuje skok do CASENT, gdzie
prowadzona jest komunikacja z magnetofonem.
W przeciwnym razie kasowany jest znacznik magnetofonu
CASFLG (CASsette FLaG) i ustalane są liczby prób podjęcia
komunikacji z urządzeniem DRETRY (Device RETRY) i CRETRY
(Command RETRY). Następnie wpisywane są do rejestrów AUDF3 i
AUDF4 wartości określające szybkość transmisji.
Polecenie wykonania operacji jest wysyłane do urządzenia w
formie czterobajtowego bloku, zwanego CFB (Command Frame
Buffer). Zawartości DDEVIC, DCMND, DAUX1 i DAUX2 są więc
przepisywane do odpowiednich rejestrów CFB. Adres pierwszego
rejestru CFB (CDEVIC) jest wpisywany jako adres bufora BUFR
(BUFfeR), a adres następnego rejestru po CFB jako adres końca
bufora BUFEN (BUFfer ENd). Teraz przez rejestr PBCTL
sygnalizowane jest nadawanie polecenia i przez wywołanie
procedury SENDIN blok CFB jest wysyłany do urządzenia. W
przypadku wystąpienia błędu - sygnalizowanego w rejestrze
ERRFLG (ERRor FLaG) - czynność ta jest powtarzana, aż do
wyzerowania rejestru CRETRY.
Po przyjęciu polecenia przez urządzenie rozpoczyna się
właściwa operacja. Kolejność czynności jest przy tym odwrotna
dla zapisu i odczytu, a do rozpoznania rodzaju operacji służy
rejestr DSTATS (Device STATuS). Ustawienie w nim bitu 7
sygnalizuje zapis, a ustawienie bitu 6 oznacza odczyt.
Przy zapisie najpierw adres bufora danych jest ustawiany
przez procedurę LODPTR i informacja jest wysyłana przez
wywołanie SENDIN. Następnie ustalany jest (przez procedurę
SETTOT) maksymalny czas wykonywania operacji i komputer czeka
na odpowiedź urządzenia. Ta czynność jest przeprowadzana przez
wywołanie STIMWT.
Podczas odczytu najpierw wywoływane są procedury SETTOT i
STIMWT, a dopiero po zgłoszeniu się urządzenia procedura LODPTR
ustala adres bufora, a procedura RECEIV dokonuje odczytu
przesyłanej informacji.
Jeżeli podczas operacji wystąpił błąd, to jest ona
powtarzana od początku, aż do wyzerowania rejestru DRETRY.
Pozytywny wynik operacji powoduje przejście do końcowej fazy
procedury SIO oznaczonej etykietą CPLSIO. Wywoływana jest tam
procedura SNDDIS, która kończy transmisję, zerowany jest
znacznik CRITIC, a rezultat operacji jest przepisywany z
rejestru STATUS do DSTATS.
Opis procedur wykorzystywanych przez SIO rozpoczną dwie
krótkie procedury pomocnicze LODPTR i SETTOT.
Procedura LODPTR przenosi adres i długość bufora danych z
rejestrów DBUFA i DBYT do rejestrów BUFR i BUFEN. Ponieważ
BUFEN zawiera adres końca bufora, to przed zapisaniem do tego
rejestru długość bufora DBYT musi być dodana do jego adresu
DBUFA.
0100 ;LOaD PoinTeR
0110 ;
0120 BUFEN = $34
0130 BUFR = $32
0140 DBUFA = $0304
0150 DBYT = $0308
0160 ;
0170 *= $EB87
0180 ;
0190 CLC
0200 LDA DBUFA
0210 STA BUFR
0220 ADC DBYT
0230 STA BUFEN
0240 LDA DBUFA+1
0250 STA BUFR+1
0260 ADC DBYT+1
0270 STA BUFEN+1
0280 RTS
Procedura SETTOT przygotowuje parametry dla STIMWT. W
bitach 0-5 rejestru X umieszczane są bity 2-7 z DTIMLO, a w
bitach 6 i 7 rejestru Y bity 0 i 1 z DTIMLO.
0100 ;SET TimeOuT
0110 ;
0120 DTIMLO = $0306
0130 ;
0140 *= $EC9A
0150 ;
0160 LDA DTIMLO
0170 ROR A
0180 ROR A
0190 TAY
0200 AND #$3F
0210 TAX
0220 TYA
0230 ROR A
0240 AND #$C0
0250 TAY
0260 RTS
Operacja wysyłania informacji przez złącze szeregowe jest
przeprowadzana przez procedurę SENDIN. Jej część od etykiety
STIMWT jest także wykorzystywana podczas odczytu z urządzenia.
SENDIN rozpoczyna się od podwójnej pętli opóźniającej. Po
jej zakończeniu wywoływana jest procedura SEND, która wysyła
informację przez złącze szeregowe. Następnie w rejestrach X i Y
ustawiane są parametry czasu oczekiwania na potwierdzenie i
wywoływana jest procedura SETT1V, uruchamiająca przerwanie
zegara TIMCNT1. Na końcu wywoływana jest procedura WAIT, w
czasie której komputer oczekuje na odpowiedź od urządzenia
zewnętrznego.
0100 ;SEND INitiation
0110 ;
0120 SEND = $EA88
0130 SETT1V = $EDE2
0140 WAIT = $EA37
0150 ;
0160 *= $ECAF
0170 ;
0180 LDX #$01
0190 LOOP1 LDY #$FF
0200 LOOP2 DEY
0210 BNE LOOP2
0220 DEX
0230 BNE LOOP1
0240 JSR SEND
0250 LDY #$02
0260 LDX #$00
0270 ;
0280 ;Set TIMeout and WaiT
0290 STIMWT JSR SETT1V
0300 JSR WAIT
0310 TYA
0320 RTS
Zadaniem procedury SETT1V jest przygotowanie systemu do
odliczania czasu oczekiwania na odpowiedź. W tym celu wektor
przerwania TIMVEC1 jest ustawiany na adres procedury TIM1INT.
Następnie wywoływana jest procedura SETVBLV, która ustawia
licznik TIMCNT1 według wartości umieszczonych w rejestrach X i
Y przed wywołaniem SETT1V. Na zakończenie znacznik TIMFLG
(TIMeout FLaG) otrzymuje wartość 1.
0100 ;SET Timer 1 Vector
0110 ;
0120 JSETVBV = $E45C
0130 TIM1INT = $EC11
0140 TIMFLG = $0317
0150 TIMVEC1 = $0226
0160 ;
0170 *= $EDE2
0180 ;
0190 LDA # <TIM1INT
0200 STA TIMVEC1
0210 LDA # >TIM1INT
0220 STA TIMVEC1+1
0230 LDA #$01
0240 SEI
0250 JSR JSETVBV
0260 LDA #$01
0270 STA TIMFLG
0280 CLI
0290 RTS
Drugą ważną procedurą wywoływaną przez SENDIN jest WAIT.
Oczekuje ona na odpowiedź urządzenia, a następnie bada
poprawność przeprowadzonej operacji.
0100 ;WAIT for completion
0110 ;
0120 BUFEN = $34
0130 BUFR = $32
0140 ERRFLG = $023F
0150 NOCKSM = $3C
0160 RECEIV = $EAFD
0170 STATUS = $30
0180 TEMP = $023E
0190 TSTAT = $0319
0200 ;
0210 *= $EA37
0220 ;
0230 LDA #$00
0240 STA ERRFLG
0250 CLC
0260 LDA # <TEMP
0270 STA BUFR
0280 ADC #$01
0290 STA BUFEN
0300 LDA # >TEMP
0310 STA BUFR+1
0320 STA BUFEN+1
0330 LDA #$FF
0340 STA NOCKSM
0350 JSR RECEIV
0360 LDY #$FF
0370 LDA STATUS
0380 CMP #$01
0390 BNE ERR
0400 LDA TEMP
0410 CMP #$41
0420 BEQ END
0430 CMP #$43
0440 BEQ END
0450 CMP #$45
0460 BNE NACK
0470 LDA #$90
0480 STA STATUS
0490 BNE ERR
0500 NACK LDA #$8B
0510 STA STATUS
0520 ERR LDA STATUS
0530 CMP #$8A
0540 BEQ TMOT
0550 LDA #$FF
0560 STA ERRFLG
0570 BNE END
0580 TMOT LDY #$00
0590 END LDA STATUS
0600 STA TSTAT
0610 RTS
Po wyzerowaniu znacznika błędu ERRFLG wektor bufora BUFR
jest ustawiany na adres rejestru tymczasowego TEMP, do którego
zostanie odczytana odpowiedź urządzenia. Następnie wywoływana
jest procedura RECEIV, która dokonuje odczytu informacji ze
złącza szeregowego.
Jeśli podczas transmisji nie wystąpił błąd (STATUS=$01), to
sprawdzana jest odpowiedź urządzenia. Wartości $41 i $43
oznaczają poprawne wykonanie transmisji i przerywają procedurę.
Wartość $45 oznacza potwierdzenie negatywne i powoduje wpisanie
do rejestru STATUS kodu błędu $8B (DEVICE NACK - negatywne
potwierdzenie). Każda inna zawartość rejestru TEMP powoduje
wpisanie do STATUS kodu błędu $90 (DEVICE DONE ERROR - błąd
wykonania).
Po wykryciu dowolnego błędu sprawdzany jest rejestr STATUS
i gdy nie wskazuje przekroczenia czasu ($8A - TIMEOUT), to
znacznik ERRFLG otrzymuje wartość $FF. W każdym przypadku
procedura kończy się przepisaniem zawartości rejestru STATUS do
TSTAT.
4.3.1. Nadawanie na złącze szeregowe
Właściwe przesłanie danych do złącza szeregowego jest
wykonywane przez procedurę SEND. Po ustawieniu statusu na 1
wywołuje ona procedurę uruchamiającą nadawanie SNDENBL.
0100 ;SEND buffer to serial bus
0110 ;
0120 BUFR = $32
0130 CHKSNT = $3B
0140 CHKSUM = $31
0150 IRQSTAT = $11
0160 PRBRKK = $EDC7
0170 SEROUT = $D20D
0180 SNDDIS = $EC84
0190 SNDENBL = $EC17
0200 STATUS = $30
0210 XMTDON = $3A
0220 ;
0230 *= $EA88
0240 ;
0250 LDA #$01
0260 STA STATUS
0270 JSR SNDENBL
0280 LDY #$00
0290 STY CHKSUM
0300 STY CHKSNT
0310 STY XMTDON
0320 LDA (BUFR),Y
0330 STA SEROUT
0340 STA CHKSUM
0350 LOOP LDA IRQSTAT
0360 BNE CONT
0370 JMP PRBRKK
0380 CONT LDA XMTDON
0390 BEQ LOOP
0400 JSR SNDDIS
0410 RTS
Następnie zeruje rejestry CHKSUM (CHecK SUM), CHKSNT (CHecK
sum SeNT) i XMTDON (eXMiTe DONe). Bajt odczytany z bufora
wskazywanego przez BUFR przepisywany jest do rejestrów CHKSUM i
SEROUT. Ostatnia czynność powoduje żądanie przerwania i
wywołanie procedury ISRODN.
Teraz komputer czeka na zmianę wartości znacznika XMTDON
sygnalizującą zakończenie transmisji. W tym czasie sprawdzany
jest rejestr IRQSTAT, a gdy wskaże on naciśnięcie klawisza
BREAK, następuje skok do środka procedury BEGNRD w miejsce
oznaczone etykietą PRBRKK. Po zakończeniu transmisji wywoływana
jest jeszcze procedura SNDDIS.
Zadaniem procedury SNDENBL jest zezwolenie na wysyłanie
informacji przez złącze szeregowe. W tym celu wpisuje ona
odpowiednie wartości do rejestrów SKCTLS (Serial and Keyboard
ConTroL Shadow register) i IRQENS (Interrupt ReQuest ENable
Shadow register). Ponadto przy współpracy z magnetofonem
ustawiane są częstotliwości generatorów dźwięku numer 1 i 2.
Procedura kończy się skokiem do środka procedury RECVEN (zob.
rozdział 4.3.2.).
0100 ;SeND ENaBLe
0110 ;
0120 AUDF1 = $D200
0130 AUDF2 = $D202
0140 DDEVIC = $0300
0150 ENABLE = $EC56
0160 IRQENS = $10
0170 SKCTLS = $0232
0180 SKSTAT = $D20F
0190 ;
0200 *= $EC17
0210 ;
0220 LDA #$07
0230 AND SKCTLS
0240 ORA #$20
0250 LDY DDEVIC
0260 CPY #$60
0270 BNE NCR
0280 ORA #$08
0290 LDY #$07
0300 STY AUDF2
0310 LDY #$05
0320 STY AUDF1
0330 NCR STA SKCTLS
0340 STA SKSTAT
0350 LDA #$C7
0360 AND IRQENS
0370 ORA #$10
0380 JMP ENABLE
Po nadaniu informacji zadanie zamknięcia komunikacji
wypełnia procedura SNDDIS. Ustawia ona rejestry zezwoleń na
przerwania IRQEN i IRQENS oraz zeruje rejestry kontroli
generatorów dźwięku AUDC1-3.
0100 ;SeND DISable
0110 ;
0120 AUDC1 = $D201
0130 IRQEN = $D20E
0140 IRQENS = $10
0150 ;
0160 *= $EC84
0170 ;
0180 NOP
0190 LDA #$C7
0200 AND IRQENS
0210 STA IRQENS
0220 STA IRQEN
0230 LDX #$06
0240 LDA #$00
0250 NEXT STA AUDC1,X
0260 DEX
0270 DEX
0280 BPL NEXT
0290 RTS
4.3.2. Odczyt ze złącza szeregowego
Właściwy odczyt z szyny szeregowej jest wykonywany przez
procedurę RECEIV. Jeżeli odczyt dokonywany jest z magnetofonu,
to najpierw zerowany jest rejestr sumy kontrolnej CHKSUM, zaś
niezależnie od rodzaju urządzenia zerowane są znaczniki BUFRFL
(BUFfeR FulL) i RECVND (RECeiVe eND). Następnie po ustawieniu
statusu na 1 wywoływana jest procedura RECVEN, która uruchamia
odczyt.
Po zasygnalizowaniu w rejestrze PBCTL gotowości do odczytu
komputer oczekuje w pętli na zmianę wartości w rejestrze
RECVND, która sygnalizuje zakończenie odczytu. Podczas pętli
sprawdzane są jeszcze rejestry IRQSTAT (sygnalizuje naciśnięcie
BREAK) i TIMFLG (sygnalizuje błąd Timeout).
Procedura RECEIV może być zakończona trzema sposobami: po
poprawnym odczycie rozkazem RTS, po naciśnięciu klawisza BREAK
skokiem do PRBRKK lub po przekroczeniu czasu skokiem do ITIMOT.
W tym ostatnim przypadku do rejestru STATUS wpisywany jest kod
błędu $8A (TIMEOUT ERROR - przekroczenie czasu).
0100 ;RECEIVe
0110 ;
0120 BUFRFL = $38
0130 CASFLG = $030F
0140 CHKSUM = $31
0150 IRQSTAT = $11
0160 PBCTL = $D303
0170 PRBRKK = $EDC7
0180 RECVEN = $EC40
0190 RECVND = $39
0200 STATUS = $30
0210 TIMFLG = $0317
0220 ;
0230 *= $EAFD
0240 ;
0250 LDA #$00
0260 LDY CASFLG
0270 BNE BPS
0280 STA CHKSUM
0290 BPS STA BUFRFL
0300 STA RECVND
0310 LDA #$01
0320 STA STATUS
0330 JSR RECVEN
0340 LDA #$3C
0350 STA PBCTL
0360 NEXT LDA IRQSTAT
0370 BNE PRC
0380 JMP PRBRKK
0390 PRC LDA TIMFLG
0400 BEQ ITIMOT
0410 LDA RECVND
0420 BEQ NEXT
0430 RTS
0440 ;
0450 ;Indicate TIMeOuT
0460 ;
0470 ITIMOT LDA #$8A
0480 STA STATUS
0490 RTS
Procedura RECVEN spełnia taką samą funkcję przy odczycie
jak SENDEN przy zapisie. Część od etykiety ENABLE jest nawet
wspólna dla obu procedur. Na początku odpowiednie wartości są
wpisywane do rejestrów SKCTL, SKCTLS, IRQEN i IRQENS. Następnie
ustawiane są parametry generatorów dźwięku w rejestrach
kontroli AUDCTL oraz AUDC1-3.
0100 ;RECeiVe ENable
0110 ;
0120 AUDC1 = $D201
0130 AUDC2 = $D203
0140 AUDC3 = $D205
0150 AUDCTL = $D208
0160 DDEVIC = $0300
0170 IOSNDEN = $41
0180 IRQEN = $D20E
0190 IRQENS = $10
0200 SKCTL = $D20F
0210 SKCTLS = $0232
0220 SKSTRES = $D20A
0230 ;
0240 *= $EC40
0250 ;
0260 LDA #$07
0270 AND SKCTLS
0280 ORA #$10
0290 STA SKCTLS
0300 STA SKCTL
0310 STA SKSTRES
0320 LDA #$C7
0330 AND IRQENS
0340 ORA #$20
0350 ENABLE STA IRQENS
0360 STA IRQEN
0370 LDA #$28
0380 STA AUDCTL
0390 LDX #$06
0400 LDA #$A8
0410 LDY IOSNDEN
0420 BNE NEXT
0430 LDA #$A0
0440 NEXT STA AUDC1,X
0450 DEX
0460 DEX
0470 BPL NEXT
0480 LDA #$A0
0490 STA AUDC3
0500 LDY DDEVIC
0510 CPY #$60
0520 BEQ EXIT
0530 STA AUDC1
0540 STA AUDC2
0550 EXIT RTS
4.4. Procedury SIO dla magnetofonu
Rozpoznanie przez procedurę SIO komunikacji z magnetofonem
powoduje skok do procedury CASENT. Oddzielenie procedury SIO
magnetofonu od procedury obsługującej pozostałe urządzenia jest
spowodowane jego specyfiką. Jako jedyne z urządzeń
peryferyjnych magnetofon nie posiada układów sterujących i
komputer komunikuje się z nim "w ciemno".
Struktura procedury CASENT jest zbliżona do procedury SIO.
Tu także jedynie początek i koniec są wspólne dla odczytu i
zapisu, natomiast w pozostałej części kolejność faz jest
zamieniona. Do rozróżnienia rodzaju operacji wykorzystywana
jest zawartość rejestru DSTATS.
Podczas zapisu najpierw ustalane są częstotliwości
generatorów dźwięku i wywoływana jest procedura SNDENBL, która
uruchamia nadawanie informacji na szynę szeregową. Następnie
według zawartości rejestru PALNTS odczytywane są z tabeli
STVCTB dane, które przekazane procedurze SETT1V służą do
ustalenia czasu operacji.
0100 ;System TV Constant TaBle
0110 ;
0120 *= $EE11
0130 ;
0140 .BYTE $B4,$96,$78,$64
0150 .BYTE $0F,$0D,$0A,$08
0160 .BYTE $83,$9C
Po ustawieniu Timeout uruchamiany jest silnik magnetofonu i
komputer czeka w pętli WAIT1. W tym czasie na kasecie nagrywany
jest sygnał pilotujący. Następnie wywoływana jest procedura
LODPTR, która ustawia adresy bufora danych, oraz procedura
SEND, która przepisuje zawartość bufora na szynę szeregową.
Zapis kończy się skokiem do ostatniej fazy procedury
(wspólnej dla obu operacji). Jeżeli zawartość DAUX2 sygnalizuje
długie przerwy między rekordami, to wyłączany jest silnik
magnetofonu. Procedura CASENT kończy się skokiem do CPLSIO.
Operacja odczytu rozpoczyna się od ustalenia czasu Timeout
przez procedurę SETT1V na podstawie wartości pobranych z tabeli
STVCTB. Następnie uruchamiany jest silnik magnetofonu. Po
upływie czasu określonego przez Timeout w celu ustawienia
adresu bufora wywoływana jest procedura LODPTR.
W dalszej kolejności wywoływana jest procedura SETTOT,
która zwraca parametry Timeout i ponownie SETT1V ustawia
procedurę przerwania TIMCNT1. Następnie poprzez BEGNRD
rozpoczynany jest odczyt, którego kontynuację przejmuje
procedura RECEIV. Po jej zakończeniu komputer przechodzi do
ostatniej fazy CASENT (zob. wyżej).
0100 ;CASsette ENTer
0110 ;
0120 AUDF3 = $D204
0130 AUDF4 = $D206
0140 BEGNRD = $ED3D
0150 CASFLG = $030F
0160 CPLSIO = $EA2A
0170 DAUX2 = $030B
0180 DSTATS = $0303
0190 LODPTR = $EB87
0200 PACTL = $D302
0210 PALNTS = $62
0220 RECEIV = $EAFD
0230 SEND = $EA88
0240 SNDENBL = $EC17
0250 SETT1V = $EDE2
0260 SETTOT = $EC9A
0270 STVCTB = $EE11
0280 TIMFLG = $0317
0290 ;
0300 *= $EB9D
0310 ;
0320 LDA DSTATS
0330 BPL READ
0340 LDA #$CC
0350 STA AUDF3
0360 LDA #$05
0370 STA AUDF4
0380 JSR SNDENBL
0390 LDX PALNTS
0400 LDY STVCTB+4,X
0410 LDA DAUX2
0420 BMI SKIP1
0430 LDY STVCTB,X
0440 SKIP1 LDX #$00
0450 JSR SETT1V
0460 LDA #$34
0470 STA PACTL
0480 WAIT1 LDA TIMFLG
0490 BNE WAIT1
0500 JSR LODPTR
0510 JSR SEND
0520 JMP END
0530 READ LDA #$FF
0540 STA CASFLG
0550 LDX PALNTS
0560 LDY STVCTB+6,X
0570 LDA DAUX2
0580 BMI SKIP2
0590 LDY STVCTB+2,X
0600 SKIP2 LDX #$00
0610 JSR SETT1V
0620 LDA #$34
0630 STA PACTL
0640 WAIT2 LDA TIMFLG
0650 BNE WAIT2
0660 JSR LODPTR
0670 JSR SETTOT
0680 JSR SETT1V
0690 JSR BEGNRD
0700 JSR RECEIV
0710 END LDA DAUX2
0720 BMI EXIT
0730 LDA #$3C
0740 STA PACTL
0750 EXIT JMP CPLSIO
Rozpoczęcie odczytu jest przeprowadzane przez procedurę
BEGNRD. Najpierw oczekuje ona w pętli na sygnał (w SKCTL)
odczytania informacji z szyny szeregowej. Podczas pętli
sprawdzany jest klawisz BREAK (poprzez rejestr IRQSTAT) oraz
upływ czasu operacji Timeout (poprzez znacznik TIMFLG).
Naciśnięcie BREAK powoduje skok do PRBRKK, gdzie przerywana
jest transmisja i ustawiany status operacji (na $80 - BREAK
ABORT - przerwanie klawiszem BREAK). Przekroczenie maksymalnego
czasu trwania operacji powoduje natomiast skok do ITIMOT.
0100 ;BEGiN ReaD
0110 ;
0120 AUDF3 = $D204
0130 AUDF4 = $D206
0140 BUFR = $32
0150 CBAUD = $02EE
0160 CHKSUM = $31
0170 COMPUT = $ECC8
0180 CPLSIO = $EA2A
0190 INTIM1 = $030C
0200 IRQSTAT = $11
0210 ITIMOT = $EB27
0220 PACTL = $D302
0230 PBCTL = $D303
0240 RTCLOCK = $12
0250 SAVIO = $0316
0260 SNDDIS = $EC84
0270 SKCTL = $D20F
0280 SKCTLS = $0232
0290 STACKP = $0318
0300 STATUS = $30
0310 TEMP3 = $0315
0320 TIMFLG = $0317
0330 VCOUNT = $D40B
0340 ;
0350 *= $ED3D
0360 ;
0370 BEGNRD LDA IRQSTAT
0380 BNE PRC
0390 JMP PRBRKK
0400 PRC SEI
0410 LDA TIMFLG
0420 BNE CONT
0430 BEQ TOT
0440 CONT LDA SKCTL
0450 AND #$10
0460 BNE BEGNRD
0470 STA SAVIO
0480 LDX VCOUNT
0490 LDY RTCLOCK+2
0500 STX INTIM1
0510 STY INTIM1+1
0520 LDX #$01
0530 STX TEMP3
0540 LDY #$0A
0550 STT LDA IRQSTAT
0560 BEQ PRBRKK
0570 LDA TIMFLG
0580 BNE CTL
0590 TOT CLI
0600 JMP ITIMOT
0610 CTL LDA SKCTL
0620 AND #$10
0630 CMP SAVIO
0640 BEQ STT
0650 STA SAVIO
0660 DEY
0670 BNE STT
0680 DEC TEMP3
0690 BMI CPT
0700 LDA VCOUNT
0710 LDY RTCLOCK+2
0720 JSR COMPUT
0730 LDY #$09
0740 BNE STT
0750 CPT LDA CBAUD
0760 STA AUDF3
0770 LDA CBAUD+1
0780 STA AUDF4
0790 LDA #$00
0800 STA SKCTL
0810 LDA SKCTLS
0820 STA SKCTL
0830 LDA #$55
0840 STA (BUFR),Y
0850 INY
0860 STA (BUFR),Y
0870 LDA #$AA
0880 STA CHKSUM
0890 CLC
0900 LDA BUFR
0910 ADC #$02
0920 STA BUFR
0930 LDA BUFR+1
0940 ADC #$00
0950 STA BUFR+1
0960 CLI
0970 RTS
0980 ;
0990 ;PRocess BReaK Key
1000 ;
1010 PRBRKK JSR SNDDIS
1020 LDA #$3C
1030 STA PACTL
1040 LDA #$3C
1050 STA PBCTL
1060 LDA #$80
1070 STA STATUS
1080 LDX STACKP
1090 TXS
1100 DEC IRQSTAT
1110 CLI
1120 JMP CPLSIO
Po zasygnalizowaniu w rejestrze SKCTL rozpoczęcia
transmisji do rejestru INTIM1 (INterval TIMer 1) przepisywane
są stany licznika linii ekranu VCOUNT i zegara RTCLOCK. Teraz
komputer oczekuje na następny sygnał w SKCTL. Po jego uzyskaniu
aktualne stany VCOUNT i RTCLOCK są zapisywane odpowiednio w
akumulatorze i rejestrze Y oraz wywoływana jest procedura
COMPUT. Służy ona do obliczenia właściwej prędkości transmisji.
Ustalona prędkość transmisji jest teraz przepisywana do
rejestrów częstotliwości generatorów dźwięku. Po wpisaniu
wartości początkowych bajtów rekordu (były one wykorzystane do
regulacji szybkości) do bufora procedura się kończy.
Procedura COMPUT oblicza rzeczywistą szybkość transmisji z
magnetofonu. Umożliwia to dostosowanie się komputera do
nierównomiernego przesuwu taśmy w magnetofonie oraz do zmian
jej długości. Na początku, po zapisaniu w rejestrze INTIM2
(INterval TIMer 2) przekazanych wartości, dwukrotnie wywoływana
jest procedura ADJUST. Jej zadaniem jest poprawienie wartości
odczytanych z licznika linii obrazu w zależności od systemu TV,
w którym pracuje komputer.
0100 ;ADJUST
0110 ;
0120 ADJTAB = $EE1B
0130 PALNTS = $62
0140 ;
0150 *= $ED2E
0160 ;
0170 CMP #$7C
0180 BMI ADJ
0190 SEC
0200 SBC #$7C
0210 RTS
0220 ADJ CLC
0230 LDX PALNTS
0240 ADC ADJTAB,X
0250 RTS
Jeśli przekazana w akumulatorze wartość jest większa od
$7C, to jest ona zmniejszana o tą wartość. Gdy jest mniejsza,
to dodawana jest wartość pobrana z tabeli ADJTAB według
znacznika zastosowanego systemu TV (PALNTS).
0100 ;ADJust TABle
0110 ;
0120 *= $EE1B
0130 ;
0140 .BYTE $07,$20
Następnie różnica między poprawionymi wartościami licznika
linii jest zapisywana do przejściowego rejestru TEMP1, a
różnica między stanami zegara RTCLOCK do rejestru Y. Odczytana
z tabeli STVCTB wartość jest teraz mnożona przez zawartość Y
(dodawana Y razy) i do rezultatu dodawana jest zawartość TEMP1.
Wynik ten zmniejszony o $16 jest umieszczany w rejestrze X, a
jego 3 najmłodsze bity (przed zmniejszeniem) w rejestrze Y.
Zawartość rejestru Y służy dalej jako mnożnik liczby $0B
dodawanej do $F5. Od osiągniętego wyniku jest jeszcze
odejmowane $07 i gdy rezultat jest ujemny, to w Y znajduje się
wartość $FF, a w przeciwnym razie - $00.
0100 ;COMPUTe baud rate
0110 ;
0120 ADJUST = $ED2E
0130 CBAUD = $02EE
0140 INTIM1 = $030C
0150 INTIM2 = $0310
0160 PALNTS = $62
0170 POKTAB = $EDF9
0180 STVCTB = $EE11
0190 TEMP1 = $0312
0200 ;
0210 *= $ECC8
0220 ;
0230 STA INTIM2
0240 STY INTIM2+1
0250 JSR ADJUST
0260 STA INTIM2
0270 LDA INTIM1
0280 JSR ADJUST
0290 STA INTIM1
0300 LDA INTIM2
0310 SEC
0320 SBC INTIM1
0330 STA TEMP1
0340 LDA INTIM2+1
0350 SEC
0360 SBC INTIM1+1
0370 TAY
0380 LDX PALNTS
0390 LDA #$00
0400 SEC
0410 SBC STVCTB+8,X
0420 LOOP1 CLC
0430 ADC STVCTB+8,X
0440 DEY
0450 BPL LOOP1
0460 CLC
0470 ADC TEMP1
0480 TAY
0490 LSR A
0500 LSR A
0510 LSR A
0520 ASL A
0530 SEC
0540 SBC #$16
0550 TAX
0560 TYA
0570 AND #$07
0580 TAY
0590 LDA #$F5
0600 LOOP2 CLC
0610 ADC #$0B
0620 DEY
0630 BPL LOOP2
0640 LDY #$00
0650 SEC
0660 SBC #$07
0670 BPL SKIP
0680 DEY
0690 SKIP CLC
0700 ADC POKTAB,X
0710 STA CBAUD
0720 TYA
0730 ADC POKTAB+1,X
0740 STA CBAUD+1
0750 RTS
Przechowywana w rejestrze X wartość służy teraz do odczytu
współczynników z tabeli POKTAB. Są one dodawane do zawartości
akumulatora i rejestru Y, po czym otrzymane w rezultacie liczby
zostają przepisane do rejestru CBAUD (Cassette BAUD rate).
Rejestr ten służy do ustalenia częstotliwości generatorów
dźwięku sterujących szybkością transmisji.
0100 ;POKey TABle
0110 ;
0120 *= $EDF9
0130 ;
0140 .BYTE $E8,$03,$43,$04
0150 .BYTE $9E,$04,$F9,$04
0160 .BYTE $54,$05,$AF,$05
0170 .BYTE $0A,$06,$65,$06
0180 .BYTE $C0,$06,$1A,$07
0190 .BYTE $75,$07,$D0,$07
|