Screen plus

Wenn Sie sich einige Demos genauer ansehen, werden Sie sicherlich schon bemerkt haben, daß sie mit einer höheren Grafikauflösung arbeiten, als normalerweise möglich ist. Mit Screen plus können Sie auch unter GEM die Auflösung erhöhen. Diese Lösung ist kein Ersatz für Hardware-Erweiterungen (z.B. AutoSwitch-OVERSCAN) oder Grafikkarten, aber bietet immerhin 45 zusätzliche Pixel-Zeilen und kostet (fast) nichts.

Wie geht das? Wenn das Videosignal mit Hilfe eines Standard-Controllers (u.a. möglich. Bei diesen Video-Controllern sind nämlich fast alle Parameter frei programmierbar wie z.B. Anzahl der Pixel jeZeile oder Anzahl der Pixel-Zeilen. Im Atari ST kommen dagegen spezielle Custom-ICs zum Einsatz. Diese sind nur für die 3 möglichen Betriebsarten (320200 / 16 Farben; 640200 / 4 Farben; 640*400 s/w) des Videosystems ausgelegt. Andere Betriebsarten sind ohne zusätzliche Hardware (normalerweise) nicht möglich.

Wie Sie schon ahnen, gibt es doch eine Möglichkeit, eine andere Auflösung als die 3 gängigen zu realisieren. Ansatzpunkt hierfür ist die Timing-Logik für das Videosignal. Diese Logik befindet sich im GLUE und läßt sich über 2 Register steuern (Shift-Mode- und Sync-Mode-Register). Wenn man in diesen Registern zum richtigen Zeitpunkt bestimmte Bits kippelt, wird die Timing-Logik so ‘durcheinander’ gebracht, daß der ST ein Bild mit einer höheren Auflösung erzeugt. Das Erhöhen der Anzahl der Pixel je Zeile ist aber sehr aufwendig, da innerhalb jeder Pixel-Zeile mehrmals, zu genau definierten Zeitpunkten, auf den GLUE zugegriffen werden muß. Das gesamte Programm muß dann unter Echtzeitbedingungen ablaufen, und es dürfen keine Interrupts auftreten. Außerdem wird bei dieser Aktion die CPU zeitlich so stark belastet, daß das Hauptprogramm wesentlich langsamer wird.

Einfacher dagegen ist die Erhöhung der Anzahl der Pixel-Zeilen. Hier muß nur, nachdem die ‘normalen’ 200 Pixel-Zeilen geschrieben sind, das Vertikalfrequenz-Bit im Sync-Mode-Register gekippelt werden. Dadurch wird die Dunkeltastung für die nächsten Pixel-Zeilen aufgehoben. Die weiteren Einzelheiten werden zusammen mit dem Programm erläutert.

Das Timing von Screen plus

Die Interrupt-Routine

Im ST gibt es ein Display-Enable Signal, welches immer dann high wird, wenn eine Pixel-Zeile geschrieben wird. Dieses Signal liegt auch am TBI-Eingang des Timers B an. Wenn der Timer B auf die Betriebsart ‘Zähler / H-L-Flanke’ programmiert wird, kann man einen Interrupt nach dem Schreiben einer beliebigen Pixel-Zeile auslösen. Da die Interrupt-Reaktionszeit der CPU nicht immer konstant ist, wird schon nach der 190. Zeile ein Interrupt ausgelöst. In der Interrupt-Routine werden alle Interrupts gesperrt. Das Erreichen der 200. Pixel-Zeile wird durch ständiges Abfragen von Timer B festgestellt. Dann wird kurzzeitig die Vertikalfrequenz auf 60 Hz geschaltet. Danach wird Timer B bis zum nächsten VBIank angehalten, und die Interrupts werden wiederfreigegeben. Die VBIank-Routine tut weiter nichts, als den Timer B für das nächste Bild vorzubereiten (Betriebsart: Zähler, Interrupt bei der 190. Zeile) (siehe Bild). Störungen des Bildes während des Zugriffs auf Disk oder Festplatte lassen sich leider nicht vermeiden. Diese treten immer dann auf, wenn der Timer-B-lnterrupt während eines DMA-Transfers ausgelöst wird. Der Start der Interrupt-Routine verzögert sich bis zum Ende des DMA-Transfers, und der Zeitpunkt zum Kippeln des Sync-Bits wird verpaßt.

Ein Bild besteht jetzt aus 245 Pixel-Zeilen. Im Monochrommodus funktioniert dieses Verfahren nicht, da dort mit 71 Hz Vertikalfrequenz gearbeitet wird und das Sync-Bit somit ohne Bedeutung ist. An der Organisation des Bildspeichers ändert sich nichts, er ist nur um 7200 Bytes größer (insgesamt 10400 Bytes). Deshalb ist es auch notwendig, eine neue Bildspeicheranfangsadresse mit der XBIOS-Funktion Setscreen festzulegen. Und schon haben wir das nächste Problem: Wie bringt man GEM die neue Auflösung bei?

Mehr Pixel-Zeilen, bitte!

Während der Initialisierung von GEM wird mit Hilfe von OPEN WORKSTATION die Grafikauflösung des Bildschirms ermittelt. Dieser VDI-Aufruf wird von einer neuen Trap-2-Routine abgefangen. Hier wird die Return-Adresse auf ein Programm umgeleitet, das nach dem Aufruf der Funktion OPEN WORKSTATION im Intout-Array (work-out[1]) und im negative Line-A-Bereich (dev_tab[45]) die neue Rasterhöhe einträgt (244 für 245 Pixel-Zeilen). Gleichzeitig wird die neue maximale Cursor-Zeilenposition (30) festgelegt. Nach dieser Initialisierung werden alle VDI-Aufrufe wieder über den normalen Trap-2-Dispatcher abgewickelt. Da der Trap-2-Vektor vor der Initialisierung von GEM verbogen werden muß, funktioniert das Programm nur, wenn es in einem AUTO-Ordner abgelegt ist.

Alle Grafikroutinen (Line-A) machen die neue Auflösung ohne weitere Änderungen mit, da sich die neuen 45 Pixel-Zeilen nahtlos an die alten anschließen. Nur die Mausroutine macht hier eine Ausnahme.

Ohne Maus nichts los

Ohne Änderung der Mausroutine verschwindet die Maus in dem neuen Bildbereich. Die Ursache dafür ist die Berechnung der Bildschirmadresse, an der die Maus gezeichnet werden soll. Diese Adresse wird mit dem Befehl adda.w d1,a1 ermittelt, wobei sich in dl die relative Adresse des Mauszeigers und in al die physikalische Anfangsadresse des Bildspeichers befindet. Wenn die relative Mauszeiger-Adresse größer als 32767 ist, wird diese als negative Zahl interpretiert, und es ergibt sich eine falsche Adresse. Demzufolge muß an dieser Stelle adda.l d1,a1 stehen.

Bei der Initialisierung der neuen Grafikauflösung wird der erste Eintrag der VBL-Queue auf den neuen Maustreiber gesetzt. Dieser Maustreiber ist fast original aus dem ROM übernommen. Leider ergeben sich je nach TOS-Version für 3 Adressen unterschiedliche Werte, Diese werden vom Programm selbständig ermittelt und eingetragen. Wer sein TOS auf EPROM hat, kann diese Änderung gleich in die Original-Mausroutine eintragen.

Alle Programme, die wirklich auflösungsunabhängig programmiert sind, können Sie unter Screen plus benutzen, wie zum Beispiel 1st Word oder Turbo-C. Auch TOS-Programme profitieren von der neuen Auflösung. Sie können jetzt 30 Cursor-Zeilen nutzen.


;************************************************ ;* * ;* SCREEN plus * ;* Steffen Scharfe * ;* * ;* (c) 1992 MAXON Computer * ;************************************************ v_bas_ad equ $044e nvbls equ $0454 vblqueue equ $0456 sysbase equ $04f2 mfp equ $fffa01 ;MFP 68901 aer equ $fffa03 ;Aktive-Edge-Register iera equ $fffa07 ;Interrupt-Enable-Register A isra equ $fffa0f ;Interrupt-in-Service-Register A imra equ $fffa13 ;Interrupt-Mask-Register A tbcr equ $fffa1b ;Timer-B-Control-Reg±ster tbdr equ $fffa21 ;Timer-B-Data-Register sync_mod equ $ff820a ;Sync-Mode-Register zeile equ 190 ;Das hintere Programmstuck wird nur zur ;Initialisierung benötigt bra init ;hier folgt nun das residente Programmstück ;diese Trap #2-Routine wird nur einmal ;angesprungen, um nach der Initialisierung des ;VDI die Parameter der neuen Bildschirmhöhe zu ;setzen (245 Pixelzeilen) ;neuer Trap #2 Routine trap_2: move.l d1,vdipb ;vdipb merken move.w d0,vdi_aes ;VDI oder AES move.l 2(sp),return ;Return-Adresse merken move.l #new_return,2(sp) ;neue Return-Adresse movea.l vblqueue,a1 move.l #new_maus,(a1) ;teilweise neue Mausroutine movea.l old_vektor,a1 jmp (a1) ;ab zum Trap 2-Dispatcher new_return: cmpi.w #$73,vdi_aes ;war dies ein VDI-Aufruf? beq.s vdi ;ja zurueck:movea.l return,a1 ;alte Return-Adresse jmp (a1) ;zurück ins Hauptprogramm vdi: movem.l d0-d2/a0-a2,-(sp) movea.l vdipb,a0 movea.l (a0),a1 ;Zeiger auf Control-Array cmpi.w #1,(a1) ;Open Workstation? bne.s no_open ;nein movea.l 12(a0),a1 ;Zeiger auf Intout-Array move.w #244,2(a1) ;neue Rasterhöhe movea.l linea_param,a0 move.w #244,-$02b2(a0) ;neue Werte in die negativen addi.w #5,-$2a(a0) ;Line-A-Variablen eintragen addi.w #45,-4(a0) ;45 Pixelzeilen mehr move.l old_yektor,-(sp) ;ausklinken move.w #34,-(sp) move.w #5,-(sp) trap #13 ;Setexc addq.l #8,sp no_open:movem.l (sp)+,d0-d2/a0-a2 bra.s zurueck ;leider notwendig ein neuer Maustreiber ; (wegen 1 Befehl !!) new_maus:movea.l linea_param,a5 ;wegen verschiedener BS-Varianten tst.b -$0153(a5) ;Maus-Flag bne.s maus_end bclr #0,-$0154(a5) ;Cur-Flag beq.s maus_end move.l -$0158(a5),d1 ;x/y-Position move.l d1,d0 swap d0 movem.w d0-d1,-(sp) lea -$014a(a5),a2 ;Save-Len maus_adr1: jsr 0 movem.w (sp)+,d0-dl movea.l linea_param,a5 lea -$0358(a5),a0 ;x-Hot-Spot lea -$014a(a5),a2 ;Save-Len bsr.s new_maus1 maus_end: rts new_maus1: move.w 6(a0),-(sp) ;Hintergrundfarbe 4(sp) move w 8(a0),-(sp) ;Vordergrundfarbe 2(sp) clr.w d2 tst.w 4(a0) ;Replace/Xor bge.s replace ;Replace-Modus moveq #$10,d2 ;XOR-Modus replace:move.w d2,-(sp) ;Modus merken 0(sp) clr.w d2 bclr #1,6(a2) ;Words gebuffert sub.w (a0),d0 ;x:=x-hotspot bcs.s x_hotspot move.w -$02b4(a5),d3 ;maximale Rasterbreite subi.w #15,d3 ;minus 15 cmp.w d3,d0 ;Mauszeiger vollständig sichtbar? bhi.s teilweise_x ;nein bset #1,6(a2) ;Longs gebuffert bra.s maus_y x_hotspot: addx.w #16,d0 moveq #8,d2 ;anmerken: x-hotspot bra.s maus_y teilweise_x: moveq #16,d2 maus_y: sub.w 2(a0),d1 ;y:=y-hotspot lea $0a(a0),a0 ;Tabelle für Vordergrund und Maske bcs.s y_hotspot move.w -$02b2(a5),d3 ;Anzahl der Pixelzeilen subi.w #15,d3 cmp.w d3,d1 ;Mauszeiger vollständig sichtbar? bhi.s teilweise_y ;nein moveq #16,d5 ;ja -> Höhe:=16 Pixelzeilen bra.s maus1 y_hotspot: move.w d1,d5 addi.w #16,d5 ;Höhe berechnen asl.w #2,d1 ;y:=y*4 suba.w d1,a0 ;ersten Pixelzeilen des Mauszeigers übergehen clr.w d1 bra.s maus1 teilweise_y: move.w -$02b2(a5),d5 ;Anzahl der Pixelzeilen sub.w d1,d5 addq.w #1,d5 ;Höhe berechnen maus1: jsr 0 ;rel Adresse im Bildspeicher ;ab der die Maus gezeichnet wird movea.l v_bas_ad,a1 ;Zeiger auf Anfang des Bildspeichers ;und nun der entscheidende Befehl ;aus adda.w d1,a1 wird... adda.l d1,a1 ;absolute Adresse ;aha, die Maus funktioniert jetzt auch mit über ;32767 Bytes Bildspeicher maus_adr3:jmp 0 ;weiter im Original-Programm ;Interrupt-Routinen new_vbl:move.b #zeile,tbdr ;Timer B move.b #8,tbcr ;Start rts timer_b:move.l d0,-(sp) move #$2700,sr ;alle Ints gesperrt w200: cmpi.b #180,tbdr ;auf 200 bne.s w200 ;Pixelzeile warten move.b #0,sync_mod ;Sync-Bit move w #2,d0 ;kippeln w: nop dbra d0,w ;etwas warten move.b #2,sync_mod move #$2300,sr move.b #0,tbcr ;Zähler stop move.l (sp)+,d0 bclr #0,isra ;Interrupt-Service fertig rte even old_vektor: ds.l 1 return: ds.l 1 vdipb: ds.l 1 vdi_aes: ds.w 1 linea_param:ds.l 1 old_stack: ds.l 1 ;bis hier ist das Programm resident !! init: movea.l 4(sp),a6 ;Adresse der Basepage move.w #$0100,d7 ;Länge der Basepage add.l 12(a6),d7 ;Länge des Text-Segments add.l 20(a6),d7 ;Länge des Daten-Segments add.l 28(a6),d7 ;Länge des Speicher-/Segments move.w #4,-(sp) ;Bildschirmauflösung holen trap #14 ;Getrez addq.l #2,sp cmp.w #2,d0 beq error1 ;monochrom kann ich nicht ! dc.w $a000 ;Line-A Init move.l a0,linea_param ;merken clr.l -(sp) ;Supermodus move.w #32,-(sp) trap #1 addq.l #6,sp move.l d0,old_stack ;alten Stack merken ;ermittelt je nach TOS-Version bestimmte Adressen movea.l sysbase,a0 move.w 2(a0),d0 ;Versionsnummer holen lea tos_1_2,a1 cmp.w #$0102,d0 ;TOS 1.2 ? beq.s tos1 ;ja lea tos_1_4,a1 emp.w #$0104,d0 ;TOS 1.4 ? bne error3 ;nein tos1: move.l (a1)+,maus_adr1+2 ;TOS-abhängige Adressen move.l (a1)+,maus1+2 ;initialisieren move.l (a1)+,maus_adr3+2 sub.l #init_end-init,d7 ;Initialisierungsteil wegwerfen move.l a6,d6 ;Adresse Base-Page add.l d7,d6 cmp.w #0,d6 ;unterste Byte 0 ? beq.s byte0 ;ja and.l #$ffff00,d6 add.l #$0100,d6 ;wegen Videoprozessor ;neue physikalische und logische ;Bildanfangsadresse setzen byte0: move.w #-1,(sp) move.l d6,-(sp) ;neue Bildanfangsadresse move.l d6,-(sp) ;logische Bildanfangsadresse move.w #5,-(sp) ;Setscreen trap #14 lea 12(sp),sp ;VBL-Interrupt in Queue eintragen movea.l vblqueue,a0 addq.l #4,a0 ;1.Eintrag freilassen (für GEM) move.w nvbls,d0 subq.w #2,d0 such: move.l (a0)+,d1 beq.s eintrag ;leeren Eintrag gefunden dbra d0,such ;weitersuchen bra error2 eintrag:move.l #new_vbl,-(a0) ;Timer-B-Interrupt initialisieren move.l #timer_b,$0120 ;Beginn der Interruptroutine move.b #0,tbcr ;Timer gestoppt ;MFP Timer B initialisieren andi.b #$f7,aer ;H-L Flanke wirksam move.b #zeile,tbdr ;Int. bei zeile ori.b #1,imra ;Interruptmaske freigeben ori.b #1,iera ;Interrupt Timer B einschalten move.w #37,-(sp) ;Wait Vbl trap #14 addq.l #2,sp move.b #8,tbcr ;Ereigniszählung ;Trap #2-Vektor verbiegen pea trap_2 move.w #34,-(sp) ;Trap #2 move.w #5,-(sp) ;neuen Vektor setzen trap #13 ;Setexc addq.l #8,sp move.l d0,old_vektor ;alten Vektor merken move.l old_stack,-(sp) ;User-Modus move.w #32,-(sp) trap #1 addq.l #6,sp ;Programm resident hinterlassen add.l #32000+7200,d6 ;Große Bildspeicher sub.l a6,d6 ;benötigter Speicherplatz clr.w -(sp) ;Status ok move.l d6,-(sp) ;Länge move.w #$31,-(sp) trap #1 ;Ptermres ;Error-Meldung error1: pea err_txt1 bra.s error error2: pea err_txt2 bra.s error error3: pea err_txt3 error: move.w #9,-(sp) ;Cconws trap #1 addq.l #6, sp move.w #-1,d0 warte: dbra d0,warte clr.w -(sp) trap #1 ;Tabelle für die verschiedenen TOS-Versionen ;dc.l maus_ad1,maus_ad2,maus_ad3 even tos_1_2:dc.l $fd01de,$fca212,$fd008c tos_1_4:dc.l 0,0,0 err_txt1:dc.b "nur niedrige oder mittlere" dc.b " Auflösung !",0 err_txt2:dc.b "alle VBL-Slots belegt !",0 err_txt3:dc.b "unbekannte TOS-Version '",0 even init_end: end

Steffen Scharfe
Aus:ST-Computer 04 /1992, Seite

Links

Copyright-Bestimmungen: siehe Über diese Seite