CIOZgodnie 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. 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 E672Jak 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) 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 E672Pracowitym 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 CIOVECPrzykł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:' 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 E672Procedura 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 CIOVECPrzykł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:' 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 RTSPrzykł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 ERRORTeraz 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
|