
ASSEMBLERKURS - LEKTION 23: Display/Screen (Version 2: Stand: 09/2024)

Autor: Göran Strack


Über DIWSTART, DIWSTOP wurde bereits in Lektion5 gesprochen, aber vielleicht
hilft dieser Beitrag das etwas "sperrige" Thema besser zu verstehen.

Screen-Positionen DIW
===============================================================================

Bekanntlich ist um den sichtbaren Screen ein schwarzer Rand. Gehen wir von
einem normalen Lowres-Screen mit (320x256) Pixeln aus so sind die typischen 
Einstellungen für diw und ddf folgende:

	dc.w	$8e,$2c81	; DiwStrt
	dc.w	$90,$2cc1	; DiwStop
	dc.w	$92,$38		; DdfStart
	dc.w	$94,$d0		; DdfStop

Warum?

Wir können z.B. durch Versuche die äusseren Begrenzungen des Bildschirmfensters
finden, bei dem ein 320x256 Lowres-Screen vollständig auf dem Bildschirm zu
sehen ist.

für DIWSTRT:
normal:				 v=$2c (44), h=$81 (129) 	dc.w	$8e,$2c81	; DiwStrt
linke, obere Ecke:	 v=$1a (26), h=$5c (92)		dc.w	$8e,$1a5c	; DiwStrt
linke, untere Ecke:	 v=$38 (56), h=$5c (92		dc.w	$8e,$385c	; DiwStrt
rechte, obere Ecke:	 v=$1a (26), h=$94 (148)	dc.w	$8e,$1a94	; DiwStrt
rechte, untere Ecke: v=$38 (56), h=$94 (148)	dc.w	$8e,$3894	; DiwStrt

und für DIWSTOP:
normal:				 v=$2c (44+256=300), h=$c1 (449)	
linke, obere Ecke:	 v=$1a (26+256=282), h=$9c (412)	
linke, untere Ecke:	 v=$38 (56+256=312), h=$9c (412) 	
rechte, obere Ecke:	 v=$1a (26+256=282), h=$d4 (468)     
rechte, untere Ecke: v=$38 (56+256=312), h=$d4 (468) 	

also:
dc.w	$90,$2cc1	; DiwStop	($81+320=$1c1=449)
dc.w	$90,$1a9c	; DiwStop	($5c+320=$19c=412)
dc.w	$90,$389c	; DiwStop	($5c+320=$19c=412)
dc.w	$90,$1ad4	; DiwStop	($94+320=$1d4=468)
dc.w	$90,$38d4	; DiwStop	($94+320=$1d4=468)

Wir haben also folgende Punkte gefunden:
linke, obere Ecke:	 h=$5c (92) , v=$1a (26)
linke, untere Ecke:  h=$5c (92) , v=$38 (56+256=312)
rechte, obere Ecke:  h=$d4 (468), v=$1a (26)
rechte, untere Ecke: h=$d4 (468), v=$38 (56+256=312)


Gesamtgröße sichtbarer Bildschirmbereich:
		
		92,26 ($5c,$1a)						468,26 ($1d4,$1a)
						------------------
						|  ------------  |
						| |			   | |
						| |            | |
						| |			   | |
						| |			   | |
						| -------------- |
						------------------
	   92,312 ($5c,$138)			        468,312 ($1d4,$138)

Abbildung 1: Screenpositionen


Mit dem Wisssen können wir den normalen Lowres-Screen zentrieren.
Distanz x= 468-92=376	($1d4-$05c=376px) max overscan
Distanz y= 312-26=286	($138-$01a=286px) max overscan

Jetzt berechnen wir den Rest (Rand):
Rest x = 376-320=56		
Rest y = 286-256=30

Nun jeweils die Hälfte:
56/2=28 ($1c)
30/2=15 ($F)

Und verschieben den Screen entsprechend:
linke, obere Ecke:	 v=$1a (26)	, h=$5c (92)	dc.w	$8e,$1a5c	; DiwStrt
h=$5c+$1c=$78
v=$1a+$F=$29

Und erhalten:					dc.w	$8e,$2978	; DiwStrt	
								dc.w	$90,$29b8	; DiwStop
was etwas abweichend ist von	dc.w	$8e,$2c81	; DiwStrt
								dc.w	$90,$2cc1	; DiwStop
		
Die horizontale Position $81 (129) ist jedoch ein Vielfaches von 16 + 1Pixel.
128/16=8 und ist somit bedingt durch data fetch DDFSTRT geeigneter. 

Das Listing23a.s zeigt verschiedene Positionen des Screens auf dem Bildschirm.
Zudem springt ein Sprite zwischen den möglichen Screenecken.

Spezial-Anmerkung von EAB (ross) zu DIW:
===============================================================================

horizontal:
$000~$05B hard blank (*)
$05c~$080 left soft blank
$081~$1c0 (320px)
$1c1~$1d3 right soft blank

Gesamtsumme:	($1d4-$05c=376px) max overscan

vertikal:
$000~$019 hard blank (on $019 you get first DMA sprite fetches)
$01a~$02b upper soft blank
$02c~$12b (256py)
$12c~$137 lower soft blank
$138 LOF last line (A1000 usable, other systems only COLOR00)

Gesamtsumme:	($138-$01a=286px) max overscan

Ab (*) CCK $e3 --> ($1c6) 'virtual lowres pixels' sind wir bereits in der
nächsten Zeile. Denise interner Zählerbereich ist von 2 bis 455
(mit 2 erweitert) und aus diesem Grund ist die letzte erreichbare 
Position für DIWSTOP(x) $c7.


Besonderheiten DIW
===============================================================================

Nachdem die Screengröße und die Position auf dem Bildschirm festgelegt wurde,
gibt es weitere Besonderheiten oder Einschränkungen die zu beachten sind.
Diese Einschränkungen sind darauf zurückzuführen, dass wir nur $FF (255) Pixel
als vertikale bzw. horizontale Position angeben können und nicht z.B. den
Bereich von 0 bis 511.

Generell ist die Auflösung die mit den Registern DiwStrt und DiwStop erzielt
werden kann vertikal - eine Rasterzeile und horizontal - ein Pixel.
Ausserhalb des sichtbaren Bereichs wird die Rahmenfarbe mit der
Hintergrundfarbe, also Color00 angezeigt.

DIWs definieren den Soft-Blank-Bereich der Anzeige, in dem COLOR00 verwendet
wird, um "unerwünschte" Teile abzudecken. Darüber hinaus definieren y-DIWs 
auch, auf welcher Zeile das Bitplane-DMA beginnt und endet. Deshalb besteht
der Nebeneffekt darin, den Bildschirm vertikal zu "verschieben". Der 
horizontale Anfang auf der Zeile für das Bitplane-DMA wird stattdessen durch
DDFSTRT definiert. Und x- und y-DIWs sind funktional unterschiedlich (obwohl
sie scheinbar ähnliche Dinge tun). Sie können die Anzeige mit DIWs nicht
horizontal verschieben und eigentlich nicht einmal vertikal, es ist nur ein
"Nebeneffekt".

Hintergrund ist, dass man verstehen muss, dass ein Teil von DIW, das y, in
Agnus ist, während das x in Denise ist. Denise ist "blind", es hat absolut
keine Ahnung, auf welcher Zeile es sich befindet, und benötigt STROBE-Signale,
um bestimmte Aktionen auszuführen.
Agnus steuert alle DMA-Aktivitäten und verfügt daher sowohl auf der y-Achse
(y-DIW) als auch auf der x-Achse (DDFSTRT) über Startregister; dementsprechend
definiert es implizit auch das Blank für die y-Koordinaten.
Denise hingegen kümmert sich um die Ausgabe der Videodaten (Bitplanes und
Sprites) und muss daher das (Soft-)Blanking für die x-Achse (x-DIW) und die
Position für die Datenfreigabe (BPLCON1) verwalten.

Allgemein gesagt:
DIWSTRT (Display Window Start) - $08 - legt die horizontale und vertikale 
									   Position fest (Zeile und Pixel)
DIWSTOP (Display Window Stop)  - $90 - Endposition

DIWSTRT legt linke, obere Ecke fest
DIWSTRT  - H0 bis H7 - d.h. 8 Bits - 256 Spalten, d.h. von $0 bis $FF
		 - V0 bis V7 - d.h. 8 Bits - 256 Zeilen,  d.h. von $0 bis $FF
		   fehlende V8,H8 werden als 0 angesehen		 	

Das gleiche gilt für die horizontale Endposition, hier jedoch:
DIWSTOP  - H0 bis H7 - d.h. 8 Bits - 256 Spalten, d.h. von $0 bis $FF
		 - V0 bis V7 - d.h. 8 Bits - 256 Zeilen,  d.h. von $0 bis $FF
Das	fehlende H8 wird als 1 angesehen	--> damit den Bereich von 256 bis 511
											d.h. 1.0000.0000 bis 1.1111.1111
Für das	fehlende V8 gilt:
Das MSB der vertikalen Endposition, V8, wird durch invertieren des V7-Bits
erzeugt. Dadurch ist die Endposition im Bereich der Zeilen 128 bis 383 möglich.

bei Endpositionen von 256 bis 383 setzt man V7 auf 0 und damit ist V8 auf 1
bei Endpositionen von 128 bis 255 setzt man V7 auf 1 und damit ist V8 auf 0

theoretischer Screen:

V7=1
0.1000.0000 bis 0.1111.1111 = 128 bis 255	--> $80  bis $FF	
							  --> resultierend: $080 bis $0FF

V7=0 --> V8=1
1.0000.0000 bis 1.0111.1111	= 256 bis 383   --> $00 bis $7F
						      --> resultierend: $100 bis $17F

Eine vertikale Endposition kann daher nicht kleiner als 128 sein!
Und die vertikale Startposition kann nicht größer als 255 sein!

Beispiel:
Der normale Lowres-Screen (320x256 ) liegt bei:

	dc.w	$8e,$2c81	; DiwStrt - linke, obere Ecke festgelegt bei:
						; vertikal $2c (44), horiz. $81 (129)
	dc.w	$90,$2cc1	; DiwStop - rechte, untere Ecke festgelegt bei:						  
						; vertikal $(1)2c (300), horiz. $(1)c1 (449)

d.h.
DIWSTRT	$2c81	$VVHH	      $2c=44		 $81=129
DIWSTOP $2cc1	$VVHH	$2c=$12c=300	$c1=$1c1=449

für DIWSTOP: 
    HH - H8 ist 1		; das fehlende H8 wird als 1 angesehen:
	VV - $2c ist 0010.1100 und damit ist V7=0 -->
			 darausfolgt V8=1 --> 1.0010.1100=300	


Grenzen der DIWSTRT-DIWSTOP-Positionen (vertikal)
===============================================================================

  --- $0		----- DIWSTRT von $00 bis $FF (0 bis 255) möglich
   |			|
   | - $1a      |	$1A - Beginn sichtbarer Bereich 
   |			
   |			
   |
   |
   |														|
   | -$7F													| 
   | -$80												 --- $80 (128)		
   | -$81											   höchste DIWSTOP-Position 
   |
   |
   |
   |
   |
   |
   |
   |
   |
   |														|
   |				 letzte DIWSTRT-Position $FF			|
   | -$FF	   ----- DIWSTRT von $00 bis $FF möglich   ----- $FF (255) 
   |		   |											 $00 (256) =$(1)00
   |		   |
   |
   |				$137 - letzte sichtbare Zeile
  --- $138		
  										

															|
															|
													   ----- $7F(383) =$(1)7F
													   tiefste DIWSTOP-Position							   
													   	 

Abbildung 2: DIWSTRT-DIWSTOP-Positionen (vertikal)
															
oben:		Screen-Grenzen DIWSTRT: $1a (26)  bis DIWSTOP: $80 (128)		
Mitte:		Screen-Grenzen DIWSTRT: $81 (129) bis DIWSTOP: $FF (255)
unten:		Screen-Grenzen DIWSTRT: $FF (255) bis DIWSTOP: $38 (312)


Grenzen der DIWSTRT-DIWSTOP-Positionen (horizontal)
===============================================================================

|----------------------------------------------------------------------|
|	   |	 | 					       |							   |	
$0    $5c	$81							$FF							 $(1)d4	
 ____						            ____		
|										| 
|										|		
	DIWSTRT: horizontal XX von $00 bis $FF d.h. von 0 bis 255



	DIWSTOP: horizontal XX von $00 bis $FF ist $(1)00=256 bis $(1)FF=511

										|								     |
									____|							      ___|
									$(1)00=256					    $(1)FF=511
									
Abbildung 3: DIWSTRT-DIWSTOP-Positionen (horizontal)

Noch ein Hinweis zum horizontale DIW. Das x-DIW wird wie gesagt von Denise
kontrolliert und Denises interner horizontaler Zähler zählt doppelt so schnell
wie der horizontale Zähler von Agnus (2, nicht 0! bis 455 ($1c7)) [in PAL].
Dh. wenn ein x-DIW <2 eingestellt wird, wird kein Fenster geöffnet, weil die
Startbedingung fehlt. Im anderen Fall, wenn x-DIW >$(1)c7 ist bleibt das 
geöffnete Fenster die ganze Zeit offen, weil die schließende Position nie
übereinstimmt.) Man spricht dann vom vollständigen horizontalen Overscan.

Die Programmbeispiele Listing23a2.s, Listing23a3.s, Listing23a4.s und
Listing23a5.s spielen mit den DiwStrt- und DiwStop-Werten.


DDF - Data Fetch
===============================================================================

Die Berechnung für den Lowres-Screen erfolgt durch: 
DDFSTRT=(HSTRT/2)-8,5 AND $FFF8				Bsp: ($81/2)-8,5 AND $FFF8	=$38
DDFSTOP=DDFSTRT+(PixelproZeile/2-8)				  $38+(320/2-8)			=$d0

Warum? Und was bedeutet das?

Erstmal:
DDFSTRT kann nicht kleiner als $18 sein und
DDFSTOP	ist auf maximal $D8 begrenzt.

Übliche Werte sind $18,$20,$28,$30,$38,$40 usw. bis $D0, $D8. (Lowres-Screen)

Falls die Register mit Werten ungleich $x0, $x4, $x8 geladen werden, werden
die Bits Bit0 und Bit1 vom Register nicht beschrieben.
d.h. aus $F wird $C	(1111 --> 1100)

Im Grunde handelt es sich bei dem im DDFSTRT Register angegebenen Wert
tatsächlich um eine Pixelposition, wie in DIWSTRT angegeben nur mit dem
von der Hardware (Videologik) benötigten zeitlichen Vorlauf. (gilt wenn 
das DDFSTRT zum DIWSTRT entsprechend anepasst ist.)

Bitplane Datafetch DMA wird vertikal automatisch mit DIWSTRT und DIWSTOP und
horizontal mit den Registern DDFSTRT und DDFSTOP eingestellt. Die Screengröße
hat somit einen entscheidenden Einfluß auf die Bitplane DMA-Nutzung.

Die Register DDFSTRT ($92) und DDFSTOP ($94) haben folgende Belegung:
Bit7-Bit0 = H8,H7,H6,H5,H4,H3, x, x

Daraus folgt, würde man die beiden Bits mit x weiter führen:
H8,H7,H6,H5,H4,H3,H2,H1	- Das heißt H0 fehlt
Im Grunde könnte man sich diese Folge auch als eine Division durch zwei
oder eine bereits erfolgte Rechtsverschiebung um eine Stelle vorstellen.
	
		H7,H6,H5,H4,H3,H2,H1,H0		(vor Verschiebung)
		H8,H7,H6,H5,H4,H3,H2,H1     (lsr #1,DDF...)(nach Verschiebung)
		H8,H7,H6,H5,H4,H3, x, x

Somit hat der eingetragene Wert nur einen halb so hohen Wert, als man
erwarten würde. Um auf den ursprünglichen Wert (Pixelposition) zu kommen,
muss man ihn wieder mit zwei multiplizieren.

Wenn wir also unseren bekannten Wert $38 in das Register schreiben, haben wir:
DDFSTRT	$38		($38=%0011.1000) 0, 0, 1, 1, 1, 0, 0, 0
					Bit7-Bit0 = H8,H7,H6,H5,H4,H3, x, x
und erhalten: $38*2 = 56*2=112 

kleine Anmerkung: es ist das selbe wie bei:
SPRCTRL Bit7-Bit0 = H8-H1, H0 ist in SPRxPOS und 
VHPOSR  Bit7-Bit0 = H8-H1, (2-Pixel Genauigkeit)

Zurück zu den DDF-Registern:
Uns stehen also 6 Bitwerte (H3-H8) zur Verfügung, allerdings nur mit einer
8-Pixel-Genauigkeit. (H0 - 1-Pixel, H1 - 2-Pixel, H2 - 4-Pixel, H3 - 8-Pixel)

Im HRM steht: It is recommended that data-fetch start values be restricted to a
programming resolution of 16 pixels (8 clocks in low-resolution mode, 4 clocks
in high-resolution mode). The hardware requires some time after the first data
fetch before it can actually display the data. As a result, there is a
difference between the value of window start and data-fetch start of 4.5 color
clocks. (oder 8,5 Buszyklen im niedrig auflösenden Modus)

Jetzt muss man natürlich wissen was mit clock gemeint ist:
Der CPU-Takt bei PAL 68000 A500 ist 7.093.790Hz (system clock). Das doppelte
bei PAL 68020 A1200. Der CPU Takt ist bezogen auf die internen Custom Chip
Buszyklen das doppelte. (NTSC- 3.579.545 Hz, PAL- 3.546.895 Hz)

Das bedeutet:
1 chip cycle  = 3.546.895Hz PAL (281.94ns) = Buszyklus = 1 CCK (Color ClocK) 	
1 clock cycle = 7.093.790Hz				   = Systemtakt

Pro Rasterzeile haben wir 227,5 Buszyklen (CCKs), von $0 bis $e3 (0 bis 227) 
Als Pixelposition: $0*2 bis $e3*2	= $0 bis $1c6 = 0 bis 454
Also: 1 CCK = 2 Pixel

Für die horizontal Position $81 bedeutet das:
DIWSTRT = $81 (129)  Bit7-Bit0 = H7-H0  (1 Pixel Genauigkeit)
129-112=17pixel (ist 8.5 clock cycles zuvor) 1 clock cycle = 2 Pixel

In Listing23a5.s varrieren wir die Screengröße und zusätzlich die 
Datafetch-Werte.


Spezial-Anmerkung von EAB (ross) zu DDF: 
===============================================================================

Eine andere Formel zur Berechnung der Pixelposition relativ zum DDFSTRT-Wert 
ist: DDFSTRT*2 + fetch_width + delay (*) -> $38*2+$10+$1 = $81 (DIW)
(*) delay is only for bitplanes data, not for sprites data.

Maximum overscan 376 ist nicht durch 16 teilbar: darum 368

DDFSTOP=DDFSTRT+(PixelproZeile/2-8)	umgestellt nach PixelproZeile ist
PixelproZeile=(DDFSTOP-DDFSTRT+8)*2

Wenn wir DDFSTRT = $28 und DDFSTOP = $d8 setzen wird der Screen geöffnet auf:
$28 * 2 + $10 + $1 = $61 Diwstrt
$61 bis ($d8 + $8 - $28) * 2 + $61 - 1 = $1d0 (inklusiv). DiwStop

Mit $1d0 sind wir über $1c7, wodurch wir keine Kontrolle über den Rand haben.
Das hat Auswirkungen bei der Verwendung des Hardwarescrolls.

Durch die Begrenzung auf 368 Pixel verliert man 5 Pixel weit links
($5c, $5d, $5e, $5f, $60) und 3 Pixel weit rechts ($1d1, $1d2, $1d3).

Es ist nicht empfehlenswert diese Pixel zu nutzen, da sie gewöhnlich nicht
sichtbar sind. Ausserdem muss ein extra fetch (der nur auf der linke Seite noch
möglich ist, rechts sind wir durch die Hardware $d8 bereits begrenzt) und der
Hardwarescroll verwendet werden.

d.h.: DDFSTRT = $20, DDFSTOP = $d8 and BPLCON1 >= $33.
An diesem Punkt gebe es ungenutzte Pixel im fetch-Puffer und es gibt noch
einen anderen Seiteneffekt.


kleinerer Screen - angepasst an Logogröße
===============================================================================

Im Listing23b.s wird gezeigt, wie ein Screen einem kleineren Bild angepasst werden
kann. Außerdem ist es durch die Copperliste möglich mehrere Screens mit dem selben
Logo zu haben. Die Bitplanepointer müssen dabei jeweils auf den Anfangswert der 
ersten Bitplane des Logos zurückgestellt werden, da die Bitplanepointer nach Anzeige
des Bildes am Beginn (der Adresse) der folgenden Bitplane des Logos steht.


Änderung der Bitplanepointer in der Mitte des Screens
===============================================================================

In den Beispielen Listing23c.s und Listing23c2.s werden die Bitplanepointer in
der Mitte des Screens auf ein anderes Playfield ausgerichtet. 


Hires, Interlace - Overscan
===============================================================================

In den Beispielen Listing23e.s und Listing23e2.s werden die Zusammenhänge bei
der Screeneinstellung erklärt. Zudem wird in Listing23d.s nochmal eine andere
Variante für den Wechsel der Halbbilder vorgeschlagen.

