Die Hexer - The Exceptions geben eine Zugabe

Jawohl, sie sind wieder da! Nach ihrer überaus erfolgreichen ST-Magazin-Serie für Programmierer im vergangenen Jahr melden sich die Assembler-Profis der »Exceptions« auf Ihren besonderen Wunsch mit einer weiteren Folge zurück: Heute geht es dem rechten Bildschirmrand an den Kragen.

Hallo liebe Leser und Freunde unserer kleinen TEX-Serie. Nach einem halben Jahr Pause ließ uns ein gewisser Mitarbeiter des ST-Magazins (Hallo Tarik!) nicht mehr in Ruhe und berichtete uns pausenlos von Ihren Briefen, in denen Sie sich eine Fortsetzung der TEX-Serie wünschen. Das Ergebnis von Tariks Hartnäckigkeit sehen Sie nun auf diesen Seiten: Eine neue Folge der Hexer ist da. Worum es diesmal geht, habe ich schon in unserem letzten Artikel angedeutet. Ich werde Ihnen heute erzählen, wie man softwaremäßig den rechten Rand beseitigt. Anschließend gibt's dann noch einen Scroller über den linken und rechten Rand, der überhaupt keine Ränder öffnet. Das klingt vielleicht seltsam, aber lassen Sie sich überraschen.

Keine Angst, wir verraten auch noch das Geheimnis des linken Randes, allerdings erst in der nächsten Ausgabe.

Rufen Sie sich nun unseren letzten Artikel (ST Magazin Ausgabe 11/88) ins Gedächtnis. Für alles, was ich Ihnen oben versprochen habe, brauchen wir die sogenannte »Synchron-Programmierung«. Falls Sie den Artikel nicht mehr zur Hand haben, fasse ich noch einmal kurz das Wichtigste zusammen. Die Experten unter Ihnen dürfen die nächsten Absätze getrost überfliegen.

Der wichtigste Grundsatz der Synchronprogrammierung ist die Tatsache, daß der Elektronenstrahl genau 512 Taktzyklen benötigt, um eine Zeile zu schreiben. Man kann dies an einem netten Effekt ganz gut verdeutlichen. Setzen Sie einfach Befehle, die die Hintergrund färbe ändern (also »move.w #$xxx,(a0) mit a0=$ff8240«), untereinander und ans Ende einen Sprung an den Anfang des Programms, bis die Schleife genau 512 Taktzyklen lang ist. Sollte es nicht aufgehen, fügen Sie noch ein oder zwei »NOPs« (4 Taktzyklen) ein. Wichtig ist noch, daß keine Interrupts auftreten, da diese das Timing durcheinanderbringen.

Gute Vorbereitung ist wichtig

Setzen Sie zu Beginn das Statusregister auf $2700. Haben Sie alles richtig gemacht, sehen Sie zirka 30 senkrechte Farbbalken auf dem Bildschirm. Da das Programm auf den Taktzyklus genau synchron läuft, kommen in jeder Zeile immer die gleichen Farben untereinander, und schon entstehen die Balken. Besonders praktikabel ist dieses Programm allerdings noch nicht, da der Prozessor in der Schleife festhängt, und keine Zeit für andere Aufgaben mehr übrig ist. Deshalb gibt es eine Methode, wie sich jeder VBL in einer beliebigen Zeile neu synchronisieren läßt. Anschließend arbeiten Sie die Sync-Schleife ab und verlassen die Routine, um das restliche Programm wieder zum Zuge kommen zu lassen. Logischerweise hängt die freie Rechenzeit direkt mit der Anzahl der Zeilen, die Sie im Synchronprogramm nutzen, zusammen. Die eigentliche Synchronisation läuft folgendermaßen ab: Zunächst setzen Sie einen Rasterinterrrupt auf die synchronisierende Zeile.

Dann warten wir wie gewohnt (über das Timer B Data Register) auf den Beginn des nächsten rechten Randes. Genaugenommen muß der Raster auf einer durch acht teilbaren Bildschirmzeile minus eins sitzen. Für den Sync-Trick nutzen wir nämlich die Tatsache aus, daß das Lowbyte des Video-Adreßzählers zu Beginn jeder achten Zeile auf Null steht. Der Raster muß natürlich eine Zeile höher sitzen, da wir auch eine Zeile warten. Zum Synchronisieren warten wir nun, bis besagtes Lowbyte erstmals wieder von Null verschieden ist und merken uns diesen Wert, den wir unmittelbar von 30 subtrahieren (30 ist willkürlich gewählt, es muß nur sichergestellt sein, daß das Ergebnis in jedem Fall positiv ist). Nun haben wir ein direktes Maß für die Verzögerung, bis wir mit dem Elektronenstrahl synchron sind in der Hand oder vielmehr im Datenregister. Da die MMU pro Byte genau zwei Taktzyklen benötigt, gibt unser Wert mal zwei genommen an, wie viele Taktzyklen wir noch warten müssen. Zum Glück gibt es aber einen Befehl, der dies automatisch erledigt:

lsl.w dx,dy

Er benötigt laut Handbuch 8 + 2n Taktzyklen. Nehmen wir unser obiges Rechenergebnis und lassen damit ein »Dummy«-Register rotieren. Ab hier sind wir synchron und können beliebige Routinen einbauen, zum Beispiel eine »Randaufklapproutine« für den rechten Rand.

Der ST im Warnstreik

Ich hoffe, das hat als Vorinformation gereicht, lassen Sie schon einmal den Atari ST Warmlaufen, erzählen Sie ihm aber nichts von einer neuen TEX-Folge, sonst geht Ihr Computer vielleicht in einen vorübergehenden Warnstreik. Meiner zeigte schon erste Ausfälle, als ich die Listings für Sie zusammenstellen wollte. Ich habe ihn aber geschickt mit 1st Word überlistet und habe erst einmal folgende Zeilen getippt.

Das Geheimnis des rechten Randes war schon früh gelüftet. Damals hatten wir gerade frisch geknüpfte Kontakte zu einer neuen deutschen Softwarefirma, und so ergab es sich, daß sich fast unsere gesamte Truppe über die Ferien im Bielefelder Raum tummelte (was nicht gerade in unserer Gegend liegt). Mir war da so eine Idee gekommen, was man mit der schönen Routine, die viele senkrechte Farbbalken auf den Bildschirm zaubert, noch alles anfangen könnte. Nach wenigen Worten mit Udo stürzte dieser begeistert an den Computer, stieß Erik beiseite, der dort zufällig saß. Neochrome verschwand zusammen mit einem angefangenen Bild aus dem Speicher; ich glaube Erik hat es nie mehr vollendet. Wenige Augenblicke später saßen wir dann beide vor dem Bildschirm, im Speicher nun der Source, der bis jetzt nur viele Farben erzeugen konnte.

50 oder 60 Hz Bildschirmfrequenz?

Es dauerte dann keine fünf Minuten mehr, und der rechte Rand war offen. Wenn Sie später meine genauen Erläuterungen im Listing sehen, verstehen Sie dann auch, warum es damals so schnell ging. Der Trick ist prinzipiell sehr einfach, es funktioniert genauso, wie mit dem unteren Rand. Hier schaltete man einfach in der letzten Bildschirmzeile auf 60 Hz und wieder zurück. Mit dem rechten Rand ist es ähnlich. Hier schalten Sie in jeder Zeile, in der der Rand geöffnet werden soll, kurz vor Beginn derselben auf 60 Hz und sofort wieder zurück. Nur müssen Sie diese Stelle recht exakt treffen, es läuft auf eine »Synchron-Schleife« hinaus, die sie kennen (sollten). Wir dehnten diese Experimente gleich auch auf den linken Rand aus, allerdings erfolglos. Mit einer einfachen 60/50 Hz-Umschaltung irgendwo im linken Rand war es offenbar nicht getan. Wir hatten allerdings ein lustiges Ergebnis. Man kann den ST dazu bewegen, überall Rand darzustellen, indem man am Ende des linken Randes die 60/50-Hz Umschaltung einbaut. Allerdings wurde dieser Trick mangels Verwendungszweck wieder ad acta gelegt. Schließlich gibt es auch einfachere Methoden einen einfarbigen Bildschirm zu erhalten. Wir gaben uns zunächst einmal mit dem rechten Rand zufrieden. Durch geschicktes Experimentieren stellte sich heraus, daß der ST nun 204 Byte pro Zeile darstellt. Schnell war der Bildschirm mit einem Muster gefüllt, und auch ein einfacher 1-Plane-Scroller an die neue Screenbreite angepaßt. So war dann an einem Abend der »Overscan-Screen« des Amiga-Demos fertig. Bis allerdings das gesamte Demo fertig war und von einer Boot-Disk lief, verging noch ein wenig Zeit.

Wir machten auch noch ein Intro, dessen Scroller sich ebenfalls im rechten Rand tummelte. Aber die ganze Sache wirkte immer so unsymmetrisch. Wir haben einfach immer unser Bild am Monitor nach links gedreht, aber das gilt schließlich nicht. Wir überlegten uns, wie sich zumindest ein Scroller auch im linken Rand darstellen läßt. Damals weigerte sich dieser Rand ja noch hartnäckigst aufzugehen, und so mußten wir uns etwas besonders Ausgefallenes einfallen lassen, um einen »symmetrischen« Scroller zu erzeugen.

Für die Lösung mußte mal wieder der Farbbalken-Trick herhalten. Statt vieler Hintergrundfarben verwendeten wir diesmal nur zwei, nämlich eine x-beliebige Farbe und Schwarz (Hintergrund). Hält man diese beiden Farbwerte in zwei Registern (d0 und d1) kann man durch Kombination von zwei Befehlen, nämlich

move.w d0,(a0)   ;a0=$ff8240

und

move.w d1,(a0)

Muster mit einer horizontalen Auflösung von 8 Pixeln erzeugen. Arbeitet man diese Befehlskette, die natürlich wieder genau 512 Taktzyklen lang sein muß, in einer Schleife ebenfalls 8mal ab, so erhält man schöne quadratische Kästchen mit 8x8 Pixel auf dem Bildschirm.

Der Vorteil dieser Methode: Da wir nur die Hintergrundfarbe umschalten, sind wir von Rändern unabhängig. Hintergrundfarbe ist schließlich überall vorhanden. Jetzt braucht man nur noch mehrere dieser Kästchenreihen untereinander zu setzen und schon hat man einen zwar sehr groben, dafür aber über das gesamte Bild laufenden Scroller. Diese Routine wurde übrigens für das erste Union-Intro geschrieben. Der Name Union dürfte spätestens seit dem Erscheinen des Union-Demos allen ein Begriff sein. Interessiert es Sie, wie es zu dieser Gruppe kam? Wie Sie vielleicht wissen, gibt es noch eine zweite große Gruppe in der »Szene«, die »Bladerunners«. Sie existieren schon eine ganze Weile länger als die Union und waren der Grund für uns (ich meine jetzt die Gründer der Union) eine zweite »Dachorganisation« für ST-Freaks aufzumachen. Denn die Qualität der Bladerunner Intros und Demos ließ doch (zumindest am Anfang) schwer zu wünschen übrig.

Also setzten wir uns zusammen, tauschten Erfahrungen und Source-Codes aus und machten uns zum Ziel, vernünftige Demos zu programmieren. Das war der eigentliche Zweck der Union, Programme zu »knacken« war und ist nur eine Nebenaktivität, die nicht (mehr) alle Mitglieder der »Union« billigen. Insgesamt ist es viel effizienter, wenn jeder ein bißchen zum Ganzen beiträgt. Ansonsten würde sich vielleicht jeder zu Hause abmühen und am Ende ist fünfmal das gleiche da, nur mit einem anderen Namen im Scrolltext. Das tatsächlich etwas dabei herausgekommen ist, sieht man wohl an unserem Demo, oder?

Es geht dem Rand an den Kragen

Nun aber genug der Selbstbeweihräucherung, fangen wir endlich an. Wir nehmen uns zuerst den rechten Rand vor. Listing 1 entfernt ihn sachgemäß. Im wesentlichen dürfte ihnen das Programm aus unserem letzten Artikel bekannt vorkommen. Es enthält die Standard Hbl-Routinen, die den Rasterinterrupt in diesem Fall auf Zeile 31 setzen. Die Position ist natürlich nach Bedarf in den altbekannten Achterschritten verschiebbar. Hinzugekommen ist die Routine »prepare«. Sie füllt den Bildschirm zunächst mit Farbe 15 auf, damit man sieht, wo der Rand beginnt. Anschließend wird dort, wo sich später der Rand öffnet, ein kleines Kästchenmuster gezeichnet. Die Timer B Routine synchronisiert sich wie oben beschrieben über den Videoadreßzähler mit anschließendem »lsl.w d2,d1«.

Nun wird es langsam interessant. Die folgende Verzögerung (delayloop1) ist so abgestimmt, daß die eigentliche Sync-Schleife (zeilenloop2) genau in der horizontalen Austastlücke beginnt, außerhalb des Bildes.

Die Sync-Schleife ist fast völlig leer, nur an einer Stelle kurz vor dem (ehemaligen) Beginn des rechten Randes sitzt die schon erwähnte Umschaltung auf 60 Hz (»move.b d4,(a0)«) und sofort danach der Befehl zum Zurückschalten auf 50 Hz (»move.b d3,(a0)«). In unserem Beispiel wird die Schleife 150mal abgearbeitet. Natürlich ist auch dieser Wert variabel. Kritisch wird es nur, wenn wir die Schleife auch im Bereich des unteren Randes abarbeiten. Von alleine geht der untere Rand leider nicht auf. Da mußten Sie schon noch eine zusätzliche Umschaltung für den unteren Rand in die 200. Zeile einbauen. Sie wissen ja noch, wie es geht, oder? Um Platz zu sparen, habe ich das Block (blk) Kommando des Seka recht intensiv eingesetzt. Der Befehl blk.w 30,$4e71 bedeutet, daß der Assembler hier 30mal das Wort $4e71, was nichts anderes als der Befehl nop ist, einsetzt. Haben Sie kein vergleichbares Kommando in Ihrem Assembler, so müssen Sie eben 30 NOPs untereinander kopieren.

So, jetzt passen Sie noch probeweise Ihre Scroll-Routine an 204 Byte pro Zeile an, dann sind Sie schon in Übung, denn im nächsten Monat wird Ihr ST 230 Byte in jeder Zeile darstellen.

Bis dahin dürfen Sie sich mit unserem Hintergrundfarben-Scroller beschäftigen. Das Hauptprogramm sowie die Hbl-Routinen sind inzwischen wohl hinreichend bekannt. In der new4-Routine ist eine kleine Besonderheit eingebaut. Der Scroller kann in jeder beliebigen Bildschirmzeile (l bis 200) beginnen. Deshalb wertet die Level 4 Routine eine Koordinaten-Tabelle (jumpbahn) aus, die den Scroller auf und ab springen läßt. Wem dies zu viel Tipparbeit ist, kann die Tabelle auch kürzen. Wie üblich ist -l die Endekennung, nicht vergessen! Die Position des Rasters ergibt sich durch das Aufteilen der Koordinaten in die nächst kleinere Zahl, die durch 8 teilbar ist. Den verbleibenden Rest schreiben wir zunächst in der Variablen »scandelay«. Das Synchronprogramm verschiebt dann den Scroller zeilenweise um diesen Wert nach unten. Die Timer B Routine beginnt zunächst nach altbekanntem Schema: Eine Zeile warten, synchronisieren und noch einmal warten, bis der Strahl im rechten Rand ist. Dann folgt die oben angesprochene Verschiebung um ganze Zeilen (scandelay-loop).

Nun kommt noch einmal ein kleiner Trick. Unser Scroller hat bekanntlich eine Auflösung von 8 Pixeln. Trotzdem scrollt er mit 4 Pixeln, was durchaus noch als »Soft«-Scrolling durchgeht. Dies wird durch die Variable »nummer« mit anschließendem »lsl.w d6,d6« bewirkt. Nummer hat entweder den Wert 2 oder 0, deshalb verzögert der lsl.w einmal um 8 + 4 Zyklen, das nächste Mal nur um 8 Zyklen. Es bleibt eine Differenz von 4 Taktzyklen, was unserer Scrollgeschwindigkeit von 4 Pixeln entspricht. Die Routine hat jeden zweiten VBL nichts anderes zu tun, als »nummer« von 2 auf 0 zu ändern. Das Scrolling kommt dann ganz automatisch. Nach dieser kleinen aber wichtigen Verzögerung folgt der Programmteil, der den Scroller auf den Bildschirm bringt. Wie oben erwähnt, läßt sich die 8-Pixel-Auflösung nur durch move.w dx,(a1) erreichen. Der folgende Programmabschnitt enthält selbstmodifizierenden Code. Die move.w dx,(a1) Befehle werden in die Schleifen hineingeneriert. Die so entstandene Befehlskette (im Source als blk.w 55, $3280 zusammengefaßt) steckt in einer 512 Taktzyklenschleife, die der ST jeweils acht Zeilen lang abarbeitet. Für den gesamten Scroller sind fünf dieser Schleifen vorhanden, da der Zeichensatz 5 Pixel hoch ist. Beim Aneinanderhängen der Schleifen muß man allerdings aufpassen. Der dbf-Befehl braucht leider 4 Taktzyklen mehr, wenn er nicht verzweigt. Der Scroller würde merkwürdig kursiv scrollen. Deshalb haben wir noch einen zusätzlichen bra.s inloopx eingebaut, der beim jeweils ersten Schleifendurchlauf 4 NOPs überspringt. Das ist genau der Differenzbetrag für dbf+bra.s. Nach der synchronen Anzeigeroutine folgt der Programmteil, der für das eigentliche Scrolling zuständig ist. Er ist nicht mehr synchron programmiert (wozu auch ?). Deshalb sind auch andere Interrupts erlaubt (move.w #$2500,sr). Zunächst prüfen wir, ob es genügt, »nummer« zu ändern oder ob zusätzliches Scrollen nötig ist. Im letzteren Fall kopieren wir zunächst die oben erwähnte »move.w dx,(a1)« Kette direkt im Programm um ein Wort nach links. Dies übernehmen für jede Schleife jeweils vier movem.l Befehle.

Anschließend hängen wir das Bitmuster für die Pixelspalte ganz rechts an.

Ist im Zeichensatz ein Bit gesetzt, generiert das Programm ein move.w d7,(a1), andernfalls ein move.w d0,(a1). »Bitnummer« gibt dabei an, welche Spalte des Zeichens das Programm gerade bearbeitet. Ist dies die Spalte null gewesen, müssen wir ein neues Zeichen aus dem Scrolltext holen. Eine negative Zahl (zum Beispiel -1) ist die Ende-Kennung, in diesem Fall beginnt der Text von vorne. Die Zahl 127 ist ein spezielles Steuerzeichen, das den Scroller für eine gewisse Zeit anhält. Empfängt der Scroller diesen Wert, holt die Routine noch ein zusätzliches Byte aus dem Text, das es mit 16 multipliziert.

Dieser Wert gibt nun an, wie viele VBLs der Scroller stehen soll. Die Zeichen von 0 bis 49 sind gewöhnliche Zeichen, Werte größer 49 fängt das Programm nicht ab, passen Sie ein wenig auf, sie sind weder im Zeichensatz noch in der »proportionaltab« definiert!

Anhand der Zahl, die es aus dem Text liest, bestimmt das Programm die Adresse des Zeichens im Zeichensatz, die es sich in »buchst_addr« merkt, sowie die Breite des Zeichens aus der Proportionaltab, die in »bitnummer« vermerkt ist. Mit diesen Parametern übernimmt es dann das Zeichen in der »bitcopyloop« spaltenweise.

Listing 2 finden Sie aufgrund des enormen Umfangs nur auf der Leserservice-Diskette zu dieser Ausgabe.

Listings zu dem Artikel

(Tarik Ahmia/tb)

Aus: ST-Magazin 08 / 1989, Seite 71

Links

Copyright-Bestimmungen: siehe Über diese Seite