← ST-Computer 09 / 1991

Farb-/Mono-Umschaltung per Software

Programmierpraxis

Thomas Mokler / Thomas Peuß

Kennen Sie das auch: Sie sitzen vor Ihrer Textverarbeitung und haben schon mehrere Seiten Text produziert, und Sie wollen sich mit einem Spiel entspannen. also (wenn man keine Umschaltbox HAT), SW-Monitor-Kabel raus und Farbmonitor-Kabel rein (wenn man eine Umschaltbox hat, Schalter umlegen). Bei ersterer Methode geht irgendwann Die Monitor-Buchse flöten, bei Zweiterer muss man ersteinmal die Umschaltbox finden und den Schalter umlegen.

Bei dem Kabelgewirr, das auf manchen Computertischen herrscht, ist es wirklich manchmal schwierig und mit Verrenkungen verbunden, bis man die Umschaltbox gefunden hat, und den Schalter umgelegt hat. Wir haben uns also überlegt wie man den Monitor ohne große Anstrengung umschalten kann (die Maus muß man schon bemühen!).

Der Erkennungs-Pin

Dazu muß man erst einmal wissen, wie der Computer erkennt, ob ein Farb- oder ein SW-Monitor angeschlossen ist. Dazu dient Pin 4 der Monitorbuchse (Abb. 1); ist dieser Pin nicht angeschlossen, geht der Computer von einem Farbmonitor aus. Wenn aber Pin 4 auf Masse liegt, geht der ST von einem Monochrommonitor aus. Dieses Umschalten läßt sich mit einem Schalter machen. Wenn man aber die Monitorbuchse genauer betrachtet, sieht man, daß Pin 3 mit einer Port-Leitung des Soundchips verbunden ist (dieser Pin wird im weiteren GPO= General Purpose Out genannt). Wenn man nun Pin 3 mit Pin 4 verbindet, kann man durch Setzen bzw. Löschen des Bits 6 im Port-A-Register des Soundchips von Farbe auf Monochrom bzw. umgekehrt umschalten. Das würde theoretisch auch funktionieren, wenn dabei kein Reset ausgelöst würde. Allerdings muß der Computer bei einem Farbwechsel das gesamte Betriebssystem an die neue Auflösung anpassen. Das geht nun mal am einfachsten mit einem Reset. Beim Reset wird aber auch das Bit 6 gelöscht, was zur Folge hat, daß man wieder im Monochrommodus landen würde. Dadurch bedingt ist, daß man bei Verwendung unserer Umschaltbox beim Einschalten immer im Monochrommodus landet. Den Schaltplan zur Umschaltbox finden Sie in Abbildung 2.

Unsere Monitorumschaltung macht riesige Probleme, wenn man z.B. Hyper-Density benutzt, da diese Umbauten das Bit 6 (Pin 31) im Soundchip benutzen. Es wäre besser gewesen, die Autoren dieses Artikels hätten für Hyper-Density das Bit 7 im Soundchip gewählt, das absolut unbenutzt ist (das entspricht Pin 30 des Soundchips).

Monitorumschaltung in BASIC

Wir versuchten es als erstes mit Omikron.BASIC, da es den Vorteil hat, daß es Resets abfängt. Es funktionierte auf Anhieb. Dieser Vortest führte zu unserer URUA (Universelle Routine zur Umschaltung der Auflösung; Listing 1). Diese Routine ist sehr nützlich: Man kann sein Farbprogramm auf dem SW-Monitor schreiben (sehr augenschonend) und auf dem Farbmonitor testen. Sie hat nur einen kleinen Schönheitsfehler: wenn man das BASIC nicht in der Auflösung verläßt, in der man es gestartet hat, stürzt der Computer ab.

Diese Version befriedigte uns aber nicht. Wir wollten die Auflösung vom GEM aus umschalten, nicht nur im BASIC. Das Resultat war das hier abgedruckte Assembler-Listing (Listing 2).

Funktionsweise

Zuerst wird die aktuelle Auflösung festgestellt, um festzustellen, ob sie vielleicht nicht schon stimmt. Wenn nicht, werden zuerst die Systemvariablen RESVECTOR und RESVALID gesichert. Dann werden in RESVECTOR die neue Reset-Routine und in RESVALID $31415926(=Pi) geschrieben. Das Pi sorgt dafür, daß im Falle eines Resets durch RESVECTOR gesprungen wird. Als nächstes wird das Port-Bit mit der XBIOS-Funktion ONGIBIT eingeschaltet und auf den Reset gewartet. Tritt dieser nicht auf, ist entweder die Umschaltbox defekt oder nicht angeschlossen und eine entsprechende Meldung wird ausgegeben und das Programm nach einem Tastendruck beendet. In der neuen Reset-Routine wird nun durch die XBIOS-Funktion SETSCREEN die Farbpalette geladen, um die neue Auflösung auch dem Betriebssystem mitzuteilen. Als nächstes werden nun die alte Reset-Adresse und die alte Magienumber wieder in RESVECTOR bzw. RESVALID geschrieben, um auch Routinen, die sich schon vorher in den Vektor eingeklinkt hatten, eine Chance zu geben. Im nächsten Programmschritt wird der Teil der Reset-Routine des ROMs ersetzt, der den Soundchip mit Standardwerten lädt und damit das Port-Bit wieder löscht.

Das Schaltbild

Um den nächsten Schritt zu verstehen, muß man wissen, daß die Reset-Routine des ROMs gleich unsere Routine anspringt, ohne vorher etwas zu tun (nur in A6 wird eine Rücksprungadresse übergeben). Um den Teil zu überspringen, den wir ersetzt haben, muß man auf A6 einen bestimmten Wert addieren, der je nach TOS-Version verschieden ist. Also wird zuerst die TOS-Version abgefragt. Diese steht gleich am Anfang des ROMs an der Adresse $FC0003 (das ROM beginnt bei $FC0000). In D0 erhalten wir die Zahl „hinter dem Komma“, also 0,2 oder 4. Beim STE bzw. TT funktioniert das nicht, da bei diesen Rechnern das ROM nicht mehr bei $FC0000 beginnt und GPO nicht mehr an der Monitorbuchse anliegt. Bei der Berechnung der Einsprungadresse ins ROM kommt uns entgegen, daß die Versionsnummem immer eine Differenz von 2 haben. Wenn wir jetzt auf die Adresse der Tabelle (in A0) einfach den Wert der Versionsnummer addieren, erhalten wir die Adresse, an der die Sprungweite steht. Diese Sprungweite müssen wir jetzt auf A6 addieren. Das alles können wir mit einem Befehl machen, nämlich „adda.l 0 (A0,D0.w),A6“. Diese Adressierungsart nennt man Adreßregister (A0) mit Adreßdistan (in diesem Fall 0) und Index (D0). Bevor wir aber jetzt ins ROM springen, fragen wir ab, ob die alte Magienumber nicht schon Pi war (also $31415926). Ist dies der Fall, war schon vorher eine andere Reset-Routine eingeklinkt, und wir springen sie an. War die Magienumber aber nicht Pi, springen wir einfach an die berechnete Adresse im ROM.

Die Pin-Belegung des Monitorsteckers

Das fertig assemblierte Programm können Sie zum Beispiel in den Auto-Ordner einer Diskette kopieren, wenn die darauf enthaltenen Programme nur auf Farbe laufen. Sie können es aber auch vom Desktop aus starten, und schon landen Sie im Farbmodus.

Aber was, wenn das Programm ausgerechnet nicht auf der Diskette ist, mit der Sie gerade arbeiten? Die Lösung: ein Monitorumschalt-Accessory (Listing 3). Für nicht Assemblersprecher haben wir das Accessory auch als Hexdump für GFA-BASIC abgedruckt (Listing 4). Die Funktionsweise ist identisch mit dem Auto-Ordner-Programm.

Achtung

Wir möchten aber noch eine Warnung aussprechen: Wenn Sie von Farbe auf SW umschalten, liegt eine Bildfrequenz von 71 Hz am Farbmonitor/-fernseher an. Fernseher/Monitore verkraften normalerweise diese überhöhte Frequenz ohne Murren. Monitore und Fernseher älteren Datums bzw. deren Ablenkspulen könnten das aber übelnehmen und sich mit einer Rauchschwade verabschieden. Wir beide betreiben diese Schaltung schon über ein Jahr an unseren STs, ohne daß etwas passiert ist, aber wenn Sie auf Nummer sicher gehen wollen, schalten Sie den Fernseher/Monitor nach der Umschaltung ab. Wenn Sie von SW auf Farbe umschalten, brauchen Sie sich um Ihren SW-Monitor keine Sorgen zu machen, an ihm liegen ja dann 50 bzw. 60Hz an, ausgelegt ist er aber für 71 Hz.

Noch ein Wort zum Schaltplan: Die Pin-Belegung ist beim Stecker wie auf der Grafik gezeigt zu zählen, bei den Buchsengenauspiegelverkehrt! Atari-User, die einen Farbfernseher am HF-Ausgang betreiben, können sich die Buchse für den Farbmonitor sparen. Sie verdrahten nur die Buchse für den SW-Monitor und die Schalter, wie im Schaltplan angegeben.

' Universelle Routine zur Umschaltung des Bildschirms ' by T. Peuß und T. Mokier ' (c) MAXON Computer 1991 Change_Res END DEF PROC Change_Res XBIOS(A_Res!,4) IF A_Res!=2 THEN XBIOS (,30,64) PALETTE $777,$700,$60,$520,$7,$50,$5,$555, $222,$77,$55,$550,$707,$770,$505,$0 ENDIF IF A_Res!<>2 THEN XBIOS (,29,255-64) ENDIF XBIOS (,5, HIGH(-1), LOW(-1), HIGH(-1), LOW(-1),2-A_Res!) RETURN ************************************************** * MONO 2 COLOR V1.1 * * Software zur automatischen Momtorumschaltbox * * * * by Thomas Peuß und Thomas Mokler * * in Assembler mit dem OMIKRON Assembler V1.86 * * * * (c) MAXON Computer 1991 * * * ************************************************** resvector: EQU $042A ;Vector fur RESET resvalid: EQU $0426 ;RESET-Kennungs-Vector xbios: EQU 14 gemdos: EQU 1 pi: EQU $31415926 move.w #4,-(SP) ;aktuelle Auflösung feststellen trap #xbios ;per XBIOS(Getrez) addq.l #2,SP cmp.w #2,D0 ;hoch? bne.s back ;nein —> Prg beenden ;ja —> weiter bsr.s superv ;in Supervisor-Modus lea oldmagic(PC),A0 lea oldres(PC),A1 move.l resvalid,(A0) ;alte "Magicnumber" sichern move.l resvector,(A1) ;alte Resetroutinenadresse sichern move.l #pi,resvalid ;„neue "Magicnumber" eintragen (Pi!!) move.l #newrst, resvector ;neue Resetroutine eintragen move.w #64,-(SP) ;Port B,Bit 6(GPO) einschalten move.w #30,-(SP) ;per XBIOS(Ongibit) trap #xbios addq.l #4,SP move.l #$0FFFFF,D0 ;auf wait: nop dbra D0,wait ;warten pea msg ;wenn kein Reset dann Meldung ausgeben move.w #9,-(SP) ;per GEMDOS(Cconws) trap #gemdos addq.l #6,SP move.w #7,-(SP) ;und auf Taste warten trap #gemdos ;per GEMDOS(Crawcin) addq.l #2,SP bsr.s old_vec ;alte Magicnumber und Resetadresse wieder eintragen bsr.s user ;in User-Modus back: move.w #0,-(SP) ;Prg beenden trap #gemdos ;per GEMDOS(Pterm0) superv: move.l #0,-(SP) ;in Supervisor-Modus schalten move.w #$20,-(SP) ;per GEMDOS(Super) trap #gemdos addq.l #6,SP move.l D0,oldusp rts user: move.l oldusp(PC),-(SP) ;in User-Modus move.w #$20,-(SP) ;per GEMDOS(Super) trap #gemdos addq.l #6,SP rts old_vec:move.l oldres(PC),resvector ;alte Resetadresse in den Vector move.l oldmagic(PC),resvalid ;alte Magicnumber in den Vector rts newrst: move.w #0,-(SP) ;Auflösung umschalten move.l #-1,-(SP) ;per XBIOS(Setscreen) move.l #—1,—(SP) move.w #5, - (SP) trap #xbios lea 12(SP),SP bsr.s old_vec ;alte Magicnumber und Resetadresse wieder eintragen lea -$7800,A0 ;Hier wird ein Teil des ROMs ersetzt damit move.b #7,(A0) ;GPO nicht wieder vom TOS umgeschaltet wird move.b #$C0,2(A0) move.b #$0E,(A0) ;bis hier alles aus dem ROM move.b #$47,2(A0) ;diese Zeile ist geändert move.b $FC0003,D0 ;TOS-Version holen ext.w D0 lea tabelle(PC),A0 ;Adresse der Sprungtabelle holen adda.w 0(A0,D0.w),A6 ;Einsprungadresse ins ROM berechnen cmpi.l #$31415926,oldmagic ;Testen, ob andere Resetroutine vorhanden beq.s another ;ja —> anspringen jmp (A6) ;nein —> ins ROM another:movea.l oldres,A1 ;Routinenadresse holen jmp (A1) ;anspringen DATA msg: DC.B 27,'E' ;Clear Screen DC.B 13,10,"Monitorumschaltbox nicht angeschlossen oder gar defekt?!" DC.B 13,10,"Bitte Taste drücken !", 0 EVEN tabelle: DC.W 62,62,68 ;Sprungweiten für die verschiedenen TOS-Versionen EVEN ;(1 0,1.2,1.4) BSS oldusp: DS.L 0 oldmagic: DS.L 0 oldres: DS.L 0 END ************************************ * * * MONITORUMSCHALTACCESSORY V1.1 * * * * by Thomas Mokler Thomas Peuß * * * * (c) MAXON Computer 1991 * * * ************************************ resvector: EQU $042A resvalid: EQU $0426 TEXT lea stack(PC),SP ;jedem Acc sein Stack lea contrl(PC),A0 ;Accessory als Applikation anmelden move.w #10,(A0) move.w #0,2(A0) move.w #1,4(A0) move.l #0,6(A0) bsr aes move.w intout(PC),appid ;Applikationskennung sichern lea addrin,A2 lea contrl (PC),A0 ;Accessory in Menüleiste eintragen move.w #35,(A0) move.w #1,2(A0) move.w #1,4(A0) move.w #1,6(A0) move.w #0,8(A0) lea intin(PC),A1 move.w appid(PC),(A1) lea accname (PC),A1 move.l A1,(A2) bsr aes move.w intout(PC),accid ;Accessorykennung sichern loop: lea msgbuff(PC),A1 lea addrin(PC),A2 lea contrl(PC),A0 ;auf Ereignis warten move.w #23,(A0) move.w #0,2(A0) move.w #1,4(A0) move.w #1,6(A0) move.w #0,8(A0) move.l A1,(A2) bsr aes lea msgbuff(PC),A1 cmpi.w #40,(A1) beq.s main bne.s loop main: lea txt(PC),A1 bsr form_alert cmp.w #2,D5 bne.s loop move.w #4,-(SP) trap #14 addq.l #2,SP cmp.w #2,D0 bne.s mono color: move.l #0,-(SP) move.w #$20,-(SP) trap #1 addq.l #6,SP lea oldsp(PC),A0 move.l D0,(A0) lea oldmagic(PC),A0 lea oldres(PC),A1 move.l resvalid,(A0) move.l resvector,(A1) move.l #$31415926,resvalid move.l #rst,resvector move.l oldsp(PC),-(SP) move.w #$20,-(SP) trap #1 addq.l #6,SP move.w #64,-(SP) move.w #$1E,-(SP) trap #14 addq.l #4,SP bra.s wait mono: move.w #191,-(SP) move.w #$1D,-(SP) trap #14 addq.l #4,SP wait: move.l #$0FFFFF,D0 wait_loop: nop dbra D0,wait_loop move.l #0,-(SP) move.w #$20,-(SP) trap #1 addq.l #6,SP lea oldsp(PC),A0 move.l D0,(A0) bsr.s resback move.l oldsp(PC),-(SP) move.w #$20,-(SP) trap #1 addq.l #6,SP quit: lea msg(PC),A1 bsr.s form_alert bra loop form_alert: lea contrl(PC),A0 move.w #52,(A0) move.w #1,2(A0) move.w #1,4(A0) move.w #1,6(A0) move.w #0,8(A0) move.w #1,intin move.l A1,addrin bsr.s aes move.w intout(PC),D5 rts resback:move.l oldres(PC),resvector move.l oldmagic(PC),resvalid rts aes: move.l #aespb,D1 move.w #$C8,D0 trap #2 rts rst: move.w #0,-(SP) move.l #-1,-(SP) move.l #-1,-(SP) move.w #5,-(SP) trap #1 lea $0C(SP),SP bsr.s resback lea -$7800,A0 move.b #7,(A0) move.b #$C0,2(A0) move b #$0E,(A0) move.b #$47,2(A0) move.b $FC0003,D0 ext.w D0 lea tabelle,A0 adda.w 0(A0,D0.w),A6 lea oldmagic(PC),A0 cmpi.l #$31415926,(A0) beq.s another jmp (A6) another:movea.l oldres,A1 jmp (A1) DATA tabelle: DC.W 62,62,68 msg: DC.B "[1][Monitorumschaltbox|nicht angeschlossen|oder abgeschaltet ? ]" DC.B "[Abbruch]", 0,0 accname: DC.B ' neuer Monitor',0 ;ACCESSORYNAME txt: DC.B '[2][ (C) 1990 by T. Mokler| und T. Peuß | |Auflösung wirklich wechseln ? ]' DC.B '[Nein|Ja]',0 EVEN aespb: DC.L contrl,global,intin,intout, addrin,addrout BSS oldsp: DS.L 1 oldmagic: DS.L 1 oldres: DS.L 1 appid: DS.W 1 accid: DS.W 1 msgbuff: DS.B 16 contrl: DS.W 1 ;AES DS.W 1 ;INTIN DS.W 1 ;INTOUT DS.W 1 ;ADDRIN DS.W 1 ;ADDROUT global: DS.W 15 intin: DS.W 2 ;WORT-EINGABEN intout: DS.W 2 ;WORT-AUSGABEN addrin: DS.L 2 ;ADR -EINGABEN addrout: DS.L 2 ;ADR -AUSGEBEN DS.L 25 ;STAPEL stack: END ' CHG_REZ ACC Lader filename$= "CHG_REZ.ACC" OPEN "O",1,Filename$ READ Wert REPEAT PRINT #1, CHR$(Wert); Summe=Summe+Wert READ Wert UNTIL Wert=-1 READ Pruefsumme IF Pruefsumme<>Summe THEN PRINT "Fehler In Datas” ENDIF CLOSE(1) Data 96, 26, 0, 0, 2, 16, 0, 0, 0, 214 Data 0, 0, 0, 196, 0, 0, 0, 0, 0, 0 Data 0, 0, 0, 0, 0, 0, 0, 0, 79, 250 Data 3, 168, 65, 250, 3, 0, 48, 188, 0, 10 Data 49, 124, 0, 0, 0, 2, 49, 124, 0, 1 Data 0, 4, 33, 124, 0, 0, 0, 0, 0, 6 Data 97, 0, 1, 130, 51, 250, 3, 12, 0, 0 Data 2, 242, 69, 249, 0, 0, 3, 54, 65, 250 Data 2, 210, 48, 188, 0, 35, 49, 124, 0, 1 Data 0, 2, 49, 124, 0, 1, 0, 4, 49, 124 Data 0, 1, 0, 6, 49, 124, 0, 0, 0, 8 Data 67, 250, 2, 218, 50, 186, 2, 154, 67, 250 Data 2, 5, 36, 137, 97, 0, 1, 66, 51, 250 Data 2, 204, 0, 0, 2, 244, 67, 250, 2, 136 Data 69, 250, 2, 196, 65, 250, 2, 144, 48, 188 Data 0, 23, 49, 124, 0, 0, 0, 2, 49, 124 Data 0, 1, 0, 4, 49, 124, 0, 1, 0, 6 Data 49, 124, 0, 0, 0, 8, 36, 137, 97, 0 Data 1, 12, 67, 250, 2, 90, 12, 81, 0, 40 Data 103, 2, 102, 198, 67, 250, 1, 201, 97, 0 Data 0, 176, 186, 124, 0, 2, 102, 184, 63, 60 Data 0, 4, 78, 78, 84, 143, 176, 124, 0, 2 Data 102, 86, 47, 60, 0, 0, 0, 0, 63, 60 Data 0, 32, 78, 65, 92, 143, 65, 250, 2, 20 Data 32, 128, 65, 250, 2, 18, 67, 250, 2, 18 Data 32, 185, 0, 0, 4, 38, 34, 185, 0, 0 Data 4, 42, 35, 252, 49, 65, 89, 38, 0, 0 Data 4, 38, 35, 252, 0, 0, 1, 178, 0, 0 Data 4, 42, 47, 58, 1, 230, 63, 60, 0, 32 Data 78, 65, 92, 143, 63, 60, 0, 64, 63, 60 Data 0, 30, 78, 78, 88, 143, 96, 12, 63, 60 Data 0, 191, 63, 60, 0, 29, 78, 78, 88, 143 Data 32, 60, 0, 15, 255, 255, 78, 113, 81, 200 Data 255, 252, 47, 60, 0, 0, 0, 0, 63, 60 Data 0, 32, 78, 65, 92, 143, 65, 250, 1, 166 Data 32, 128, 97, 76, 47, 58, 1, 158, 63, 60 Data 0, 32, 78, 65, 92, 143, 67, 250, 0, 194 Data 97, 4, 96, 0, 255, 18, 65, 250, 1, 168 Data 48, 188, 0, 52, 49, 124, 0, 1, 0, 2 Data 49, 124, 0, 1, 0, 4, 49, 124, 0, 1 Data 0, 6, 49, 124, 0, 0, 0, 8, 51, 252 Data 0, 1, 0, 0, 3, 46, 35, 201, 0, 0 Data 3, 54, 97, 24, 58, 58, 1, 164, 78, 117 Data 35, 250, 1, 90, 0, 0, 4, 42, 35, 250 Data 1, 78, 0, 0, 4, 38, 78, 117, 34, 60 Data 0, 0, 2, 206, 48, 60, 0, 200, 78, 66 Data 78, 117, 63, 60, 0, 0, 47, 60, 255, 255 Data 255, 255, 47, 60, 255, 255, 255, 255, 63, 60 Data 0, 5, 78, 65, 79, 239, 0, 12, 97, 196 Data 65, 249, 255, 255, 136, 0, 16, 188 0, 7 Data 17, 124, 0, 192, 0, 2, 16, 188, 0, 14 Data 17, 124, 0, 71, 0, 2, 16, 57, 0, 252 Data 0, 3, 72, 128, 65, 249, 0, 0, 2, 16 Data 220, 240, 0, 0, 65, 250, 0, 238, 12, 144 Data 49, 65, 89, 38, 103, 2, 78, 214, 34, 121 Data 0, 0, 2, 238, 78, 209, 0, 62, 0, 62 Data 0, 68, 91, 49, 93, 91, 77, 111, 110, 105 Data 116, 111, 114, 117, 109, 115, 99, 104, 97, 108 Data 116, 98, 111, 120, 124, 110, 105, 99, 104, 116 Data 32, 97, 110, 103, 101, 115, 99, 104, 108, 111 Data 115, 115, 101, 110, 124, 111, 100, 101, 114, 32 Data 97, 98, 103, 101, 115, 99, 104, 97, 108, 116 Data 101, 116, 32, 63, 32, 93, 91, 65, 98, 98 Data 114, 117, 99, 104, 93, 0, 0, 32, 32, 110 Data 101, 117, 101, 114, 32, 77, 111, 110, 105, 116 Data 111, 114, 0, 91, 50, 93, 91, 32, 32, 32 Data 32, 40, 67, 41, 32, 49, 57, 57, 48, 32 Data 98, 121, 32, 84, 46, 32, 77, 111, 107, 108 Data 101, 114, 124, 32, 32, 32, 32, 32, 32, 32 Data 117, 110, 100, 32, 84, 46, 32, 80, 101, 117 Data 158, 32, 124, 32, 124, 65, 117, 102, 108, 153 Data 115, 117, 110, 103, 32, 119, 105, 114, 107, 108 Data 105, 99, 104, 32, 119, 101, 99, 104, 115, 101 Data 108, 110, 32, 63, 32, 93, 91, 78, 101, 105 Data 110, 124, 74, 97, 93, 0, 0, 0, 3, 6 Data 0, 0, 3, 16, 0, 0, 3, 46, 0, 0 Data 3, 50, 0, 0, 3, 54, 0, 0, 3, 62 Data 0, 0, 0, 40, 6, 58, 142, 138, 6, 32 Data 76, 24, 196, 4, 4, 4, 4, 4, 0 Data -1 Data 54487