Wer auf seinem Falcon des öfteren TOS-Programme benutzt, dem wird vielleicht aufgefallen sein, daß die Bildschirmausgabe nicht immer korrekt ist. Der folgende Artikel beschreibt die Probleme und bietet ein Listing, das eine Korrektur des VT52-EmuIators vornimmt.
Der wohl deutlichste Fehler tritt bei der normalen Textausgabe auf (auch im Raw-Modus): Befindet sich der Cursor in der unteren rechten Bildschirmecke, wird plötzlich nach jedem weiteren Zeichen gescrollt, so daß pro Zeile nur noch ein Buchstabe steht. Dies ist insbesondere bei solchen Programmen mehr als störend, die längere Listen ohne Zeilenumbruch ausgeben, da die Bildschirmausgabe schlicht unlesbar wird.
Des weiteren funktionieren einige der Escape-Sequenzen nicht mehr, was unter Umständen zu völlig zerstörten Bildschirmmasken führen kann. Im einzelnen sind dies ESC b (Setzen der Vordergrundfarbe), ESC c (Setzen der Hintergrundfarbe), ESC j (Cursor-Position speichern) und ESC k (gespeicherte Cursor-Position abrufen).
Anscheinend haben sich in der Eile der Falcon-TOS-Entwicklung unbemerkt ein paar Fehler eingeschlichen. Abhilfe schafft die Verwendung von NVDI 2.5 oder das im folgenden beschriebene Listing.
Um die Unzulänglichkeiten der Falcon-Bildschirmausgabe zu beseitigen, muß man in das Betriebssystem eingreifen. Dazu sollte man zunächst wissen, daß nur die BIOS-Textausgabe (per Bconout) abgefangen werden muß, da sämtliche GEM-DOS-Ausgaberoutinen intern auf das BIOS zurückgreifen (das BIOS ist die unterste Betriebssystemebene). Man könnte sich also nun in den BIOS-Trap einhängen und den Bconout-Aufruf abfangen, doch es geht noch einfacher: Seit TOS 1.02 existiert eine Tabelle mit Zeigern auf Routinen, die das BIOS für die einzelnen Ausgabegeräte bei Bconstat, Bconin, Bcostat und Bconout benutzt. Somit müssen in dieser Tabelle nur die beiden Zeiger auf die Bconout-Routinen für CON: und RAWCON: umgebogen werden, was selbstverständlich per XBRA geschehen sollte.
In der eingeklinkten CON:-Routine wird nun geprüft, ob eine der fehlerhaften Escape-Sequenzen ausgeführt werden soll.
Wenn ja, wird diese durch eine eigene, korrigierte Funktion ersetzt. Um das erstgenannte Problem zu beseitigen, das auch im Raw-Modus auftritt, muß man wissen, was hier überhaupt schiefläuft: Nach dem Erreichen des unteren rechten Bildschirmrands wird die X-Cursor-Position auf einen viel zu großen Wert gesetzt, so daß das BIOS meint, der Cursor befände sich immer noch am Rand, obwohl er ja eigentlich wieder am Zeilenanfang steht. Also wird beim nächsten Zeichen gleich wieder gescrollt, was natürlich falsch ist. Beheben läßt sich dies, indem man vor jeder Zeichenausgabe prüft, ob die horizontale Cursor-Position größer als der Maximalwert ist. Wenn ja, muß sie auf Null gesetzt werden.
Das Listing benötigt die negativen Line-A-Variablen, da nur hier die aktuelle Cursor-Position ermittelt und die Vorder- bzw. Hintergrundfarbe gesetzt werden kann. Dabei werden auch Schreibzugriffe vorgenommen, was laut Dokumentation [2] nicht erlaubt, hier aber leider nicht zu vermeiden ist, da nur so eine Korrektur möglich ist.
Leider verlangsamt sich die Zeichenausgabe durch die eingehängten Routinen geringfügig, was man jedoch verschmerzen kann, da sie nun endlich wieder so funktioniert, wie sie sollte.
Literatur:
[1] Jankowski/Rabich/Reschke, ATARI Profibuch ST-STE-TT, SYBEX-Verlag GmbH, Düsseldorf, 1991 (besonders Teil I, Kapitel 1, Abschnitt 2: Zeichenorientierte Funktionen)
;***********************************************
;* Modulname : VT52FIX.S *
;* (C)1994 by MAXON-Computer *
;* Autor : Thomas Binder *
;* Zweck : TSR-Programm, das einige *
;* Fehler in der VT52-Emula- *
;* tion des Falcon030 behebt *
;* Compiler : Pure Assembler 03.02.1992 *
;* Erstellt am : 02.01.1994 *
;* Letzte Änderung: 10.01.1994 *
;***********************************************
super
mc68030
equ _longframe,$59e
equ xconout,$57e
text
; Ist VT52FIX bereits installiert?
pea is_installed(pc)
move.w #38,-(sp) ; Supexec
trap #14
addq.l #6,sp
tst.w d0
bne already_installed
; Ist der Rechner wirklich ein F030?
pea check_f030(pc)
move.w #38,-(sp) ; Supexec
trap #14
addq.l #6,sp
tst.w d0
beq no_falcon
; Routinen einklinken
pea install(pc)
move.w #38,-(sp) ; Supexec
trap #14
addq.l #6,sp
; Anfangsadresse der Line-A-Variablen merken
aline #0
move.l d0,lineavar
; Erfolgsmeldung ausgeben
pea patch_text (pc)
move.w #9,-(sp) ; Cconws
trap #1
addq.l #6,sp
; Größe des resident zu haltenden Speicherbereichs
; berechnen und Programm mit Ptermres beenden
move.l #$100,d0
move.l 4(sp),a0
add.l $c(a0),d0
add.l $14(a0),d0
add.l $1c(a0),d0
clr.w -(sp)
move.l d0,-(sp)
move.w #49,-(sp) ; Ptermres
trap #1
; Meldung ausgeben, daß die Routine bereits in-
; stalliert ist
already_installed:
pea already_installed_text(pc)
bra.s out
; Meldung ausgeben, daß der Rechner kein Falcon
; ist
no_falcon:
pea no_falcon_text(pc)
out:
move.w #9,-(sp) ; Cconws
trap #1
; Programm verlassen
clr.w -(sp) ; Pterm0
trap #1
; Die neue conout-Routine
dc.b "XBRAVTFX"
old_conout:
dc.l 0
new_conout:
move.l sp,a0
; wenn wir noch nicht in einer Escape-Sequenz
; sind, das Zeichen "normal" behandeln
tst.w in_escape(pc)
beq normal_char
; ansonsten prüfen, ob mit diesem Zeichen die
; Sequenz festgelegt wird
addq.w #1,escape_count
cmpi.w #1,escape_count(pc)
bne continue_escape
; Escape-Sequenz beginnt, ist es eine, die korri-
; giert werden muß?
cmpi.b #'j',7(a0) ; save cursor position
bne.s 11
; Bei ESC j die aktuelle Cursorposition aus den
; negativen Line-A-Variablen auslesen
move.l lineavar(pc),a1
move.l -$1c(a1),saved_curpos
; Jeweils 32 addieren, da ESC k spater durch ESC Y emuliert wird
addi.l #$200020,saved_curpos
clr.w 6(a0)
clr.w in_escape
bra back
11:
cmpi.b #'k',7(a0) ; restore cursor position
bne.s l2
; Die gespeicherte Cursorposition wird per ESC Y
; angesprungen
move.w #'Y',-(sp)
move.w #2,-(sp)
bsr old_out
addq.l #4,sp
move.w saved_curpos+2(pc),-(sp)
move.w #2,-(sp)
bsr old_out
addq.l #4,sp
move.w saved_curpos(pc),-(sp)
move.w #2,-(sp)
bsr.s old_out
addq.l #4,sp
; Gespeicherte Position löschen, da nach VT52-
; Konvention die gesicherte Position durch ESC k
; verloren geht
move.l #$200020,saved_curpos
clr.w in_escape
rts
12:
cmpi.b #'b',7(a0) ; set foreground color
bne.s 13
; Hier nur das Flag setzen, daß ESC b angefangen
; wurde und dafür sorgen, daß die begonnene Escape-
; Sequenz abgebrochen wird (einfach noch ein NUL
; senden, da ESC NUL wirkungslos ist)
move.w #2,in_escape
clr.w 6(a0)
bra.s back
13:
cmpi.b #'c',7(a0) ; set background color
bne.s 14
; Wie oben, nur für ESC c
move.w #3,in_escape
clr.w 6(a0)
bra.s back
14:
cmpi.b #'Y',7(a0) ; position cursor
beq.s back
; Wenn es nicht ESC Y war, das Escape-Sequenz-Flag
; löschen (nur ESC Y benötigt zusätzliche Para-
; meter, ESC b und ESC c werden ja separat behan-
; delt
clr.w in_escape
bra.s back
; Normales Zeichen ausgeben, dabei vorher testen,
; ob die x-Cursorposition noch fehlerfrei ist
; (also kleiner oder gleich dem Maximalwert)
; Ist das Zeichen ein Escape, das entsprechende
; Flag setzen
normal_char:
cmpi.b #27,7(a0)
bne.s no_escape
move.w #1,in_escape
clr.w escape_count
no_escape:
; Ist x-Position außerhalb des zulässigen
; Bereichs?
move.l lineavar(pc),a1
move.w -$1c(a1),d0
ccmp.w -$2c(a1),d0
bls.s back
; wenn ja, X-Position auf 0 setzen (höchst
; unsauber, da Schreibzugriff auf negative
; Line-A-Variable, aber leider notwendig)
clr.w -$1c(a1)
; Die alte conout-Routine aufrufen
back:
old_out:
move.l old_conout(pc),a0
jmp (a0)
; Mit Escape-Sequenzen fortfahren, die mehr als
; einen Parameter erhalten (ESC b, ESC c und
; ESC Y, wobei letztere nicht korrigiert werden
; muß)
continue_escape:
; Ist es ESC Y?
cmpi.w #1,in_escape(pc)
bne.s correction
; Wenn ja, ist dies das letzte Parameterzeichen?
cmpi.w #3,escape_count(pc)
bne.s back
; Ja, also Escape-Flag löschen
clr.w in_escape
bra.s back
correction:
; ESC b bzw. ESC c ausführen, leider mit Schreib-
; Zugriff aus die negativen Line-A-Variablen :(
move.l lineavar(pc),a1
cmpi.w #2,in_escape(pc)
bne.s background_color
clr.w in_escape
move.w 6(a0),-$24(a1)
rts
background_color:
clr.w in_escape
move.w 6(a0),-$26(a1)
rts
; Neue Routine für RAWCON:; hier muß nur geprüft
; werden, ob die x-Cursorposition im zulässigen
; Bereich liegt, da es ja hier keine Escape-
; Sequenzen gibt
dc.b "XBRAVTFX"
old_rawconout:
dc.l 0
new_rawconout:
; siehe oben
move.l lineavar(pc),a0
move.w -$1c(a0),d0
cmp.w -$2c(a0),d0
bls.s rawcon_back
clr.w -$1c(a0)
; Die alte conout-Routine aufrufen
rawcon_back:
move.l old_rawconout(pc),a0
jmp (a0)
; Diese Routine prüft anhand des _MCH-Cookies, ob
; der Rechner ein Falcon ist
check_f030:
clr.w d0
move.l $5a0,d1
beq.s back2
move.l d1,a0
loop2:
tst.l (a0)
beq.s back2
cmpi.l #'_MCH',(a0)+
bne.s goon2
cmpi.l #$30000,(a0)
bne.s back2
moveq #1,d0
back2:
rts
goon2:
addq.l #4,a0
bra.s loop2
; Diese Routine prüft, ob in der XBRA-Kette des
; xconout-Vektors die Limit-Routine bereits einge-
; klinkt ist
is_installed:
move.l xconout+8,a0 ; Xconout-Vektor
loop:
cmpi.l #'XBRA',-12(a0)
bne.s not_installed
cmpi.l #'VTFX',-8(a0)
beq.s installed
move.l -4(a0),a0
bra.s loop
installed:
moveq #1,d0
rts
not_installed:
clr.w d0
rts
; Neue conout/rawconout-Routinen einklinken
install:
move.l xconout+2*4,old_conout
move.l #new_conout,xconout+2*4
move.l xconout+5*4,old_rawconout
move.l #new_rawconout,xconout+5*4
; Position für ESC k initialisieren
move.l #$200020,saved_curpos
rts
data
no_falcon_text:
dc.b 13,10,"Machine is not a Falcon030!"
dc.b 13,10,0
even
patch_text:
dc.b 13,10,"VT52FIX installed!"
dc.b 13,10,0
even
already_installed_text:
dc.b 13,10,"VT52FIX is already "
dc.b "installed!",13,10,0
bss
lineavar:
ds.l 1
saved_curpos:
ds.l 1
in_escape:
ds.w 1
escape_count:
ds.w 1
; Projektdatei zu VT52FIX.PRG
; Autor: Thomas Binder
; (c)1993 by MAXON-Computer
; Compiler: Pure C 1.0
; Erstellt: 02.01.1994
; Letzte Änderung: 02.01.1994
VT52FIX.PRG
.L [ -S=0 ]
.S []
=
VT52FIX.S ; der Sourcecode
; Ende der Projektdatei zu VT52FIX.PRG