Powrót do spisu treści

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
Zientara Wojciech: Mapa pamięci Atari XL/XE. Procedury wejścia-wyjścia, SOETO, Warszawa, 1988.