BigSTE: Pump up the Resolution

Ein Großbildschirm ist sicherlich der Traum vieler ST-Besitzer - und wegen der hohen Kosten bleibt er für die meisten bestimmt auch weiterhin ein Traum. Trotzdem sind Großbildschirme und die damit verbundene Auflösungserhöhung nicht mehr aus dem Computeralltag wegzudenken, da sie in vielen Anwendungsgebieten enorme Vorteile bringen (z.B. DTP, CAD).

Ist man nun aber doch glücklicher Besitzer eines Großbildschirmes, hat man das Problem, daß sich ein nicht unbeträchtlicher Teil der gängigen Software außerstande sieht, diese Pixel-Darstellungswunder ordnungsgemäß zu betreiben. Also ist Software gefragt, die durch andere als die Standardauflösungen des ST nicht gleich außer Rand und Band gerät.

Angenommen, Sie wollten nun als (Hobby-) Programmierer mit naturgemäß immer zu kleinem Geldbeutel (und ohne Großbildschirm) solche Programme schreiben, würde bei Ihnen ein mittelgroßes Problem auftauchen, weil Sie die einwandfreie Funktion der Programme mangels Großbildschirm leider nicht austesten können.

„BigSTE“ kann Ihren SM 124 oder Fernseher zwar leider auch nicht in einen 10mal so teuren Großbildschirm verwandeln, aber das Programm kann Ihrem STE zumindest vorgaukeln, daß Sie neuerdings ein paar Pixel mehr darstellen können.

Insider werden jetzt zu Recht einwenden, daß ein Programm mit der eben beschriebenen Fähigkeit bereits existiert („Bigscreen“ von Julian Reschke [ 1 ]), das Ganze also kalter Kaffee ist. Ich habe mich daher ausschließlich der STEs mit ihren neuen Grafikfähigkeiten angenommen und ein Programm ähnlich „Bigscreen“ entwickelt, das die erweiterten Hardware-Fähigkeiten nutzt. Ging bei einem „normalen“ ST und „Bigscreen“ noch sehr viel wertvolle Prozessorzeit dabei verloren, die geänderte Auflösung auf dem Bildschirm darzustellen, macht das ein STE quasi mit Links, man muß nur wissen wie. Deswegen erst einmal ein kleiner Exkurs in die Videohardware der STEs.

Beim STE sind unter anderem die folgenden drei Videoregister ins Leben gerufen worden [2], die es dem Programmierer ermöglichen, dem Videochip flexiblere Darstellungen des Grafikspeichers mitzuteilen. Alle drei Register können sowohl gelesen, als auch beschrieben werden (s. Tab.l).

Diese drei Register machen es möglich, daß wir erhöhte Auflösungen ohne nennenswerten Arbeitsaufwand darstellen können. Natürlich stellt der Monitor jetzt nicht plötzlich 1280 * 800 Pixel dar, wir sehen immer nur einen bestimmten, verschiebbaren Ausschnitt daraus.

Aber, um es noch einmal zu betonen, der Rechenaufwand ist beim STE fast Null, während sich ein ST (ohne E) fast zu Tode arbeiten muß, um ein ähnliches Ergebnis zu liefern.

Das VBASELO-Register macht es möglich, pixelweise vertikal und in 16-Pixel-Schritten (Wortlänge!) horizontal zu scrollen. Pixel weise horizontal scrollen kann man erst mit Hilfe des HSCROLL-Registers, indem dort eine weitere Verschiebung um 0 bis 15 Pixel eingetragen wird.

Zum Verständnis der Wirkungsweise des LINEWID-Registers ein kleines Beispiel: Im Monochrommodus (1 Bitplane) hat eine Bildzeile bei 960 Pixeln horizontaler Auflösung eine Länge von 960 / 16 = 60 Wörtern.

40 Wörter (640 Pixel) werden in hoher Auflösung standardmäßig zur Anzeige gebracht, 20 Wörter müssen im virtuellen Bildschirm also übersprungen werden, um zu den Daten der nächsten Zeile zu gelangen (siehe Bild 1).

Diesen Offset kann man nun in das LINEWID-Register eintragen, und aus wirren Pixel-Mustern wird plötzlich ein ansehnliches Bild, wobei man beachten muß, daß man den Offset auch in Wörtern und nicht in Bytes angibt.

Sobald man jetzt aber in das HSCROLL-Register einen Wert ungleich 0 einträgt, hat man wieder Pixel-Müll auf dem Bildschirm, den man nur durch Verkleinern des Wertes im LINEWID-Register um 1 beseitigen kann. Angezeigt wird in diesem Moment ein Teil des 1. Wortes, dann 39 Wörter komplett und ein Teil des 4L Wortes, also 41 Wörter insgesamt. Daher beträgt die Distanz zur nächsten Zeile jetzt nur noch 19 anstatt 20 Wörter, was entsprechend im LINEWID-Register berücksichtigt werden muß.

Vorrangige Aufgabe des Programmes ist es natürlich, erst einmal dem GEM eine höhere Auflösung mitzuteilen. Dies geschieht durch eine Routine, die sich in den GEM-Vektor einschleift, auf den ersten OPEN WORKSTATION-Aufruf (v_opnwk) wartet und dessen Rückgabewerte sowie einige negative Line-A-Variablen [3] entsprechend abändert. Vorher muß natürlich noch der Bildschirmspeicher so vergrößert werden, daß er die Daten der erhöhten Auflösung aufnehmen kann.

Bezeichnung Adresse Bedeutung
VBASELO $FF820D Low-Byte der Bildschirmbasisadresse. Ermöglicht es, die Adresse auf eine Wortgrenze (bisher 256-Byte-Grenze) zu legen (niederwertigstes Bit wird nicht genutzt, deswegen nur gerade Adressen).
LINEWID $FF820E Offset zur nächsten Zeile. Enthält die Anzahl der Wörter, die am Ende einer Zeile addiert werden, um zur nächsten Zeile zu gelangen. Das High-Byte wird nicht genutzt, daher sind nur Werte von 0 bis 255 möglich.
HSCROLL $FF8264 Anzahl der Bits, um die der Bildschirm nach rechtsverschoben werden soll (ermöglicht horizontales, pixelweises Scrollen).
Die Bits 4 bis 15 werden nicht genutzt, daher sind nur Werte im Bereich von 0..15 möglich. Bei einer Verschiebung um höhere Beträge muß das VBASELO-Register mitbenutzt werden.

Tabelle 1: Die drei Videoregister des STE

Ist das getan, muß das LINEWID-Register entsprechend gesetzt werden (s.o.), um die geänderte Auflösung sichtbar zu machen. Ab jetzt ist nur noch ein Ausschnitt des gesamten Bildes zu sehen.

Um mit dem Programm sinnvoll arbeiten zu können, ist es wünschenswert, den angezeigten Bildausschnitt verschieben zu können. Dabei bietet es sich an, die Bewegung bzw. die Position des Mauszeigers bei der Wahl des Ausschnittes einzubeziehen, so daß der angezeigte Bereich immer mit dem Mauszeiger mitwandert.

Zwei Routinen erledigen diese Aufgabe:

Bild 1: Wirkungsweise des LINEWD-Registers

Das waren soweit die wichtigsten Aktionen, die das Programm erledigen muß, um grundsätzlich zu funktionieren. Nun aber noch ein paar Worte zu den Nebensachen, die auch getan werden müssen, und die dem Programmierer das Leben meist am schwersten machen:

„BigSTE“ muß aus dem Auto-Ordner heraus gestartet werden!

(falls Sie einen GDOS-Treiber besitzen, unbedingt nach dessen Installation!!!)

Da „BigSTE“ vor der Initialisierung des AES installiert werden muß, ist es nötig zu testen, ob das Programm in der Boot-Phase aus dem AUTO-Ordner heraus gestartet wurde. Das können wir überprüfen, indem wir einen appl_init -Aufruf durchführen und den ersten Eintrag im global-Feld auf 0 testen [4]. Bekommt man dort bereits die Versionsnummer des AES und nicht den Wert 0 zurückgeliefert, wurde das Programm erst nach der Initialisierung des AES gestartet, also zu spät.

„BigSTE“ läuft nur auf den STEs!

Deswegen muß überprüft werden, ob der Rechner, auf dem das Programm gestartet wurde, auch ein STE ist. Um das zu testen, fallen mir mehrere Möglichkeiten ein:

Letzteres Verfahren ist wohl das „sauberste“ und funktioniert folgendermaßen: Die Systemvariable_p cookie {Adresse $5AO) enthält ein Langwort, das ab TOS 1.6 einen Zeiger auf einen Cookie-Jar darstellt [5]. Hat dieser Zeiger den Wert NULL (bei älteren TOS-Versionen), gibt es keinen Cookie-Jar, und der Test wird mit dem Ergebnis, daß es sich bei dem verwendeten Rechner wohl um keinen STE handelt, abgebrochen. Existiert aber ein Cookie-Jar, findet man an der Adresse, auf die _p_cookie zeigt, eine Tabelle mit Wertepaaren vor. In dieser Tabelle sollte sich ein Eintrag mit der Kennung _VDO befinden, wobei der zugehörige Wert die Version der Video-Hardware beschreibt. Hierbei steht ein Wert von $00000000 für die Video-Hardware eines normalen STs, $00010000 steht für die eines STEs und $00020000 für die eines TTs.

Das Programm soll nicht mehrfach installiert werden können!

Da die vom Programm benutzten Vektoren mit Hilfe des XBRA-Verfahrens umgelegt werden, kann man das relativ einfach abtesten, indem man die jeweiligen Vektorketten nach der eigenen XBRA-Kennung absucht. Dieses Verfahren funktioniert aber leider nur, wenn sich Programme, die sich vorher schon in dieselben Vektoren eingeklinkt haben, auch der XBRA-Kennung bedienen.

Wenn in niedriger und mittlerer Auflösungsstufe die Info-Box des Desktops angezeigt wird, wird vom Betriebssystem der TIMER-B benutzt, um die durchlaufenden Farben im Atari-Logo zeichnen zu können. Erstens benötigt „BigSTE“ diesen Timer zum Scrollen, und zweitens wird nach Verlassen der Info-Box der alte Vektor vom Betriebssystem nicht restauriert, daher wird der eigene Vektor vom Programm in jeder VBL-Routine aufs neue eingetragen, um eine einwandfreie Funktion des Programms zu gewährleisten. Auf eine bunte Info-Box muß man jetzt leider verzichten, aber das dürfte wohl eines der kleineren Übel sein.

Mit „BigSTE“ hat man die Möglichkeit, Auflösungen in gewissen Grenzen einzustellen. Die Programmierung der Auflösungseingabe wäre aber relativ aufwendig geworden und hätte das Programm unnötig aufgebläht, da das Programm in Assembler geschrieben ist. Daher habe ich noch ein kurzes Programm in GFA-BASIC geschrieben, das die Konfiguration von „BigSTE“ übernimmt. Es sollte, wie „BigSTE“, im AUTO-Ordner liegen, sinnvollerweise davor, damit sich die Konfiguration direkt auswirken kann. Das Programm wird bei einem Start aus dem AUTO-Ordner nur bei vorher aktiviertem CapsLock durchlaufen, ansonsten gleich wieder beendet! Man hat hier die Möglichkeit, folgende Einstellungen vorzunehmen:

Die Hardcopy-Routine des Betriebssystems kommt mit einer geänderten Bildschirmauflösung leider nicht zurecht, deswegen ist der Vektor dump vec (Adresse $502) auf eine eigene kleine (um nicht zu sagen winzige) Routine verbogen worden. Diese Routine macht schlicht und einfach nichts, außer sofort wieder zurückzuspringen. Auf eine Hardcopy-Funktion muß also leider verzichtet werden.

Zum Schluß noch ein paar Einschränkungen beim Umgang mit „BigSTE“:

Ein Auflösungswechsel über das Desk-top sollte vermieden werden, da „BigSTE“ auf diesen Wechsel nicht reagieren kann. (Es ist aber problemlos möglich, über einen Reset und eine entsprechende Konfiguration von „BigSTE“ die Auflösungsstufen zu wechseln.)

Werden Programme gestartet, die bezüglich der Bildschirmdarstellung „unsauber“ programmiert sind, kann es bei manchen dieser Programme passieren, daß auch nach deren Beendigung die Bildschirmdarstellung nicht mehr korrekt ist. Hier hilft dann meistens nur ein Reset.

Ich habe es trotz unzähliger Versuche leider nicht geschafft, in mittlerer und hoher Auflösung mit Hilfe der STE-Register pixelweise horizontal zu scrollen, ohne daß ein unschöner Seiteneffekt auftritt.

Und zwar klappt ständig ein Teil des rechten Bildes auf die linke Seite um, wenn der Inhalt des HSCROLL-Registers auf 0 wechselt. Hier scheint die Bildsynchronisation gehörig aus dem Tritt zu geraten. Alle Versuche, dieses Register zu verschiedenen Zeitpunkten während des Bildaufbaues zu ändern, haben keine befriedigenden Ergebnisse gebracht. Was bleibt, ist die Vermutung, daß pixelweises, horizontales Scrolling hardwaremäßig nur für die niedrige Auflösungsstufe gedacht ist. Auf eine diesbezügliche Anfrage bei Atari habe ich leider keine Antwort erhalten. Wer hier eine Lösung kennen sollte, möge sie mir bitte mitteilen. In mittlerer und hoher Auflösungsstufe kann deswegen leider auch nur in 16-Pixel-Schritten horizontal gescrollt werden.

Quellennachweis:

[1] Julian F. Reschke: Der weiche Großbildschirm, ST-Magazin 11/1988

[2] Martin Backschat: STarkes noch STErker, ST-Magazin 12/1989

[3] Julian F. Reschke: Saubere Fenster, ST-Magazin 10/1988

[4] Laurenz Prüßner: Reine Existenzfrage, ST-Magazin 2/1990

[5] Julian F. Reschke: Vorhang auf für die Keksdose, ST-Magazin 3/1990

; -----------------------------------------------------------
;
; BigSTE für Atari-STE
;
; Beschreibung: Simulation erhöhter Auflösungen auf dem Atari STE 
;               (STE-Hardware erforderlich)
;
;       Autor: Matthias Andrä
;     Sprache: Assembler
; Progammname: 'BIG_STE,PRG1 (unbedingt so benennen !!!)
;
; Version: 1.2 (c) 1991 MAXON Computer
;
; -----------------------------------------------------------

GEMDOS      equ 1
GEM         equ 2
XBIOS       equ 14

LINE_A      equ $A000   ; Line-A-Initialisierung

v_lin_wr    equ $02     ; Line-A-Variable (Zeilenbreite)

BYTES_LIN   equ -$02    ; negative Line-A-Variablen

V_REZ_VT    equ -$04
V_REZ_HZ    equ -$0C
V_REZ_WR    equ -$28
V_CEL_MY    equ -$2A
V CEL MX    equ -$2C
V_CEL_HT    equ -$2E
MOUSE_Y     equ -$0258
MOUSE_X     equ -$025A
DEV_TAB     equ -$02B4

VBLVEKTOR   equ $70     ; benutzte Vektoren
GEMVEKTOR   equ $88
TIMERBVEK   equ $0120

dump_vec    equ $0502   ; Zeiger auf Hardcopy-Routine
_p_cookies  equ $05A0   ; Zeiger auf Cookie-Jar
VBASEHI     equ $FF8201 ; diverse (STE-)Video-Register
VBASEMID    equ $FF8203
VBASELO     equ $FF320D
LINEWID     equ $FF820E ; Offset zur nächsten Zeile
HSCROLL     equ $FF8264 ; Register für pixelweises Scrollen

IERA        equ $FFFA07 ; Interrupt EnableRegister
ISRA        equ $FFFA0F ; Interrupt In-Service Register
IMRA        equ $FFFA13 ; Interrupt Mask Register
TBCR        equ $FFFA1B ; Timer B Control Register
TBDR        equ $FFFA21 ; Timer B Data Register

; ----------------------------------------------

            text

            bra.s   start   ; zu Programmstart springen
            dc.b    'BSTE'  ; Programmkennung

; Nachfolgende Variablen werden von 'K_BIGSTE.PR6'
; gepatcht und dienen zur Konfiguration von ’BigSTE'

aufloesung: dc.w    1 ; Farbauflosung (Mid/Low)
; BigSTE wird nicht installiert, wenn 'aufloesung' >1 !!!
rez_plus:   dc.w    320,200,0,200,640,560
; Tabelle: zusätzliche Auflösungen
;          wird zu Standardauflösung addiert
rand:       dc.w    16,16,32,16,32,32
; Tabelle: hör./vert. Schieberänder

start:
    movea.l     4(SP),A6    ; Basepageadresse
    movea.w     #$0500,A5   ; Größe der Basepage + Stackgröße
    adda.l      12(A6),A5   ; + Größe TEXT-Segments
    adda.1      20(A6),A5   ; + Größe DATA-Segments
    adda.l      28(A6),A5   ; + Größe BSS-Segments
    move.l      A5,D1       ; = Gesamtlänge
    and.b       #$FE,D1     ; Länge gerade
    add.l       A6,D1       ; + Basepageadresse
    movea.l     D1,SP       ; Stackende
    move.l      A5,-(SP)    ; Programmlänge
    move.l      A6,-(SP)    ; Basepageadresse
    move.l      #$4A0000,-(SP)
    trap        #GEMDOS     ; Mshrink
    lea         12(SP),SP

    lea         test_ste(PC),A0 ; auf STE testen
    bsr         supexec     ; im Supervisormodus ausführen
    tst.b       ste         ; STE-Hardware vorhanden?
    beq         no_ste      ; nein, Abbruch

    bsr         appl_init   ; 'appl_init' durchführen
    tst.w       global      ; geglückt ?
    bne         auto        ; dann Abbruch, da BigSTE nicht 
                            ; aus Auto-Ordner gestartet wurde 
    cmpi.w      #2,aufloesung ; 'aufloesung' > 1 ? 
    bge         not_installed ; dann BigSTE nicht installieren

    dc.w        LINEA ; Line-A-Init
    move.l      A0,linea_var ; Variabien-Startadresse merken

    move.w      #3,-(SP)    ; Logbase
    trap        #XBIOS      ; logische Bildschirmadresse

    addq.l      #2,SP
    move.l      D0,videobase ; merken 

    move.w      #4,-(SP)    ; Getrez
    trap        #XBIOS      ; Auflösungsstufe holen
    addq.l      #2,SP       ; Stack korrigieren
    cmp.w       #2,D0       ; hohe Auflösung ?
    beq.s       res_ok      ; dann weiter
    cmp.w       aufloesung(PC),D0
    ; tats. Farbauflösung = gewünschter ? 
    beq.s       resok       ; ja, dann weiter

    move.w      aufloesung(PC),-(SP) ; Auflösung setzen (Voreinstellung)
    move.l      #-1,-(SP)
    move.l      #-1,-(SP)
    move.w      #5,-(SP)
    trap        #XBIOS
    lea         12(SP),SP
    move.w      aufloesung(PC),D0

res_ok:
    move.w      D0,resolution       ; merken
    add.w       D0,D0               ; *2
    lea         planes(PC),A0
    move.w      0(AO,D0.w),planeanz
    add.w       D0,D0               ; *2 *2 = *4
    lea         rand(PC),A0         ; Zeiger auf Randtabellen
    move.w      0(A0,D0.w),h_rand   ; horizontaler Rand
    move.w      2(A0,D0.w),v_rand   ; vertikaler Rand

    lea         rez(PC),A0          ; Zeiger auf Auflösungstabelle 
    move.w      0(A0,D0.w),D6       ; Standardauflösung holen
    move.w      2(A0,D0.w),D7
    move.w      D6,h_mon
    move.w      D7,v_mon
    addi.w      #1,h_mon ; +1 = Breite
    addi.w      #1,v_mon ; +1 = Höhe

    move.w      v_mon(PC),D3
    lsr.w       #1,D3
    move.b      D3,count            ; halbe vertikale Auflösung

    lea         rez_plus(PC),A0     ; Tabelle Auflösungserhöhung
    move.w      0(A0,D0.w),D4
    add.w       2(A0,D0.w),D4       ; keine Auflösungserhöhung? 
    beq         not_installed       ; dann Ende
    add.w       0(A0,D0.w),D6       ; X-Wert addieren
    add.w       2(A0,D0.w),D7       ; Y-Wert addieren
    move.w      D6,h_rez            ; und merken
    move.w      D7,v_rez

    addq.w      #1,D6               ; Breite
    addq.w      #1,D7               ; Höhe
    lsr.w       #3,D6               ; Breite / 8
    mulu        planeanz(PC),D6     ; * Anzahl Planes
    mulu        D6,D7               ; * Hohe = Bildschirmbedarf
    add.l       #255,D7             ; +255
    and.1       #$FFFF00,D7         ; auf 256 Byte Grenze bringen
    move.l      D7,D6
    sub.l       #$8000,D6           ; -32k vorhandenen Bildschirmspeicher

    move.l      #-1,D0              ; Größten freien Speicherblock 
    bsr         malloc              ; erfragen
    move.l      D0,D5               ; Länge in D5
    bsr         malloc              ; Speicher reservieren
    movea.l     D0,A0               ; Startadresse in A0
    move.l      D0,D4               ; und D4 merken
    bsr         mfree               ; und gleich wieder freigeben

    add.l       D5,D4               ; Länge Speicherblock dazuaddieren 
    cmp.l       videobase(PC),D4    ; Block direkt am Video-Ram? 
    bne.s       new_v_ram           ; nein, weiter
    cmp.l       D6,D5               ; genug Speicher frei?
    blt         memfull             ; nein, Meldung ausgeben

    sub.l       D6,D5               ; Freier Speicher minus benötigter 
    move.l      D5,D0               ; nach D0
    bsr         malloc              ; 1. Block reservieren
    movea.l     D0,A6               ; Startadresse in A6 merken
    move.l      D6,D0               ; benötigter Speicherplatz 
    bsr         malloc              ; Block unter Video-Ram reservieren 
    tst.l       D0                  ; geklappt ?
    bmi         memfull             ; nein, Meldung ausgeben
    move.l      D0,videobase        ; Startadresse merken 
    movea.l     A6,A0               ; Startadresse 1. Block
    bsr         mfree               ; Block wieder freigeben
    bra.s       install1

new_v_ram:
    cmp.l       D7,D5               ; genug Speicher frei ?
    blt         memfull             ; nein, Meldung ausgeben

    move.l      D7,D0               ; Speicher für Bildschirm
    bsr         malloc              ; reservieren
    tst.l       D0                  ; geklappt ?
    bmi         memfull             ; nein, Meldung ausgeben
    move.l      D0,videobase        ; Startadresse merken

; Das alte Videoram (32k) liegt jetzt brach,
; da kein Speicherblock direkt darunter 
; reserviert werden konnte !

install1:
    andi.l      #$FFFF00,videobase ; auf 256-Byte-Grenze bringen

    lea         install2(PC),A0     ; ’install2' im
    bsr         supexec             ; Supervisormodus
    tst.b       installiert         ; BigSTE bereits installiert ? 
    bne         installed           ; dann Meldung und Abbruch
    lea         TEXT8(PC),A0        ; Bildschirm löschen
    bsr         printline

    move.w      #-1,- (SP)
    move.l      videobase(PC),-(SP) ; Physikalische
    move.l      videobase(PC),-(SP) ; und logische
    move.w      #5,-(SP)
    trap        #XBIOS              ; Bildschirmadresse setzen 
    lea         12(SP),SP

    lea         TEXT0(PC),A0        ; Headertext
    bsr         printline
    lea         TEXT3(PC),A0        ; "BigSTE installiert"

    bsr         printline
    clr.w       -(SP)
    move.l      A5,-(SP) 
    move.w      #$31,-(SP) ; Ftermres
    trap        #GEMDOS ; Programm resident halten und Ende

install2:
    lea         GEMVEKTOR, A0
    bsr.s       inst_test           ; BigSTE schon im GEM-Vektor 
    bne.s       install2end         ; ja, Abbruch
    move.l      (A0),oldgenrvec     ; alten GEM-Vektor sichern und 
    move.l      #new_gem,(A0)       ; eigene Routine eintragen

    lea         VBLVEKTOR,A0
    bsr.s       inst_test           ; BigSTE schon im VBL-Vektor 
    bne.s       install2end         ; ja, Abbruch
    move.l      (A0),oldvblvec      ; alten VBL-Vektor sichern und 
    move.l      #new_vbl,(A0)       ; eigene Routine eintragen

    move.l      dump_vec,olddumpvec ; alten Hardcopy-Vektor sichern 
    move.l      #hardcopy,dump_vec  ; Dummy-Routine eintragen
    move.l      TIMERBVEK,oldtimerb ; alten Timer-B-Vektor sichern 
    move.l      #timer_b,TIMERBVEK  ; Timer-B-Routine eintragen 
    ori.b       #1,IERA             ; Timer-B erlauben
    ori.b       #1,IMRA 
install2end: 
    rts

; -- Testen ob ’BSTE'-Kennung bereits in 
; Vektorkette vorhanden ist --------------

inst_test:
    sf          installiert
    movea.l     (A0),A1 
testloop:
    cmpa.l      #$08,A1 
    blt.s       testend
    cmpi.l      #'XBRA',-12(A1)     ; XBRA-Kennung gefunden ?
    bne.s       testend             ; nein, Ende
    cmpi.l      #'BSTE',-8(A1)      ; Eigene Programmkennung gefunden ? 
    seq         installiert         ; Ja, BigSTE bereits installiert
    beq.s       testend             ; und Ende
    movea.l     -4(A1),A1           ; Nein, XBRA-Kette weiterverfolgen
    beq.s       testend 
    bra.s       testloop 
testend:
    tst.b       installiert
    rts

; -- Verschiedene (Fehler)-Meldungen ausgeben —

installed:
    movea.l     videobase(PC),A0
    bsr         mfree
    lea         TEXT1,A0            ; Headertext
    bsr         printline
    lea         TEXT7(PC),A0        ; "BigSTE bereits installiert"
    bsr         printline
    bra.s       waitkey

no_ste:
    lea         TEXT1(PC),A0        ; Headertext
    bsr         printline
    lea         TEXT6(PC),A0        ; "Benötigte Hardware fehlt"
    bsr         printline
    bra.s       waitkey

memfull:
    lea         TEXT1(PC),A0        ; Headertext
    bsr         printline
    lea         TEXT2(PC),A0        ; "Nicht genug Speicher"
    bsr         printline

waitkey:
    move.w      #7,-(SP)
    trap        #GEMDOS             ; auf Tastendruck warten
    addq.l      #2,SP
    bra.s       ende                ; und Ende

not_installed:
    lea         TEXT1(PC),A0        ; Headertext
    bsr         printline
    lea         TEXT4(PC),A0        ; "BigSTE nicht installiert"
    bsr         printline
    bra.s       ende

auto:
    move.w      #1,intin
    move.l      #TEXT5,addrin       ; BigSTE aus Auto-Ordner starten ! 
    bsr         form_alert          ; Meldung ausgeben ...
    bsr         appl_exit           ; Applikation abmelden
ende:
    clr.w -(SP)
    trap        #GEMDOS             ; Ende

; — Rechner auf Vorhandensein der 
; STE-Hardware testen -----------

test_ste:
    movea.l     _p_cookies,A0       ; Cookie-Jar vorhanden ?
    beq.s       tst_end             ; Nein, dann kein STE

cookie_tst:
    cmpi.l      #'_VDO',(A0)+       ; gesuchte Cookie-ID gefunden?
    beq.s       cookie_val          ; ja, dann Wert abtesten
    lea         4(A0),A0            ; nächster Cookie
    tst.l       (A0)                ; Ende der Liste ?
    bne.s       cookie_tst          ; Nein, weiter
tst_end: 
    rts 
cookie_val:
    cmpi.l      #$010000,(A0)       ; Cookie-Wert mind. STE-Videohardware? 
    sge         ste                 ; Flag entsprechend setzen
    rts                             ; und zurück

; -- Hardcopy-Dummyroutine ----------------------

    dc.b 'XBRA' 
    dc-b 'BSTE' 
olddumpvec: 
    ds.l 1 
hardcopy:
    rts                             ; Bloß schnell wieder raus...

; ------------------------------------------------
; Timer-B-Interrupt starten und Mausaktionen überwachen ...
; -- VBL-Interrupt -----------------------------

    dc.b 'XBRA' 
    dc.b 'BSTE' 
oldvblvec: 
    ds.l 1

new_vbl:
    sf          half                ; 1. Hälfte Bildschirm zählen
    clr.b       TBCR                ; Timer anhalten
    move.l      #timer_b,TIMERBVEK  ; Eigene Timer-B-Routine auf jeden 
    ori.b       #1,IERA             ; Fall einsetzen und
    ori.b       #1,IMRA             ; Timer-B erlauben
    move.b      count(PC),TBDR      ; 1/2 Bildschirm zählen 
    move.b      #8,TBCR             ; Event-Count-Mode starten

mouse:
    movem.l     D0-A0,-(SP)         ; benutzte Register retten
    movea.l     linea_var(PC),A0    ; Adresse Line-A-Variablen
    move.w      MOUSE_X(A0),D0      ; Maus X-Position
    move.w      MOUSE_Y(A0),D1      ; Maus Y-Position
    cmp w       mousex(PC),D0       ; Mauaposition geändert ?
    bne.s       setnew              ; ja, weiter
    cmp.w       mousey(PC),D1
    beq         mouseend            ; nein, Abbruch

setnew:
    move.w      D0,mousex           ; geänderte Mausposition verarbeiten
    move.w      D1,mousey
    move.w      x_pos(PC),D2        ; linke Ecke Bildschirmanzeige 
    move.w      y_pos(PC),D3        ; obere Ecke
    move.w      D2,D4
    move.w      D3,D5
    add.w       h_mon(PC),D4        ; rechte Ecke
    add.w       v_mon(PC),D5        ; untere Ecke
    add.w       h_rand(PC),D2       ; Verschieberänder zu 
    sub.w       h_rand(PC),D4       ; Bildschirmgrenzen
    add.w       v_rand(PC),D3       ; addieren (links und oben) und 
    sub.w       v_rand(PC),D5       ; subtrahieren (rechts und unten)

    cmp.w       D2,D0               ; linker Rand erreicht ?
    bgt.s       pos1
    move.w      D2,D6
    sub.w       D0,D6               ; Verachiebewert (positiv)
    sub.w       D6,x_pos            ; von Anzeigeposition subtrahieren
    bge.s       pos2
    clr.w       x_pos               ; auf Null setzen
    bra.s       pos2

pos1:
    cmp.w       D4,D0               ; rechter Rand erreicht ?
    blt.s       pos2 
    move.w      D4,D6
    sub.w       D0,D6               ; Verschiebewert (negativ)
    sub.w       D6,x_pos 
    move.w      x_pos(PC),D6 
    add.w       h_mon(PC),D6
    cmp.w       h_rez(PC),D6        ; schon ganz rechts?
    blt.s       pos2
    move.w      h_rez(PC),D6
    sub.w       h_mon(PC),D6
    addq.w      #1,D6
    move.w      D6,x_pos            ; neue X-Position 
pos2:
    cmp.w       D3,D1               ; oberer Rand erreicht?
    bgt.s       pos3                ; nein, weiter
    move.w      D3,D7
    sub.w       D1,D7               ; Verschiebewert
    sub.w       D7,y_pos
    bge.s       adresse
    clr.w       y_pos
    bra.s       adresse
pos3:
    cmp.w       D5,D1               ; unterer Rand erreicht ?
    blt.s       adresse             ; nein, weiter
    move.w      D5,D7
    sub.w       D1,D7               ; Verschiebewert
    sub.w       D7,y_pos
    move.w      y_pos(PC),D7
    add.w       v_mon(PC),D7
    cmp.w       v_rez(PC),D7        ; schon ganz unten? 
    blt.s       adresse             ; nein, weiter
    move.w      v_rez(PC),D7 
    sub.w       v_mon(PC),D7
    addq.w      #1,D7
    move.w      D7,y_pos            ; max. untere Position

adresse:
    moveq       #0,D0
    move.l      D0,D1
    move.w      x_pos(PC),D0
    move.w      y_pos(PC),D1
    movea.l     videobase(PC),A0    ; Bildschirmbasisadresse holen
    move.w      D0,D2
    and.w       #$0F,D2
    move.w      D2,shift
    lsr.w       #4,D0               ; X-Position auf Wortgrenze
    mulu        planeanz(PC),D0     ; * Anzahl Planes
    add.w       D0,D0               ; in Bytes
    adda.l      D0,A0               ; zu Bildschirmbasis addieren
    move.w      h_rez(PC),D0        ; hor. Auflösung 
    addq.w      #1,D0               ; +1
    lsr.w       #3,D0               ; /8
    mulu        planeanz(PC),D0     ; * Anzahl Planes = Bytes pro Zeile 
    mulu        D1,D0               ; * Höhe
    adda.l      D0,A0               ; zu Bildschirmbasis addieren

    move.l      A0,videoadr         ; neue Videoadresse merken

mouseend:
    movem.l     (SP)+,D0-A0         ; benutzte Register restaurieren 
    move.l      oldvblvec(PC),-(SP) ; alte VBL-Routine 
    rts                             ; anspringen

; ---------------------------------------------
; Am Ende des Bildaufbaues Videoadressen setzen 
; -- Timer-B-Interrupt ------------------------

    dc.b        'XBRA' 
    dc.b        'BSTE' 
oldtimerb: 
    ds.l 1

timer_b:
    move.l      D0,-(SP)

    clr.b       TBCR ; Timer Stop
    move.b      count (PC),TBDR     ; Bildschirmzeilen zahlen 
    move.b      #8,TBCR             ; Event-Count-Mode starten

    not.b       half
    bne.s       hbl2end             ; erst halber Bildschirm gezählt ?

setvideo:
    tst.l       videoadr            ; aktuelle Videoadresse
    beq.s       hbl2end             ; schon gesetzt ?

    move.b      videoadr+1(PC),VBASEHI ; Videoadresse Highbyte 
    move.b      videoadr+2(PC),VBASEMID ; Videoadresse Midbyte 
    move.b      videoadr+3(PC),VBASELO ; Videoadresse Lowbyte 
    clr.l       videoadr            ; gesetzt

    move.w      line_wid(PC),D0     ; Video-Offset 
    tst.w       resolution          ; Auflösung > Low-Resolution 
    bne.s       hbl1end             ; dann Ende
    tst.w       shift               ; Wortgrenze (Pixelverschiebung=0) 
    beq.s       set_shift           ; ja, weiter
    sub.w       planeanz(PC),D0     ; nein, Offset - (1 *Anzahl Planes)
set_shift:
    move.w      shift(PC),HSCROLL   ; Verschiebung in Pixeln

hbl1end:
    move.w      D0,LINEWID          ; Video-Offset zur nächsten 
;                                     Zeile in Wortlänge
hbl2end:
    move.l      (SP)+,D0
    bclr        #0,ISRA             ; In-Service-Bit löschen
    rte

; ---------------------------------------------------
; Auf v_opnwk-Aufruf warten und Variablen patchen ...
; -- Trap #2 ----------------------------------------

    dc.b 'XBRA' 
    dc.b 'BSTE' 
oldgemvec: 
    ds.l 1

new_gem:
    cmp.l       #$73,D0             ; VDI-Aufruf ?
    bne.s       oldgem              ; nein, zum normalen Aufruf
    movea.l     D1,A0
    move.l      $0C(A0),intoutadr   ; intout-Adresse merken
    movea.l     (A0),A0             ; contrl-Adresse
    cmpi.w      #1,(A0)             ; v_opnwk-Aufruf ?
    bne.s       oldgem              ; nein, zum normalen Aufruf

    move.l      2(SP),oldgemret     ; Return-Adresse merken
    move.l      #set_vdi,2(SP)      ; und neue setzen, 

oldgem:
    move.l      oldgemvec(PC),-(SP) ; Normalen VDI-Aufruf
    rts                             ; ausführen

set_vdi:
    movea.l     intoutadr(PC),A0    ; intout-Adresse
    move.w      h_rez(PC),(A0)      ; horizontale Auflösung setzen 
    move.w      v_rez(PC),2(A0)     ; vertikale Auflösung setzen

set_linea:
    movea.l     linea_var(PC),A0

    move.w      h_rez(PC),V_REZ_HZ(A0) ; horizontale Auflösung setzen
    addq.w      #1,V_REZ_HZ(A0) 
    move.w      h_rez(PC),DEV_TAB(A0)

    move.w      v_rez(PC),V_REZ_VT(A0) ; vertikale Auflösung setzen
    addq.w      #1,V_REZ_VT(A0)
    move.w      v_rez(PC),DEV_TAB+2(A0)

    move.w      V_REZ_HZ(A0),D0     ; horizontale Auflösung
    lsr.w       #3,D0               ; /8 = Bytes pro Zeile
    move.w      D0,V_CEL_MX(A0)
    subq.w      #1,V_CEL_MX(A0)     ; maximale Cursorspalte

    mulu        planeanz(PC),D0     ; * Anzahl Planes 
    move.w      D0,v_lin_wr(A0)     ; Bytes pro Zeile 
    move.w      D0,BYTES_LIN(A0)

    mulu        V_CEL_HT(A0),D0     ; * Zeichensatzhöhe 
    move.w      D0,V_REZ_WR(A0)     ; = Bytes pro Charakterzeile

    moveq       #0,D0
    move.w      V_REZ_VT(A0),D0     ; vertikale Auflösung
    divu        V_CEL_HT(A0),D0     ; / Zeichensatzhöhe
    subq.w      #1,D0               ; - 1
    move.w      D0,V_CEL_MY(A0)     ; = maximale Cursorzeile

    lea         set_video(PC),A0    ; ’set_video' im
    bsr.s       supexec             ; Supervisormodus ausführen

    movea.l     oldgemret(PC),A0
    jmp         (A0)                ; in aufrufendes Programm zurück

set_video:
    movea.l     linea_var(PC),A0    ; Zeiger auf Line-A-Variablen 
    lea         line_w(PC),A2       ; Zeiger auf Tabelle (Bytes/Zeile) 
    move.w      resolution(PC),D1   ; Auflösungsstufe holen 
    add.b       D1,D1               ; *2
    move.w      V_REZ_HZ(A0),D0     ; horizontale Auflösung 
    lsr.w       #4,D0               ; /16
    mulu        planeanz(PC),D0     ; * Planesanzahl = Worte pro Zeile 
    sub.w       0(A2,D1.w),D0       ; - Worte pro Zeile (Standard)
    move.w      D0,LINEWID          ; = Video-Offset zur nächsten Zeile 
    move.w      D0,line_wid         ; Offset merken
    move.l      oldgemvec(PC),GEMVEKTOR ; alten GEM-Vektor restaurieren
    rts

; -- Betriebssystemaufrufe ----------------------

printline:
    pea         (A0)                ; Startadresse in AO
    move.w      #$09,-(SP)          ; Text auf Bildschirm ausgeben
    bra.s       trapgemdos

malloc:
    move.l      D0,-(SP)            ; Länge in D0
    move.w      #$48,-(SP)          ; Speicher reservieren
    bra.s       trapgemdos

mfree:
    pea         (A0)                ; Adresse in A0
    move.w      #$49,-(SP)          ; Speicher freigeben
trapgemdos:
    trap        #GEMDOS
    bra.s       stackkor

supexec:
    pea         (A0)                ; Startadresse der Routine in a0 
    move.w      #38,-(SP)           ; im Supervisormodus
    trap        #XBIOS              ; ausführen
stackkor:
    addq.l      #6,SP
    rts

; -- GEM-Aufrufe --------------------------------

form_alert:
    move.l      #$340001,control 
    move.l      #$010001,control+4 
    bra.s       call2gem

appl_init:
    move.l      #$0A0000,control 
    bra.s       call1gem

appl_exit:
    move.l      #$130000,control
call1gem:
    move.l      #$010000,control+4
call2gem:
    clr.w       control+8
    move.l      #aespb,D1
    move.w      #$C8,D0
    trap        #GEM
    rts

; -----------------------------------------------
    .data

rez:        dc.w 319,199,639,199,639,399

; Tabellen:Standardauflösungen 
line_w:     dc.w 80,80,40
planes:     dc.w 4,2,1

mousex:     dc.w 0              ; alte Maus-X-Position
mousey:     dc.w 0              ; alte Maus-Y-Position
half:       dc.b 0
count:      dc.b 0
ste:        dc.b 0
installiert: dc.b 0

TEXT0:      dc.b 27,'E'
TEXT1:      dc.b 13,10,27,'p',' BigSTE ',27,’q Version 1.2',13,10 
            dc.b '5/91, Matthias Andrä',13,10,0 
TEXT2:      dc.b 'Nicht genug freier Speicher!!!',13,10,0
TEXT3:      dc.b 'Installation durchgeführt ...',13,10,0
TEXT4:      dc.b 'Nicht installiert ...',13,10,0
TEXT5:      dc.b '[1][ |BigSTE muß unbedingt bei|Systemstart aus dem Auto-Ordner|herausgestartet werden!][ Ok ]',0 
TEXT6:      dc.b 'Hardwarevoraussetzungen nicht gegeben !',13,10,0 
TEXT7:      dc.b 'BigSTE bereits installiert!!!',13,10,0 
TEXT8:      dc.b 27,'E',0

aespb:      dc.1 control,globa1,intin,intout,addrin,addrout

    bss

linea_var:  ds.l 1 
intoutadr:  ds.l 1 
videobase:  ds.l 1 
videoadr:   ds.l 1
oldgemret:  ds.l 1

x_pos:      ds.w 1      ; Darstellung ab X-Position
y_pos:      ds.w 1      ; Darstellung ab Y-Position
h_mon:      ds.w 1      ; hor. Monitorauflösung
v_mon:      ds.w 1      ; vert. Monitorauflösung
hrez:       ds.w 1      ; eingestellte hör. Auflösung
v_rez:      ds.w 1      ; eingestellte vert. Auflösung
h_rand:     ds.w 1      ; eingestellter hor. Schieberand 
v_rand:     ds.w 1      ; eingestellter vert. Schieberand

line_wid:   ds.w 1
resolution: ds.w 1 
planeanz:   ds.w 1
shift:      ds.w 1

control:    ds.w 5
global:     ds.w 15
intin:      ds.w 16
intout:     ds.w 7
addrin:     ds.l 3
addrout:    ds.l 1

end

' ******************************************
' * BigSTE-Konfigurationsprogramm   12/90  *
' * Version 1.02        Matthias Andra     *
' * (c) 1991 MAXON Computer                *
' ******************************************
'
Bootdev%=Dpeek(&H446)+65                    ! Bootlaufwerk
Bste$=Chr$(Bootdev%)+":\AUTO\BIG_STE.PRG"   ! Pfad BigSTE 
Desktopinf$=Chr$(Bootdev%)+":\DESKTOP.INF"  ! Pfad DESKTOP.INF
'
If Dpeek(Lpeek(Gb+4))<>0 Or (Bios(11,-1) And &H10)
    ' Programm normal gestartet,
    ' oder bei Systemstart aus Auto-Ordner mit Caps-Lock aktiv?
    Void Bios(11,0)                         ! Caps-Lock desaktivieren
    Print
    If Exist(Bste$) Then                    ! 'BIG_STE.PRG' suchen
        Open "U",#1,Bste$
        Seek #1,&H1C+2
        If InputS(4,#1)="BSTE" Then         ! Programmkennung korrekt?
            @Konfiguration                  ! Dann konfigurieren 
        Else
            Print "'BIG_STE.PRG' ist nicht BigSTE ..."
            Fehler!=True                    ! Programm unbekannt
        Endif 
        Close #1 
    Else
        Print "'BIG_STE.PRG' nicht gefunden ..."
        Fehler!=True                        ! BigSTE nicht im Auto-Ordner.
    Endif
    Print
    If Fehler! Then
        Print "Konfiguration nicht möglich !!!"
    Else
        Print "BigSTE konfiguriert ..."
        @Patch_desktop_inf                  ! Auflösung in "DESKTOP.INF" anpassen
    Endif
    Print
Endif
'
Pause 20 
Edit
'
Procedure Konfiguration
    ' Einlesen der alten BigSTE-Parameter,
    ' Verändern der Werte durch Benutzer und 
    ' neues Setzen der BigSTE-Parameter
    Local A$,B$,A%
    Repeat
        Cls
        Print '''''''Chr$(27);"p BigSTE -Konfiguration ";Chr$(27);"q"
        Print "             Version 1.02"
        Print "         von Matthias Andrä"
        '
        Seek #1,&H1C+6
        '
        A$="j"
        Print At(1,5);"BigSTE Installation (j,n)?: "; 
        Form Input 1 As A$
        A$=Upper$(A$)
        A%=Cvi(Input$(2,#1))
        Relseek #1,-2 
        If A$="J" Then
            Print #1,Mki$(A% And 1);
            Relseek #1,-2
            @Werteingabe(7,"Farb-Auflösungsmodus [0,1] ?: ",0,1,1,1)
            '
            Print At(1,9);"Niedrige Auflösung (in Pixel)"
            @Werteingabe(10,"Horizontal [320..1280]?: ",320,1280,16,4)
            @Werteingabe(11," Vertikal [200..800]?: ",200,800,8,3)
            Print At(1,9);"Mittlere Auflösung (in Pixel)"
            @Werteingabe(10,"Horizontal [640..2560]?: ",640,2560,16,4)
            @Werteingabe(11," Vertikal [200..800]? : ",200,800,8,3)
            Print At(1,9);"Hohe Auflösung (in Pixel)" 
            @Werteingabe(10,"Horizontal [640..2560]?: ",640,2560,16,4)
            @Werteingabe(11," Vertikal [400..1600]? : ",400,1600,16,4)
            '
            Print At(1,13);"Schieberand (niedrige Auflösung)"
            @Werteingabe(14,"Horizontal [0..120] ?: ", 0,120,1,3)
            @Werteingabe(15," Vertikal [0.75] ?: ", 0, 75,1,2)
            Print At(1,13);"Schieberand (mittlere Auflösung)"
            @Werteingabe(14,"Horizontal [0..240] ?: ",0,240,1,3)
            @Werteingabe(15," Vertikal [0..75] ?: ", 0,75,1,2)
            Print At(1,13);"Schieberand (hohe Auflösung) " 
            @Werteingabe(14,"Horizontal [0. 240] ?: ", 0,240,1,3)
            @werteingabe(15," Vertikal [0.150] ?: ", 0,150,1,3)
            '
            B$="j"
            Print At (1,17);"Eingaben in Ordnung (j, n): ";
            Form Input 1 As B$
            B$=Upper$(B$)
        Else
            Print #1,Mki$(A% Or 2);
        Endif
    Until A$<>"J" Or B$="J"
Return
'
Procedure Werteingabe(Y%,Text$,Min%,Max%,Schritt%,Stellen%)
    ' Automatisierte Werteingaberoutine 
    Local Wert$
    Wert$=Str$(Cvi(Input$(2,#1))+Min%)
    Repeat
        Print At(1,Y%);Chr$(27);"K";Text$;
        Form Input Stellen% As Wert$
        Wert$=Str$((Val(Wert$) Div Schritt%)* Schritt%)
    Until Val(Wert$)>=Min% And Val(Wert$)<=Max% 
    Print At(1,Y%);Chr$(27);"K";Text$;Wert$ 
    Relseek #1,-2
    Print #1,Mki$(Val(Wert$)-Min%);
Return
'
Procedure Patch_desktop_inf 
    Local A$,A%,B%,P%
    Print
    If Exist(Desktopinf$)
        If Exist(Bste$) Then
            Open "U",#1,Desktopinf$
            Open "I",#2,Bste$
            Seek #2,&H1C+2
            If Input$(4,#2)=”BSTE" Then ! BigSTE Programmkennung korrekt? 
                A%=Cvi(Input$(2,#2)) ! BigSTE Auflösungsstufe lesen. 
                If A%<2 Then ! Soll BigSTE installiert werden? 
                    A%=2-A% ! Auflösung in 'DESKTOP.INF'-Format 
                    A$=Input$(Lof(#1),#1)
                    P%=Instr(A$,"#E ") ! Auflösungsinformation im "DESKTOP.INF"
                    If P%>0 Then ! gefunden?
                        B%=Val("&"+Mid$(A$,P%+7,1)) ! Lesen
                        If B%<>A% ! Auflösungen unterschiedlich?
                            Seek #1,p%+6
                            Out #1,Asc(Hex$(A%)) ! Auflösung in "DESKTOP.INF" schreiben. 
                            Print "BigSTE-Auflösung in 'DESKTOP.INF' angepafit ..."
                        Endif
                    Endif
                Endif
            Else
                Print "'BIGSTE.PRG' ist nicht BigSTE ..." ! Programm unbekannt.
            Endif
            Close
        Else
            Print "'BIG_STE.PRG' nicht gefunden ..." 
        Endif 
    Else
        Print "'DESKTOP.INF' nicht gefunden ..." 
    Endif 
    Print 
Return


Matthias Andrä
Aus: ST-Computer 01 / 1992, Seite 114

Links

Copyright-Bestimmungen: siehe Über diese Seite