Schwarz-Weiß-Emulator

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.

Das Prinzip

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.

Eine veränderte dumpvec-Routine

Ü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.

Ein veränderter Xbios-Aufruf

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.

Eine geänderte Keyboard-Interrupt-Routine

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.

Änderungen für Blitter-TOS

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

Volker Ullrich
Aus: ST-Computer 07 / 1988, Seite 85

Links

Copyright-Bestimmungen: siehe Über diese Seite