Tajemnice ATARI

CIO


    Zgodnie z obietnicą zawartą w pierwszym odcinku poświęconym systemowej procedurze CIO, poniższy artykuł wyjaśni działanie operacji transmisji danych (odczytu oraz zapisu), a także opisze wywołanie procedur STATUS oraz operacji specjalnych (SPECIAL) użytkownika.

  • Początek procedury STATUS lub SPECIAL
    Sprawdź czy IOCB jest zamknięty
    E597 LDA ICHIDZ
    E599 CMP #$FF
    E59B BNE E5A2
    Wywołanie procedury obsługi podanej
    nazwy urządzenia; powrót z ustawionym
    znacznikiem Carry oznacza błąd
    E59D JSR E6FF
    E5A0 BCS E547
    Ustal adres procedury użytkownika
    obsługującej operację STATUS lub SPECIAL
    E5A2 JSR E695
    wywołaj procedurę STATUS lub SPECIAL użytkownika
    E5A6 JSR E6EA
    Ustaw stary status IOCB
    E5A8 LDX ICAX5Z
    E5AA LDA IOCB,X
    E5AD STA ICHIDZ
    Procedura zakończenia obsługi IOCB-u
    E5AF JMP E672
    
        Jak wynika z powyższej procedury, operacje STATUS oraz SPECIAL (dla stacji dysków na przykład kasowanie pliku, zmiana jego nazwy, formatowanie dysku itp.) nie wymagają wcześniejszego otwarcia kanału we/wy. Jeżeli operacja tego typu miała miejsce poprzez zamknięty IOCB, to jej wykonanie nie spowoduje otwarcia kanału, a tym samym nie wymaga późniejszego wykonania operacji zamknięcia IOCB-U. Wywołanie procedury SPECIAL lub STATUS poprzez otwarty kanał we/wy nie spowoduje jego zamknięcia. Oto przykład wykorzystania operacji SPECIAL do skasowania pliku FILENAME.EXT zapisanego na dyskietce umieszczonej w stacji numer 2 (wartości etykiet: patrz poprzedni numer TA):
    RENAME EQU $20 
    DELETE EQU $21
    
    LDX #ICBNUM 
    LDA #DELETE 
    STA ICCOM,X
    LDA <DEVICE
    STA ICBAL,X 
    LDA >DEVICE 
    STA ICBAH,X
    JMP CIOVEC
    
    DEVICE DTA C'D2:FILENAME,EXT',B($9B)
    
  • Początek procedury czytania danych (GET BYTE)
    Sprawdź, czy właściwa komenda odczytu
    E5B2 LDA ICCOMZ
    E5B4 AND ICAX1Z
    E5B6 BHE E5BD
    Błąd: odczyt z kanału we/wy otwartego do
    zapisu jest niemożliwy
    E5B8 LDY #$83
    E5BA JMP E670
    Ustal adres procedury użytkownika
    obsługującej operację GET BYTE; powrót
    z ustawionym znacznikiem Carry oznacza
    błąd
    E5BD JSR E695
    E5C0 BCS E5BA
    Sprawdź, czy przesłać tylko 1 bajt
    E5C2 LDA ICBLLZ 
    E5C4 ORA ICBLHZ
    E5C6 BNE E5D0
    Jeśli długość bufora jest równa 0,
    to prztransmituj tylko 1 bajt; w ten sposób
    można przesyłać dane bez użycia pamięci
    (jedynie przy pomocy rejestru A)
    Wywołaj procedurę GET BYTE użytkownika
    E5C8 JSR E6EA
    Zapamiętaj otrzymaną daną (bajt należy
    przesyłać przez rejestr A)
    E5CB STA ICAX6Z
    Procedura zakończenia obsługi IOCB-U
    E5CD JMP E672
    Początek pętli czytania danych;
    wywołaj procedurę GET BYTE użytkownika
    E5D0 JSR E6EA
    Zapamiętaj otrzymaną daną
    E5D3 STA ICAX6Z
    Jeżeli wystąpił błąd, to zakończ operację
    E5D5 BMI E618
    Uzyskany z urządzenia zewnętrznego bajt
    zapamiętaj pod żądanym przez programistę adresem
    E5D7 LDY #0
    E5D9 STA (ICBALZ),Y
    Zwiększ o 1 adres przesyłanego bajtu
    E5DB JSR E6D1
    Sprawdź, czy komendą jest odczyt aż do
    napotkania znaku końca linii (EOLN=$9B)
    E5DE LDA ICCOMZ
    E5E0 AND #$02
    E5E2 BNE E5F0
    Czy przesłanym bajtem jest znak końca linii
    E5E4 LDA ICAX6Z
    E5E6 CMP #$9B
    E5E8 BNE E5F0
    Zmniejsz o 1 liczbę przesyłanych danych
    E5EA JSR E6BB
    Zakończ operację czytania linii (GET LINE)
    E5ED JMP E618
    Zmniejsz o 1 liczbę przesyłanych danych
    E5F0 JSR E6BB
    Jeśli nie przesłano wszystkich danych,
    to czytaj następny bajt danych
    E5F3 BNE E5D0
    Cały bufor został już wypełniony;
    sprawdź, czy komendą jest odczyt aż do
    napotkania znaku końca linii
    E5F5 LDA ICCOMZ
    E5F7 AND #$02
    E5F9 BNE E618
    Odczytaj dane linii nie mieszczące się w buforze;
    wywołaj procedurę GET BYTE użytkownika
    E5FB JSR E6EA
    E5FE STA ICAX6Z
    Jeżeli wystąpił błąd, to wyjdź z pętli
    E600 BMI E60C
    Czytaj dotąd dane aż napotkasz znak końca linii
    E602 LDA ICAX6Z
    E604 CMP #$9B
    E606 BNE E5FB
    Ustaw status operacji na błąd: próba odczytu
    linii o większej długości niż dozwolona
    E608 LDA #$89
    E60A STA ICSTAZ
    Zmniejsz o 1 adres przesyłanych danych
    E60C JSR E6C8
    Ostatni bajt bufora ustaw na znak końca linii
    E60F LDY #0
    E611 LDA #$9B
    E613 STA (ICBALZ),Y
    Zwiększ o 1 adres przesyłanego bajtu
    E615 JSR E6D1
    Ustal liczbę otrzymanych danych
    E618 JSR E6D8
    Procedura zakończenia obsługi IOCB-U
    E61B JMP E672
    
        Pracowitym programistom polecam koniec niniejszego odcinka o CIO, gdzie zgodnie z obietnicą znajdą radę, jak przyspieszyć transmisję danych przez CIO. Dla tych praktycznych podaję wersję gotowej do wywołania procedury IOCB_GET czytającej dane przez CIO (wartości etykiet: patrz poprzedni numer TA):
    GET_LINE EQU 5 czytaj linię 
    GET BYTE EQU 7 czytaj do wypełnienia bufora 
    ADDRESS  EQU $600 adres umieszczenia danych 
    LENGTH   EQU $100 maksymalna długość bufora
    
    IOCB_GET EQU *
    
    LDX #ICBNUM
    LDA #GET_BYTE może być GET_LINE
    STA ICCOM,X
    LDA <ADDRESS
    STA ICBAL,X
    LDA >ADDRESS
    STA ICBAH,X
    LDA <LENGTH
    STA ICBLL,X
    LDA >LENGTH
    STA ICBLH,X
    JMP CIOVEC
    
        Przykładem wykorzystania procedury GET BYTE może być porównanie sekwencji naciśniętych klawiszy z wzorcowym ciągiem znaków, na przykład z hasłem, które zabezpiecza program przed uruchomieniem przez niepowołane osoby. Wykonujemy procedurę IOCB_OPEN opisaną w poprzednim numerze TA z parametrami: ICBNUM=$10, OPERAT=READ, DEVICE='K:'. Następnie wywołujemy procedurę IOCB_GET, ustawiając parametry: ICBNUM - bez zmian, LENGTH=0, ADDRESS - nieistotny, bo dane będą przesyłane przez rejestr A z pominięciem pamięci komputera. Na końcu wykonujemy operację IOCB_CLOSE z poprzedniego numeru TA. Powrót z procedury PASSWORD ze zgaszonym znacznikiem Carry oznacza wpisanie właściwego hasła:
    ICBNUM EQU $10 
    OPERAT EQU READ (4) 
    LENGTH EQU 0 
    EOLN   EQU $9B
    
    PASSWORD EQU *
    
    LDX #ICBNUM
    JSR IOCB_OPEN
    BMI FAIL otwarcie IOCB-U zakończyło się
    niepomyślnie
    LOOP JSR IOCB_GET
    BMI FAIL błąd odczytu z klawiatury
    LDY PATTERN
    BNE CHECK
    CMP #EOLN naciśnięto RETURN
    BNE LOOP
    FAIL JSR IOCB_CLOSE
    SEC niewłaściwe hasło
    RTS
    CHECK CMP PATTERN,Y A-wpisana dana
    BNE HACK
    INC PATTERN
    CMP #EOLN koniec hasła
    BNE LOOP
    JSR IOCB_CLOSE
    CLC poprawne hasło
    RTS
    HACK LDA #0
    STA PATTERN
    BEQ LOOP skok bezwzględny
    
    PATTERN DTA B (1),C'TAJEMNICE ATARI',B(EOLN) 
    DEVICE DTA C'K:'
    
  • Początek operacji zapisu danych (PUT BYTE)
    Sprawdź, czy właściwa komenda zapisu
    E61E LDA ICCOMZ
    E620 AND ICAX1Z
    E622 BNE E629
    Błąd: zapis przez kanał we/wy otwarty do
    odczytu jest niemożliwy
    E624 LDY #$87
    E626 JMP E670
    Ustal adres procedury użytkownika
    obsługującej operację PUT BYTE; powrót
    z ustawionym znacznikiem Carry oznacza
    błąd
    E629 JSR E695
    E62C BCS E626
    Sprawdź, czy przesłać tylko 1 bajt
    E62E LDA ICBLLZ
    E630 ORA ICBLHZ
    E632 BNE E63A
    Wyślij tę jedną daną
    E634 LDA ICAX6Z
    E636 INC ICBLLZ
    E638 BNE E640 skok bezwzględny
    Pętla wysyłania danych do urządzenia
    zewnętrznego
    Załaduj bajt przeznaczony do przesłania
    E63A LDY #0 
    E63C LDA (ICBALZ),Y 
    E63E STA ICAX6Z 
    Wywołaj procedurę PUT BYTE
    użytkownika; powrót
    z ustawionym znacznikiem
    ujemności oznacza błąd 
    E640 JSR E6EA 
    E643 PHP
    Zwiększ o 1 adres przesyłanego
    bajtu
    E644 JSR E6D1
    Zmniejsz o 1 liczbę 
    przesyłanych danych 
    E647 JSR E6BB
    Odtwórz status wykonanej przez
    użytkownika operacji 
    E64A PLP 
    E64B BMI E66A
    Sprawdź, czy przesyłać dane do 
    napotkania znaku końca linii 
    (PUT LINE) 
    E64D LDA ICCOHZ 
    E64F AND #$02 
    E651 BNE E659
    czy to jest koniec linii? 
    E653 LDA ICAX6Z 
    E655 CMP #$9B 
    E657 BEQ E66A 
    Sprawdź, czy przesłano 
    wszystkie dane 
    E659 LDA ICBLLZ 
    E65B ORA ICBLHZ 
    E65D BNE E63A
    Jeśli wysłano cały bufor, 
    a operacją jest PUT LINE i nie 
    napotkano znaku EOLN, to wyślij
    ten znak końca linii 
    E65F LDA ICCOMZ 
    E661 AND #$02 
    E663 BNE E66A 
    E665 LDA #$9B
    Wywołaj procedurę PUT BYTE 
    użytkownika 
    E667 JSR E6EA
    Ustal liczbę wysłanych danych 
    E66A JSR E6D8
    Procedura zakończenia obsługi IOCB-U 
    E66D JMP E672
    
        Procedura wysyłająca dane do urządzenia zewnętrznego może wyglądać tak:
    PUT_LINE EQU 9 zapisz linię 
    PUT_BYTE EQU 11 zapisz cały bufor 
    ADDRESS  EQU $600 adres
    pobierania danych 
    LENGTH   EQU $100 maksymalna 
    długość bufora
    
    IOCB_GET EQU *
    
    LDX #ICBNUM
    LDA #PUT_BYTE może być PUT_LINE
    STA ICCOM,X
    LDA <ADDRESS
    STA ICBAL,X
    LDA >ADDRESS
    STA ICBAH,X
    LDA <LENGTH
    STA ICBLL,X
    LDA >LENGTH
    STA ICBLH,X
    JMP CIOVEC
    
        Przykład wykorzystania procedury PUT BYTE: na ekranie wypisywana jest zawartość pamięci o wskazanym adresie (ADDRESS) i o długości do 256 bajtów. Znaki są wypisywane w kodzie ATASCII.
    ICBNUM EQU $10 
    OPERAT EQU WRITE (8) 
    LENGTH EQU 0 
    BELL   EQU $F556
    
    DISPLAY EQU *
    
    LDX #ICBNUM
    JSR IOCB_OPEN
    BHI QUIT
    LDY #0
    LOOP TYA
    PHA
    LDA ADDRESS,Y
    AND #$7F
    CMP #$1B
    BCC OK
    CMP #$20
    BCC SPEC
    CMP #$7D
    BCC OK
    SPEC LDA #$lB
    JSR IOCB_PUT
    BMI FAIL
    OK PLA
    PHA
    TAY
    LDA ADDRESS,Y
    JSR IOCB_PUT
    BMI FAIL
    PLA
    TAY
    INY
    BNE LOOP
    QUIT JMP IOCB_CLOSE
    FAIL PLA
    JSR BELL
    JMP IOCB_CLOSE
    
    DEVICE DTA C'E:'
    
  • Procedury wykorzystywane przez CIO w operacjach przesyłania danych.
    Procedura zmniejszenia
    o 1 liczby przesyłanych danych
    E6BB LDA ICBLLZ
    E6BD BNE E6C1
    E6BF DEC ICBLHZ
    E6C1 DEC ICBLLZ
    E6C3 LDA ICBLLZ
    E6C5 ORA ICBLHZ
    E6C7 RTS
    
    Procedura zmniejszenia
    o 1 adresu przesyłanych danych
    E6C8 LDA ICBALZ
    E6CA BNE E6CE
    E6CC DEC ICBAHZ
    E6CE DEC ICBALZ
    E6D0 RTS
    
    Procedura zwiększająca adres
    przesyłanego bajtu
    E6D1 INC ICBALZ
    E6D3 BNE E6D7
    E6D5 INC ICBAHZ
    E6D7 RTS
    
    Procedura ustalająca liczbę
    przesłanych danych
    E6D8 LDX ICAX5Z
    E6DA SEC
    E6DB LDA ICBLL,X
    E6DE SBC ICBLLZ
    E6E0 STA ICBLLZ
    E6E2 LDA ICBLH,X
    E6E5 SBC ICBLHZ
    E6E7 STA ICBLHZ
    E6E9 RTS
    
        Przykładem wykorzystania jednoczesnego czytania i zapisywania danych może być rozwiązanie problemu zakodowania danych pliku. Załóżmy, że plik LIST.TXT zawiera tekst, który chcemy zaszyfrować. Zmieńmy wszystkie dane w tym pliku, odwracając ich niektóre bity, a potem zapiszmy je do innego pliku, na przykład LIST.COD:
    ICBNH1 EQU $10 
    ICBNM2 EQU $20 
    OPEN   EQU 3 
    CLOSE  EQU 12 
    GETBYT EQU 7
    PUTBYT EQU 11
    READ   EQU 4
    WRITE  EQU 8
    EOFFIL EQU 136
    MASK   EQU $FF
    BELL  EQU $F556 brzęczyk
    
    Otwórz plik do odczytu
    LDX #ICBNMl
    LDA #OPEN
    STA ICCOM,X
    LDA <SOURCE
    STA ICBAL,X
    LDA >SOURCE
    STA ICBAH,X
    LDA #READ
    STA ICAX1,X
    JSR CIOVEC
    BMI ERROR
    Otwórz plik do zapisu
    LDX #ICBNM2
    LDA #OPEN
    STA ICCOM,X
    LDA <DSTNTN
    STA ICBAL,X
    LDA >DSTNTN
    STA ICBAH,X
    LDA #WRITE
    STA ICAX1,X
    JSR CIOVEC
    BMI ERROR
    Czytaj bajt
    LOOP LDX #ICBNMl
    LDA #GETBYT
    STA ICCOM,X
    LDA #0
    STA ICBLL,X
    STA ICBLH,X
    JSR CIOVEC
    BPL CRRCT
    CPY #EOFFIL
    BEQ ENDLP
    Zadźwięcz gdy błąd
    ERROR JSR BELL
    Zamknij kanały WE/WY
    ENDLP LDX #ICBNMl
    LDA #CLOSE
    STA ICCOM,X
    JSR CIOVEC
    BMI ENDLP
    LDX #ICBNM2
    LDA #CLOSE
    STA ICCOM,X
    JMP CIOVEC
    Zmień bajt
    CRRCT EOR #MASK
    Zapisz bajt
    TAY
    LDX #ICBNM2
    LDA #PUTBYT
    STA ICCOM,X
    LDA #0
    STA ICBLL,X
    STA ICBLH,X
    TYA
    JSR CIOVEC
    BPL LOOP
    BMI ERROR
    
        Teraz obiecana informacja dla programistów piszących sterowniki urządzeń zewnętrznych. Jak łatwo zauważyć, procedury transmisji danych (GET BYTE i PUT BYTE) są tak skonstruowane, że sprawdzają określone warunki, wywołują ewentualnie procedurę użytkownika przesyłającą 1 bajt i krążą w pętli, uaktualniając swoje wskaźniki. Przeniesienie koniecznych sekwencji rozkazów (zmiana adresu transmitowanego bajtu, ilości danych do przesłania) do własnej procedury GET lub PUT przyspieszy przepływ danych, symulując rutynowe działania CIO.

    Lesław Pasternak



  • Powrót na start | Powrót do spisu treści | Powrót na stronę główną

    Pixel 2002