ST-Tips: ATARI-BIOS-Patch zur Behebung von Fehlern der seriellen Schnittstelle

Ein im AUTO-Ordner abgelegtes Programm eliminiert die Fehler des RTS/CTS-Handshakes sowohl in der PROM- als auch in Disketten-Version der bisherigen TOS-Versionen.

Für viele Besitzer eines Druk-kers mit ausschließlich seriellem Anschluß stellen die BIOS-Fehler in der Behandlung der XON/XOFF- und RTS/ CTS-Handshake-Signale des seriellen Ports ein Ärgernis dar. Wenngleich (fast) alle Textprogramme hier hilfreich eingreifen und einen fehlerfreien Treiber installieren, so ist dieser nur für die Laufzeit der Programme vorhanden. Ein Anklicken eines Textfiles unter GEM-Desktop und die Auswahl „DRUCKEN“ endet jedesmal mit einer Endlos-Schleife in der fehlerhaften Interruptroutine, nur erneutes Booten erweckt den ST wieder zum Leben.

Das kann man zwar umgehen, indem kein Handshake-Protokoll des seriellen Ports aktiviert wird (RS232-Einstellungs-ACC), dafür fehlen dann aber auch garantiert Zeichen auf dem Druckerpapier. Die Gründe für dieses Fehlverhalten des seriellen Ports sind wohl dem Umstand zuzuschreiben, daß ATARI diesen Port 'Modem’ nennt und ihn wohl auch nur in dieser Umgebung ausgetestet hat. Alle seriellen Kopplungen, sei es über ein Modem zu einem anderen Rechner oder nur die lokale Kopplung mit einem Druk-ker, müssen dem Partner mitteilen, wann sie bereit sind, Daten zu empfangen, damit der (serielle) Datenstrom nicht im Nirwana endet. Zu diesem Zweck gibt es die zwei gebräuchlichsten Verfahren XON/XOFF und RTS/CTS.

Im abgedruckten Assemblerlisting sind die Fehler des RTS/CTS-Protokolls behoben. Dieses Protokoll wird auch Hardware-Handshake genannt, da sich die beiden gekoppelten Geräte über zwei zusätzliche Leitungen RTS (request to send) und CTS (clear to send) über die Sende- bzw. Empfangsbereitschaft unterhalten. Bei der Ankopplung eines Druckers spielt nur das Signal CTS eine Rolle, hierrüber teilt der Drucker dem ST mit, wann er in der Lage ist, Zeichen zu empfangen. Dieses Signal wird im ST vom Pin 5 des Steckers der seriellen Schnittstelle auf den Interrupt-Eingang 2 des MFP 68901 (Multifunktionsbaustein) geführt. Ein Pegelwechsel an diesem Eingang führt zu einem Interrupt, der den Prozessor veranlasst, eine mittels Interruptvektor diesem Interrupt zugeordnete Routine auszuführen. Ob eine positive oder negative Flanke diesen Interrupt auslöst, muß im ’active edge register’ des MFP programmiert werden. Ein solcher Interrupt aktiviert die CTS-Interruptroutine. Wird hingegen ein Zeichen gesendet, ebenfalls durch diesen MFP-Baustein, so teilt das Sen-deregister des MEP dem 68000 mittels Interrupt mit, wann es wieder bereit zur Aufnahme eines weiteren zu sendenden Zeichens ist. Dieser Interrupt aktiviert die Sende-Interruptroutine. In der Sende-Interruptroutine muß nun geprüft werden, ob ein fehlendes CTS-Signal vom Drucker die weitere Aussendung von Zeichen verhindert.

Fehlt das CTS-Signal, so darf kein weiteres Zeichen in das Senderegister abgelegt werden, es muß vielmehr auf die Flanke eines wiederkehrenden CTS-Signals gewartet werden. Mittels Disassembler, in diesem Fall mit dem PROFIMAT von DATA BECKER, wurden die entsprechenden Interruptroutinen analysiert und die Fehlerursachen lokalisiert.

In der Sende-Routine verläßt sich der ATARI darauf, daß nach jedem Zeichen das CTS-Signal geht und anschließend (Interrupt-auslösend) wiederkommt. Drucker verhalten sich hier aber anders, sie lassen das CTS-Signal solange gesetzt, bis der interne Puffer voll ist und nehmen dann erst das Signal weg. In der Sende-Interruptroutine muß also das statisch anliegende CTS-Signal überprüft werden; ist es vorhanden, muß ein weiteres Zeichen gesendet werden. Erst ein Fehlen des Signals ist Anlaß, das Zeichensenden zu unterbinden und sich wieder durch einen CTS-Interrupt wecken zu lassen.

In der CTS-Interruptroutine ist ebenfalls ein Fehler: Hier wird abgefragt, ob das Senderegister des MFP bereit zur Aufnahme eines neuen Zeichens ist. Ist es noch nicht bereit, wird in einer Schleife ständig die Sendebereitschaft überprüft. Leider stimmt das Sprungziel in der Schleife nicht, denn es wird immer nur der gerettete Wert des XMIT-Statusregisters abgefragt. Hier wird sich aber nie wieder etwas ändern, und schon ist <man in der schönsten Endlosschleife.

Nachdem die Fehler erkannt waren, wurde eine Möglichkeit zur Behebung gesucht. Da das TOS im PROM war, hätte man neue EPROMS schießen können, was aber ziemlich umständlich, zumal es elegantere Möglichkeiten gibt, die Fehler zu beheben. Es bietet sich an, die betroffenen Interruptroutinen neu zu programmieren und mit einem im AUTO-Ordner abgelegten Programm nach jedem Bootvorgang neu zu installieren. TOS bietet die Möglichkeit, ein Programm resident im Speicher zu belassen, ein Verfahren, das z. B. alle Druckerspooler nutzen. Da die neuen Interruptroutinen sowohl die Fehler im PROM-TOS als auch im Disketten-TOS beheben sollen, muß man sich alle benötigten absoluten Adressen mit BIOS-Aufrufe besorgen.

Hier eine kurze Beschreibung der Vorgehensweise: Zuerst wird in bekannter Weise die Länge des Programms berechnet, dieser Parameter wird beim Verlassen des Programmes mit dem GEM KEEP-Call benötigt. Nach dieser Berechnung wird die Adresse des Puffers geholt, in dem die Sendedaten für die serielle Schnittstelle bereitgestellt werden. Dazu dient der IOREC-XBIOS-Call, dieser liefert in DO einen Pointer auf den Ausgabepuffer zurück. Nach dieser Berechnung wird der Vektor des Sende-Bereit-Interrup-tes (XREADY) auf die neue Interruptroutine umgelegt. Dies geschieht mit dem MFPINT-XBIOS-Call (13). In gleicher Weise wird der Vektor des CTS-Interruptes auf die neue CTS-Interruptroutine umgelegt. Danach kann das Programm mittels KEEP-Call verlassen und zum Desktop zurückgekehrt werden. Die geladenen neuen Interruptroutinen stehen jetzt permanent im Speicher und erleichtern dem Besitzer eines seriell angeschlossenen Druckers das Leben un-gemein. Wenn das Programm dann noch in einen Autoordner geladen wird, können die Probleme (bis zur nächsten TOS-Version) vergessen werden.

Für diejenigen, die keinen Assembler besitzen, ist ein BASIC-Lader abgedruckt.

R. Lange

10  ' V24PATCH.PRG Lader
11  Filename$="V24PATCH.PRG"
12  OPEN "O",1,Filename$
13  READ Wert
14  REPEAT
15      PRINT #1, CHR$(Wert);
16      Summe=Summe+Wert
17      READ Wert
18  UNTIL Wert=-1
19  READ Pruefsumme
20  IF Pruefsumme<>Summe THEN
21      PRINT "Fehler In Datas"
22  ENDIF
23  CLOSE(1)
100 DATA 96,26,0,0,1,26,0,0,0,0
101 DATA 0,0,0,4,0,0,0,0,0,0
102 DATA 0,0,0,0,0,0,0,0,32,111
103 DATA 0,4,44,60,0,0,1,0,220,168
104 DATA 0,12,220,168,0,20,220,168,0,28
105 DATA 63,60,0,0,63,60,0,14,78,78
106 DATA 88,143,35,192,0,0,1,26,47,60
107 DATA 0,0,0,86,63,60,0,10,63,60
108 DATA 0,13,78,78,80,143,47,60,0,0
109 DATA 0,180,63,60,0,2,63,60,0,13
110 DATA 78,78,80,143,66,103,47,6,63,60
111 DATA 0,49,78,65,72,231,32,224,97,0
112 DATA 0,162,8,40,0,1,0,32,102,0
113 DATA 0,68,8,40,0,0,0,32,103,0
114 DATA 0,10,74,40,0,31,102,0,0,38
115 DATA 17,105,0,44,0,29,52,40,0,20
116 DATA 180,104,0,22,103,0,0,20,97,0
117 DATA 0,126,36,104,0,14,19,114,32,0
118 DATA 0,46,49,66,0,20,8,169,0,2
119 DATA 0,14,76,223,7,4,78,115,8,41
120 DATA 0,2,0,0,102,236,96,180,72,231
121 DATA 32,224,97,0,0,68,8,40,0,1
122 DATA 0,32,103,0,0,46,17,105,0,44
123 DATA 0,29,8,40,0,7,0,29,103,242
124 DATA 52,40,0,20,180,104,0,22,103,0
125 DATA 0,20,97,0,0,42,36,104,0,14
126 DATA 19,114,32,0,0,46,49,66,0,20
127 DATA 8,169,0,2,0,16,76,223,7,4
128 DATA 78,115,32,121,0,0,1,26,67,249
129 DATA 0,255,250,1,78,117,82,66,180,104
130 DATA 0,18,101,0,0,4,116,0,78,117
131 DATA 0,0,0,36,6,18,196,0 
9998 DATA -1
9999 DATA 14977


Adresse Zielcode    Quelltext

000000 :            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
000000 :            ;                                      ;
000000 :            ; PATCH-PROGRAMM ZUR BEHEBUNG DER FEHLER IN DEN HANDSHAKE-
000000 :            ; PROTOKOLLEN DER SERIELLEN SCHNITTSTELLE IM ROM-TOS
000000 :            ;                                      ;
000000 :            ;   R. LANGE                           ;
000000 :            ;                                      ;
000000 :            ;   V15/03/87                          ;
000000 :            ;                                      ;
000000 :            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
000000 :            ;                                      ;
000000 :            ; DA DAS PROGRAMM RESIDENT BLEIBEN SOLL;
000000 :            ; ZUERST DIE LAENGE BERECHNEN          ;
000000 :            ;                                      ;
000000 :206F0004    BEGIN   MOVE.L 4(SP),A0 ; BASEPAGE ADDRES TO A0
000004 :2C3C00000100    MOVE.L  #$100,D6    ; BASE PAGE LENGTH TO D6
00000A :DCA8000C        ADD.L   $0C(A0),D6  ; ADD TEXT LENGTH
00000E :DCA80014        ADD.L   $14(A0),D6  ; ADD DATA LENGTH
000012 :DCA8001C        ADD.L   $1C(A0),D6  ; ADD BSS LENGTH
000016 :            ;
000016 :            ; IN D6 IST JETZT DIE PROGRAMMLAENGE ABGELEGT
000016 :            ;
000016 :            ; JETZT DEN POINTER AUF DEN AUSGABEPUFFER (IOREC) HOLEN
000016 :            ;
000016 :3F3C0000        MOVE.W  #0,-(SP)    ; DEVICE 0 = RS232
00001A :3F3C0OOE        MOVE.W  #14,-(SP)   ; IOREC (14)
00001E :4E4E            TRAP    #14 ; XBIOS CALL
000020 :588F            ADDQ.L  #4,SP   ; STACK JUSTIFY
000022 :23C00000011A    MOVE.L  D0,IOREC    ; POINTER TO OUTBUFFER
000028 :            ;
000028 :            ;
000028 :            ; INTERRUPT-VEKTOR DES XREADY-INTERRUPTES AUF NEUE ROUTINE LEGEN
000028 :            ;
000028 :2F3C00000056    MOVE.L  #XRDY_INT,-(SP) ; NEW ADDRESS OF I-ROUTINE
00002E :3F3C000A        MOVE.W  #10,-()SP)  ; XRDY * MFP-INTERRUPT #10
000032 :3F3C0OOD        MOVE.W  #13,-(SP)   ; MFPINT (13) XBIOS-CALL
000036 :4E4E            TRAP    #14
000038 :508F            ADDQ.L  #8.SP   ; STACK JUSTIFY
00003A :            ;
00003A :            ; INTERRUPT-VEKTOR DES CTS-INTERRUPTES AUF NEUE ROUTINE LEGEN
00003A :            ;
00003A :2F3C000000B4    MOVE.L  #CTS_INT,-(SP)  ; NEW ADDRESS OF I-ROUTINE
000040 :3F3C0002        MOVE.W  #2,-(SP)    ; CTS = MFP-INTERRUPT #2
000044 :3F3C000D        MOVE.W  #13,-(SP)   ; MFPINT (13) XBIOS-CALL
000048 :4E4E            TRAP    #14
00004A :508F            ADDQ.L  #8,SP       ; STACK JUSTIFY
00004C :            ;
0000D4 :34280014        MOVE.W  $14(A0),D2  ; HEAD INDEX
0000D8 :B4680016        CMP.W   $16(A0),D2  ; COMPARF. WITH TAIL INDEX
0000DC :67000014        BEQ CTS2    ; TRANSMIT BUFFER EMPTY
0000E0 :6100002A        BSR WRAP    ; CHECK IF WRAP ARROUND
0000E4 :2468000E        MOVE.L  $E(A0),A2   ; SET POINTER TO XMIT-BUFFER
0000E8 :13722000002E    MOVE.B  $0(A2,D2.W),$2E(A1) ; BYTE TO MFP XMIT-REGISTER
0000EE :31420014        MOVE.W  D2,$14(A0)  ; NEW HEAD INDEX TO IOREC
0000F2 :08A900020010    CTS2    BCLR    #2,$10(A1)  ; CLEAR INTERRUPT SERVICE BIT
0000F8 :4CDF0704        MOVEM.L (SP)+,D2/A0-A2  ; RESTORE REGISTER
0000FC :4E73            RTE ; EXIT INTERRUPT SERVICE
0000FE :            ;
0000FE :            ;
0000FE :            ; GETPTR LIEFERT RS232 IOREC ADRESSE ($D8E IM ROM-BIOS) IN A0
0000FE :            ; UND   MFP-    ADRESSE IN  Al
0000FE :            ;
0000FE :20790000011A    GETPTR  MOVE.L  IOREC,A0
000104 :43F900FFFA01            LEA $FFFA01,A1
00010A :4E75                    RTS
00010C :
00010C :                ; WRAP TESTET AUF WRAP AROUND
00010C :                ;
00010C :5242            WRAP    ADDQ.W  #1,D2   ; TAIL INDEX +1
00010E :B4680012                CMP.W   $12(A0),D2  ; = MAX BUFFERSIZE ?
000112 :65000004                BCS WRAP1   ; NO
000116 :7400                    MOVEQ.L #0,D2   ; YES SET TO    BEGIN
000118 :4E75            WRAP1   RTS
00011A :                ;
00011A :                ;
00011A :                ; DAS WAR's !
00011A :                ;
00011A :                ;
00011A :                ;
00011A :                        BSS
00011A :    4           IOREC   DS.L    1
00011A :                        DATA
00011A :                        END

Variablentabelle

BEGIN = 00000000
CTS1 = 000000C6
CTS2 - 000000F2
CTS_INT = 00000064
GETPTR = 000000FE
IOREC = 0000011A
RTS_CTS = 000000AA
WRAP = 0000010C
WRAP1 = 00000118
XRDYO - 00000068

00004C :                ; NUN DAS PROGRAMM MIT GEMDOS KEEP AUFRUF RESIDENT HALTEN
00004C :                ;
00004C :4267                        CLR     -(SP)
00004E :2F06                        MOVE.L  D6,-(SP)    ; PROGRAM LENGTH
000050 :3F3C0031                    MOVE    #$31,-(SP)  ; GEM KEEP-CALL ($31)
000054 :4E41                        TRAP    #1  ; RETURN TO DESKTOP
000056 :                ;
000056 :                ;
000056 :                ; NEUE XRDY-INTERRUPTROUTINE
000056 :                ;
000056 :48E720E0        XRDY_INT    MOVEM.L D2/A0-A2,-(A7)  ; SAVE  REGISTER
00005A :610000A2                    BSR GETPTR  ; GET POINTER FROM IOREC
00005E :082800010020                BTST    #1,$20(A0)  ; RTS/CTS MODE ?
000064 :66000044                    BNE RTS_CTS ; YES
000068 :082800000020    XRDY0       BTST    #0,$20(A0)  ; XON/XOFF  MODE ?
00006E :6700000A                    BEQ XRDY1   ; NO
000072 ;4A28001F                    TST.B   $1F(A0) ; XOFF ACTIV-FLAG SET ?
000076 :66000026                    BNE XRDY2   ; YES
Adresse Zielcode    Quelltext

00007A :1169002C001D    XRDY1       MOVE.B  $2C(A1).$1D(A0) ; XMIT-STATUS TO IOREC
000080 :34280014                    MOVE.W  $14(A0),D2  ; HEAD INDEX
000084 :B4680016                    CMP.W   $16(A0),D2  ; COMPARE WITH TAIL INDEX
000088 :67000014                    BEQ XRDY2   :   TRANSMIT-BUFFER EMPTY
00008C :6100007E                    BSR WRAP    ; CHECK IF WRAP ARROUND
000090 :2468000E                    MOVE.L  $E(A0),A2   ; SET POINTER TO XMIT-BUFFER
000094 :13722000002E                MOVE.B  $0(A2,D2.W),$2E(A1) ; BYTE TO MFP XMIT-REGISTER
00009A :31420014                    MOVE.W  D2.$14(A0)  ; NEW HEAD INDEX TO IOREC
00009E :08A90002000E    XRDY2       BCLR    #2,$E(A1)   ; CLEAR INTERRUPT SERVICE BIT
0000A4 :4CDF0704                    MOVEM.L (A7)+,D2/A0-A2 ; RESTORE REGISTER
0000A8 :4E73                        RTE ; EXIT INTERRUPT SERVICE
0000AA :                ;
0000AA :                ; HIER IST DIE EIGENTLICHE KORREKTUR
0000AA :                ;
0000AA :082900020000    RTS_CTS     BTST    #2,0(A1)    ; CHECK IF CTS ACTIV
0000B0 :66EC                        BNE XP.DY2      ;   NO, WAIT FOR CTS-INTERRUPT
0000B2 :60B4                        BP.A    XRDYO   ; YES, OK SEND BYTE
0000B4 :                ;
0000B4 :                ;
0000B4 :                ; NEUE  CTS-INTERRUPTROUTINE
0000B4 :                ;
0000B4 :48E720E0        CTS_INT     MOVEM.L D2/A0-A2,-(SP)  ; SAVE REGISTER
0000B8 :61000044                    BSR GETPTR  ; GET POINTER FROM IOREC
0000BC :082800010020                BTST    #1,$20(A0)  ; RTS/CTS MODE ?
0000C2 :6700002E                    BEQ CTS2    ; NO, IGNORE INTERRUPT
0000C6 :1169002C001D    CTS1        MOVE.B  $2C(A1),$1D(A0) ; XMIT-STATUS TO IOREC
0000CC :08280007001D                BTST    #7,$1D(A0)  ; XMIT-REGISTER EMPTY ?
0000D2 :67F2                        BEQ CTS1    ; NO. WAIT

XRDY1 = 0000007A 
XRDY2 = 0000009E 
XRDY_INT = 00000056


Links

Copyright-Bestimmungen: siehe Über diese Seite
Classic Computer Magazines
[ Join Now | Ring Hub | Random | << Prev | Next >> ]