Mit diesem Programm läßt sich der Monochrom-Modus des ATARI ST auf einem Farbmonitor darstellen. Eine Vielzahl von Programmen (leider nicht alle) laufen mit diesem Schwarzweiß-Emulator. Natürlich erreicht man nicht die Qualität eines SM124, doch das Programm zeigt doch eine interessante Möglichkeit, wie man den ST manipulieren kann. Es ist allerdings notwendig, einige direkte Sprungadressen zu benutzen, so daß man einige Zeilen abändern muß, damit es auch auf dem Blitter-TOS läuft. Die Änderungen werden am Ende des Artikels angegeben.
Zuerst wird die TOS-Variable phystop ($42E) heruntergesetzt und dadurch Raum für einen zweiten Bildschirmspeicher und einige Routinen geschaffen, die nach einem Reset erhalten bleiben. Der Wert von phystop ändert sich bei einem Warmstart nicht.
Hinter phystop werden folgende Routinen abgelegt:
Eine veränderte vbl-Interrupt-Routine, bei der erstens der Monitor-Detect abgeschaltet ist (normalerweise führt der Computer ein Reset aus, wenn er merkt, daß im Schwarzweiß-Modus ein Farbmonitor angeschlossen ist oder andersherum) und die zweitens dafür sorgt, daß der Schwarzweiß-Bildschirmspeicher in den 2. Bildschirmspeicher hinter phystop übertragen und dabei auch gleich an die verschiedenen Modi angepaßt wird. Aus zeitkritischen Gründen wird dabei bei jedem vbl-Interrupt jeweils nur ein Viertel des Bildschirms übertragen, sonst würde der Computer extrem langsam werden.
Außerdem wird geprüft, ob sich vielleicht das Invers-Bit geändert hat. Die Farben paßt man dann entsprechend daran an. Auch eine Veränderung der Adresse des Schwarzweiß-Bildschirmspeichers wird erkannt und sofort gespeichert. Bei aktiven Floppies wird auch bei eingeschaltetem Emulator der Bildschirmspeicher nicht übertragen, da es sonst zu Fehlern kommen kann.
Über dump_vec springt der Computer jedesmal, wenn ALT/HELP gedrückt wird. Normalerweise erzeugt man damit eine Hardcopy auf dem Drucker. Hier dient dieser Vektor dazu, den Emulator ein- und auszuschalten (MIT Shift-Taste), bzw. zwischen den verschiedenen Modi hin- und herzuschalten (OHNE Shift-Taste). Beim Ausschalten des Emulator setzt diese Routine wieder die originale Bildschirmadresse.
Folgende Xbios-Routinen werden verändert:
Xbios(4)=Getrez liefert immer den Wert 2 = High-Res zurück.
Xbios(2)=Physbase liefert bei eingeschaltetem Emulator die Adresse des Schwarzweiß-Bildschirmspeichers zurück.
Xbios(5)=Setscreen verändert bei eingeschaltetem Emulator nicht die wirkliche Bildschirmadresse (ab der der Videoprozessor abbildet), sondern die Adresse des Bildschirmspeichers, aus dem übertragen wird. Ein Ändern der Auflösung mit dieser Routine wird unterdrückt. Sonst verhält sich diese Routine wie gewöhnlich.
Bei allen anderen Xbios-Aufrufen werden die Original-Routinen angesprungen.
Diese sorgt nur dafür, daß während der Abarbeitung eines Keyboard-Interrupts der vbl-Interrupt eingeschaltet ist, da es sonst zu unschönen Erscheinungen kommen kann.
Außerdem werden hinter phystop noch einige Variablen, die der Emulator benötigt, gespeichert:
In alt_adr speichert er die Adresse des Schwarzweiß-Bildschirmspeichers, aus dem bei eingeschaltetem Emulator übertragen wird.
In neu_adr speichert er die Adresse des 2. Bildschirmspeichers hinter phystop, auf den bei eingeschaltetem Emulator der Videoprozessor gesetzt ist. Diese Adresse wird nur am Anfang gemerkt und dann nicht mehr verändert.
In aufl merkt er sich, ob er ein- oder ausgeschaltet ist. 1=An, 2=Aus.
In modus merkt er sich, in welchem der 4 Modi er sich befindet:
modus=0 : Jede 2. Zeile wird abgebildet (alle ungeraden Zeilen).
modus=1 : Jede 2. Zeile wird abgebildet (alle geraden Zeilen).
modus=2 : Der obere Teil des Bildschirms wird abgebildet.
modus=3 : Der untere Teil des Bildschirms wird abgebildet.
Nachdem das Programm die obigen 4 Routinen und die Variablen hinter phystop abgelegt hat, wird eine Routine erzeugt, die nach einem Reset automatisch aufgerufen wird. Wer Genaueres wissen will, sollte sich das ROM ab $fc0d20 ansehen. Eine Reset-Routine muß unterhalb von phystop an einer Adresse stehen, die ein Vielfaches von 512 ist. Das erste Langwort muß das “Magic” $12123456 sein, das zweite Langwort die Adresse des Magics enthalten und die Prüfsumme über 256 Worte = $5678 sein. Die Routine wird nach dem Laden des Boot-Sektors, aber noch vor dem Ausführen des Auto-Ordners, ausgeführt. In dieser Routine werden nur die Adressen der vier veränderten Aufrufe und die Auflösung = High gesetzt und dann die Bildschirmausgabe neu initialisiert.
Nach dem Laden des Programms prüft dieses zuerst, ob sich der Computer im Schwarzweiß-Modus befindet. Wenn ja, wird das Programm sofort wieder verlassen und nichts geschieht. Im anderen Fall wird die Kurzanleitung ausgegeben und dann die Routine “supexec” im Supervisor-Modus angesprungen. Diese macht nun nichts anderes, als phystop herunterzusetzen, die verschiedenen Routinen zu verschieben und die Reset-Routine zu erzeugen. Danach wird in einer Endlos-Schleife solange gewartet, bis der Resetknopf gedrückt wird.
Für all diejenigen, die mit dem Blitter-TOS arbeiten, müssen folgende Zeilen im Listing abgeändert werden:
Zeile 88 in: btst #1,$e61
Zeile 180 in: jmp $fc0748
Zeile 182 in: jmp $fc071a
Zeile 214 in: jmp $fc07f2
Zeile 235 in: jmp $fc29ce
Zeile 252 in: jmp $fca96e
; Schwarzweiß Emulator
;
; (C) Volker Ullrich 1987
; Postfach 1646
; 7770 Überlingen
;
; bitte relozierbar anklicken
phystop equ $42e
swv_vec equ $46e
dump_vec equ $502
sshiftmod equ $44c
move #4,-(a7)
trap #14 ; xbios 4, Getrez
cmpi #2,d0 ; Schon Highres?
beq.s term ; ja = term
pea message
move #9,-(a7)
trap #1 ; Gemdos 9. Print Line
pea supexec
move.w #38,-(a7)
trap #14 ; xbios 38. Supexec
term:
clr (a7)
trap #1 ; gemdos 0, Term
supexec:
; Hier nachfolgende Routinen verschieben, Prüfsumme
; erzeugen, phystop anpassen etc.
move.l phystop,a0
suba.l #$8000,a0 ; a0 = Adresse 2. Bildschirmbereich
move.l a0,neu_adr
suba.l #$200,a0 ; a0 = Adresse neues phystop
move.l a0,phystop
move.l a0,al ; phystop retten
suba.l #$8200,a1 ; a1 = Adresse Reset-Routine
lea -4(a1),a7 ; Stack heruntersetzen
move.l #vbl_sprung,a2
move #255,d0 ; Länge change_aufl + ubl2 : ca. 256 Worte
verschieben:
move.w (a2)+,(a0)+ ; change_aufl hinter phystop kopieren
dbra d0,verschieben
move.l al,a0 ; a0 = Anfang Reset-Routine
move #127,d0 ; 128 Langworte
loeschen:
clr.l (a0)+ ; Platz für Reset-Routine loschen
dbra d0,loeschen
move.l a1,a0 ; a0 = Anfang Reset-Routine
move.l #reset_resident,a2
move #39,d0 ; Länge: ca. 40 Worte
verschieben2:
move.w (a2)+,(a0)+ ; Reset-Routine verschieben
dbra d0,verschieben2
move.l a1,4(a1) ; Adresse der Routine speichern
move #255,d0 ; 256 Worte für Prüfsumme
clr d1 ; Prüfsumme löschen
pruefsumme:
add (a1)+ ,d1 ; Prüfsumme erzeugen
dbra d0,pruefsumme
move #$5678,d0
sub d1,d0
move d0,-(a1) ; Prüfsumme korrigieren
endlos:
bra.s endlos ; Auf Reset warten
; Die folgenden Routinen werden hinter phystop gespeichert:
vbl_sprung:
bra vbl2 ; geänderter vbl Interrupt Aufruf
bra xbios2 ; geänderter xbios Aufruf
bra keyb_int ; geänderter mfp 68901 Level 6-Interrupt
bra.s change_aufl ; geänderter dump_vec
alt_adr:
dc.l 0
neu_adr:
dc.l 0
aufl:
dc.b 2 ; default: High=Emulator aus
modus:
dc.b 0 ; Modus : Jede 2. Zeile a)
change_aufl: ; Aufruf dieser Routine mit Alt/Help
lea alt_adr(pc),a0 ; Anfang Uariablen in a0
btst #1,$elb ; linke Shifttaste?
bne.s shift ; ja
addq.b #1,9(a0) ; wenn nicht gedrückt: modus erhöhen
andi.b #3,9(a0) ; falls 4 erreicht, wieder modus=0
rts
shift:
eori.b #3.8(a0) ; Hier Auflösung Umschalten
cmpi.b #l,8(a0) ; Neue Auflösung = Mid ?
bne.s aufl_high ; Nein
moveq.l #0,d0 ; Hier wenn neue Auflösung Mid
move.b $ff8201,d0
lsl.w #8,d0
move.b $ff8203,d0
lsl.l #8,d0 ; physikalische Uideoadr. in d0
move.l d0,(a0) ; in alt_adr merken
move.l 4(a0),-(a7) ; Neue Videoadresse auf Stack
video_setzen:
move.b 1(a7),$ff8201; und setzen
move.b 2(a7),$ff8203
clr.l (a7)+ ; Stack löschen
rts
aufl_high:
move.l (a0),-(a7) ; Alte Videoadresse auf Stack
bra.s video_setzen ; und setzen
vbl2: ; veränderte vbl-Routine ohne Monitor-Detect
movem.l d0-d7/a0-a6,-(a7) ; Register retten
lea alt_adr(pc),a0 ; Anfang Uariablen in a0
move.b 8(a0),d0 ; Auflösung in dB
move.b d0,$ff8260 ; und setzen
cmpi.b #1,d0 ; Mid Auflösung ?
bne nix ; Nein : nichts verschieben
move.l #$ffff,d0 ; Hier wenn Auflösung Mid
btst #0,$ff8241 ; Bit Null Farbpalettenregister 0 gesetzt ?
bne.s invers ; ja
swap d0 ; sonst : Maske vertauschen
invers:
move d0,$ff8240 ; schwarze und weiße Farbe setzen
swap d0
move d0,$ff8246
moveq.l #0,d0 ; aktuelle Videoadresse ausrechnen
move.b $ff8201, d0
lsl.w #8,d0
move.b $ff8203,d0
lsl.l #8,d0
cmp.l 4(a0),d0 ; muß bei Mid = neu_adr sein
beq.s gleich
move.l d0,(a0) ; sonst: alt_adr neu setzen
move.l 4(a0),-(a7) ; neu_adr auf Stack
move.b 1(a7),$ff8201 ; und setzen
move.b 2(a7),$ff8203
clr.l (a7)+ ; Stack löschen
gleich:
tst.w $43e ; flock, Floppies aktiu ?
bne.s nix ; Ja : nichts verschieben
move.w $468,d0 ; vbl-Zähler
andi.w #3,d0
mulu #8000,d0 ; Jeden vbl ein Viertel übertragen
move.l 4(a0),a1 ; Neue Videoadresse in a1
move.l (a0),a2 ; Alte Videoadresse in a2
move.b 9(a0),d1 ; Modus in d1
bne.s modus1
lea 80(a2),a2 ; 2. Zeilensatz
modus1:
cmpi.b #3,d1
bne.s modus2
adda.l #16000,a2 ; untere Bildschirmhälfte
modus2:
adda.l d0,al
moveq.l #80,d2 ; Jede 2. Zeile uerschlucken
btst #1,d1
beq.s modus3
clr.l d2 ; Modus 2,3: Jede 2. Zeile nicht verschlucken
asr.l #1,d0 ; d0/2
modus3:
adda.l d0,a2
move #49,d1 ; 50 Zeilen
schleife1:
move #39,d0 ; 80 Bytes je Zeile
schleife2:
move (a2),(a1)+
move (a2)+,(a1)+
dbra d0,schleife2
adda.l d2,a2 ; Jede 2. Zeile verschlucken
dbra d1,schleife1
nix:
addq.l #1,$466 ; wie Original
subq.w #1,$452 ; wie Original
bmi.s gesperrt ; wie Original
addq.l #1,$462 ;
sub.l a5,a5 ;
jmp $fc069e ; und Sprung in Original Routine (aber hinter der kritischen Stelle)
gesperrt:
jmp $fc071a ; vbl gesperrt: Sprung an Ende der Routine
; Obige zwei Sprungadressen gelten nur für ROM-TOS !!
xbios2:
lea 6(a7),a0 ; Adresse Funktionsnummer in a0
btst #5,(a7) ; Aufruf aus Supervisor ?
bne.s supervisor ; ja
move.l usp,a0 ; Adresse Funktionsnummer in a0
supervisor:
lea alt_adr(pc),a1 ;Adresse Variablen in a1
cmpi #4,(a0) ;=4? (Getrez)
bne.s weiter ; nein
moveq.l #2,d0 ; Getrez = 2
rte
weiter:
cmpi #2, (a0) ; = 2? (Physbase)
bne.s weiter2 ; nein
move.l alt_adr(pc),d0 ; Physbase = alt_adr
cmpi.b #1,8(a1) ; Emulator an?
beq.s physb_aus ; Ja
moveq.l #0,d0 ; sonst: aktuelle Videoadresse ausrechnen
move.b $ff8201,d0
lsl.w #8,d0
move.b $ff8203,d0
lsl.l #8,d0
physb_aus:
rte
weiter2:
cmpi #5,(a0) ; = 5 ? (Setscreen)
beq.s setscreen
jmp $fc0748 ; Original xbios, nur für R0M-T05
setscreen:
tst.l 2(a0)
bmi.s setscreen2
move.l 2(a0),$44e ; _v_bs_ad setzen
setscreen2:
tst.l 6(a0)
bmi.s setscr_aus
move.l 6(a0),(a1) ; physbase in alt_adr speichern
cmpi.b #1,8(a1) ; Emulator an ?
beq.s setscr_aus ; Ja
move.l 6(a0),-(a7) ; Sonst: auch Videoadresse setzen
move.b 1(a7),$ff8201
move.b 2(a7),$ff8203
clr.l (a7)+ ; Stack löschen
setscr_aus: ; Auflösung ändern wird unterdrückt
rte
keyb_int:
andi.b 8$fb,(a7) ; Interruptmaske 0-3, vbl enable
jmp $fc281c ; Sprung in Original Routine
; obige Adresse gilt nur für ROM-TOS !
reset_resident:
; Wird an 512 Grenze kopiert und nach Reset ausgeführt
de.1 $12123456 ; Magic
dc.l 0 ; Hier kommt Adresse des Magic hinein
move.l phystop,a0
move.l a0,$70 ; Level 4 Interrupt : Auf vbl2
lea 4(a0),a0 ; a0 += 4
move.l a0,$b8 ; Trap 814 : Auf xbios2
lea 4(a0),a0
move.l a0,$118 ; mfp 68901, Level 6 auf keyb_int
lea 4(a0),a0
move.l a0,$502 ; dumpvec auf change_aufl
move.b 82,sshiftmod ; Auflösung setzen
jmp $fca7c4 ; Bildschirmausgabe initialisieren + rts
; Adresse gilt nur für ROM-TOS !
data
message:
dc.b 27,"u",27,"E" ; Überlauf ein & Cls
dc.b "Schwarz-Weiß Emulator ® 1987 Volker Ullrich", 13,10
dc.b "Dieses Programm simuliert auf einem Farbmonitor einen Schwarzweiß Monitor.", 13,10,13,10
dc.b "Bedienung:", 13,10,13,10
dc.b "Shift/Alternate/Help —> Emulator An/Aus",13,10
dc.b "Alternate/Help —> Modus umschalten",13,10
dc.b "Da ein Farbmonitor nur die Hälfte der Zeilenanzahl eines Schwarz-Weiß Monitors",13,10
dc.b "darstellen kann (640x206 anstatt 640x400 Punkte), wird mit Alt/Help zwischen",13,10
dc.b "4 Möglichkeiten umgeschaltet:",13,10
dc.b "1.) Nur jede 2. Zeile wird abgebildet (1. , 3., 5., 7. usw.)",13,10
dc.b "2.) Wie oben, jedoch 2.. 4., 6. usw. Zeile",13,10
dc.b "3.) Nur die obere hälfte des Bildschirms wird abgebildet",13,10
dc.b "4.) Nur die untere Hälfte des Bildschirms wird abgebildet",13,10,13,10
dc.b "Funktioniert nur mit ROM-TOS ! ", 13,10
dc.b "Kann auch in den Auto-Ordner kopiert werden.”,13,10,13,10
dc.b "Jetzt bitte eine Diskette einlegen und den Resetknopf drücken. Der Computer geht"
dc.b "dann automatisch nach kurzer Zeit in den Hochauflösenden Modus. Nach Beendigung".13,10
dc.b "des Ladevorgangs Shift/Alt/Help drücken, um den Emulator einzuschalten.",13,10,13,10,0