<<>> Dies soll eine Tile-Engine sein die hauptsächlich aus diskreten 74xx-LogikBausteinen besteht. Sie wird an den Adress- und Datenbus eines Prozessors angeschlossen und mit Read und Write angesprochen. Die nutzbare Bildschirmauflösung beträgt 320x240 Pixel aufgeteilt in 40x30 Tiles zu je 8x8 Pixel. Die physikalische Auflösung beträgt 640x480 mit 60Hz Bildwiederholrate. Sync-Timing und der Beginn des sichtbaren Bereiches stammen von tinyvga.com. Der Quartz-Oszillator hat die Frequenz 25.175MHz und wird für die Tile-Engine-Schaltung mit einem Flipflop halbiert, so dass die Periodendauer etwa 80ns beträgt (von nun an "Pix-CLK" benannt). Es sind 4 Dual-Port-SRAMs vorhanden, welche mit einem ihrer beiden Ports am Prozessor-Bus angeschlossen sind und verschiedene Adressbereiche belegen. Es gibt auch Register für Scroll-Positionen der Zähler und das Hintergrund-Farben-Register - diese haben jeweils eine eigene Adresse im Speicherbereich und können auch vom Prozessor schreibend adressiert werden. Im Folgenden werde ich zu den einzelnen Teilen der Tile-Engine etwas dazu schreiben. <> Der Sync-Teil erzeugt die horizontalen und vertikalen VGA-Sync-Pulse für ein 640x480 mit 60Hz Bild sowie ein H-Blank-, V-Blank-, ein 324-Pix-CLK-Fenster- und ein TZ_320-Signal, die der Steuerung einiger Funktionen dienen. Die Schaltungen sind nicht optimiert und mussten für den Steckbrett-Aufbau zwecks Signal-Integrität und -Laufzeit mehrmals modifiziert werden. <> Dieser Zähler begleitet das aktuell gerenderte Pixel und stellt seine horizontale Position innerhalb des aktuell gerenderten Tiles dar. Der Wert dieses Zählers wird in der Pipeline zur Adressbildung im Detailspeicher (Bit 2) und zur Pixel-Paar-Extraktion (Bits 0 und 1) benutzt. Indem der Prozessor das Register-Latch beschreibt kann er Soft-Scrolling durchführen, also vom Pixel ganz links bis zu dem ganz rechts scrollen. Das R-Flag (Register-Latch-Bit 7) bestimmt in welche Richtung das Scrollen gehen soll - bei R=1 erscheint am linken Bildrand die linke Einrückspalte und die Bits 0-2 des Register-Latches bestimmen welches Pixel am linken Bildrand anliegt. Das CP_X-Signal sorgt dafür, dass zu Beginn jeder Bild-Doppelzeile das Register-Latch übernommen wird. Dadurch kann der Prozessor bereits kurz nach Zeilenbeginn einen neuen horizontalen Scroll-Wert eintragen und stört die gegenwärtige Zeile nicht - zB. falls ein Rasterzeilen-Interrupt in der Zeile stattgefunden hat. X_ODER_Q gehört zur Steuerlogik und lädt den Pixel_X-Zähler mit 111, damit diese den X_UND-Steuereingang benutzen kann und somit den nachgeschalteten Tile-Zähler pulsen kann.X=7 erzeugt jedes Mal einen Puls wenn der Pix_X-Zähler einen Überlauf der ersten 3 Bit hat - das wird als Zählpuls für den Tile-Zähler benutzt, denn das bedeutet den Beginn des nächsten Tiles am Bildschirm. Der Zähltakt des Pixel_X-Zählers wird vom TZ_320-Signal nach 320 Pulsen angehalten, damit es am Ende einer Bildzeile nicht zu überzähligem Anpulsen des Tile-Zählers kommt. Die Pix_CLK_324 würde nämlich noch 4 Pulse weiter laufen. Die Grundposition des Pixel-X-Register-Latches erreicht man mit dem Scroll-Wert "0xxxx111", also Richtungs-Flag auf 0 und Pixel 7 am linken Rand sichtbar (Kurzform "L7" für Links-Scrolling und Pixel 7 am Rand). Bei Scroll-Position "L7" erscheint genau die Mitte des möglichen Render-Bereiches am Bildschirm - die beiden Einrück-Spalten (rechts und links) sind unsichtbar aussen hinter den Rändern. Der Pixel-X-Zähler wird nicht automatisch initialisiert sondern hat einen zufälligen Wert nach dem Einschalten der Versorgungsspannung. <> Er zeigt die Y-Position des aktuellen Pixels innerhalb des aktuellen Tiles an. Dieser Zähler wird vom Flipflop nur jede zweite Bildzeile angepulst, dadurch ist es möglich jede Bildzeile zweimal zu zeichnen - das ist nötig zur vertikalen Pixel-Doppelung. Das Signal des Flipflop (CP_X) taktet zu Beginn jeder Doppelzeile und wird noch in anderen Schaltungsteilen benutzt. Der Pixel_Y-Zähler wird zu Beginn jedes Bildes initialisiert (mit PL_Y). Der Zähler zählt von 0 bis 7 und erzeugt beim Überlauf ein Signal das vom Steuerteil benutzt wird. Die 3 Bit dieses Zählers werden zur Adressbildung im Detail-RAM benutzt. Vertikales Soft-Scrollen wird durch Laden des Register-Latches mit dem gewünschten Wert (0-7) erreicht. Die Grundposition des Pixel-Y-Register-Latches erreicht man mit dem Scroll-Wert "xxxxx000" - dadurch ist die erste Tile-Zeile vertikal komplett sichtbar . Der Pixel-Y-Zähler wird nicht automatisch initialisiert sondern hat einen zufälligen Wert nach dem Einschalten der Versorgungsspannung. <> Der Tile-Zähler hat 11 Bit und wird zu Beginn des sichtbaren Bildes aus den zwei Register-Latches geladen (während der Init-Phase der Steuerlogik). Ein Ändern des Inhaltes der Register-Latches zur Laufzeit des Bildes hat keine Einwirkung mehr. Mittels Multiplexer können die Eingänge des Tile-Zählers auf die beiden Zwischen-Latches geschaltet werden. Diese Zwischen-Latches dienen dem Nachladen des Tile-Zählers auf den ersten Wert einer Tile-Zeile - denn es müssen bis zu 16 Bildzeilen eines Tiles vom selben Startwert gerendert werden. Ich habe synchrone Zähler gewählt, da etwas wenig Zeit bleibt zwischen jeweils zwei 80ns-Pipeline-Takten. <<16 Steuerpulse in H-Sync>> Diese Schaltung erzeugt während des H-Sync-Signales zu Beginn jeder sichtbaren Zeile 16 Impulse. Duch die Schieberegister entstehen diese Impulse jedes auf einer anderen Leitung und sind 80ns lang. Impuls 16 (P16) hält die Schieberegister an, bis der nächste H-Sync-480-Puls sie wieder startet. Das Rücksetzen erfolgt immer nachdem H-Sync wieder auf 1 geht. Das Flipflop stellt sicher dass nur 1 Bit geschoben wird. <> Die Steuerung der Zähler erfolgt mit der ersten Flanke von H-Sync, neun Pulsen von den insgesamt 16 Pulsen der 16-Puls-Erzeuger-Schaltung sowie dem V-Sync-Signal, welches das Init-Flipflop zurücksetzt. Manche Steuerpulse benötigen eine darauffolgende low-Phase, andere nur die vordere Flanke. Zu Beginn jedes Bildes folgt die Initialisierungsphase (wenn der Flipflop-Ausgang "Init_Q" wahr bzw. high ist). Der Pixel-X-Zähler wird gleich zu Beginn auf "111" gesetzt, damit die Steuerlogik mittels dem Signal "X_UND_2" den Tile-Zähler pulsen kann. Die X_UND_2-Pulse sind alle von Bedingungen abhängig (zB. Pixel-Y-Zähler-Überlauf) und bewirken zB. dass der Tile-Zähler zuerst auf die linke Einrück-Spalte gesetzt und dann in seine Nachlade-Latches kompiert wird. Auch können sie den Tile-Zähler bei Zeilen-Wiederholungen aus diesen Nachlade-Latches laden. Die X_UND_2-Pulse setzen auch den Tile-Zähler auf die aktuelle Scroll-Position über die linke Einrück-Spalte hinaus, falls der Inhalt des Pixel-X-Scroll-Register-Latches dies verlangt. Dabei werden auch vorher gespeicherte Parameter der vorangegangenen Bildzeile beachtet , zB. R_Latch sowie auch aktuelle Parameter wie das R-Flag. Die erste Bildzeile ist vom Initialisierungs-Prozess dominiert, welcher zB. den Pixel-Y-Zähler nochmal neu lädt, nachdem dieser fälschlicherweise einen Zählpuls von H-Sync bekam. Die Steuerlogik reagiert auch, wenn der Pix-X-Zähler bereits den Wert "111" aufwies (durch den letzten Pix_CLK-Puls der Bildzeile) - dann wird entweder ein extra Puls an "X_UND_2" erzeugt oder nicht. Da zwischen den einzelnen Steuer-Pulsen (High- plus folgende Low-Phase) 160ns Zeit ist, können mehrere Logik-Gatter hintereinander eingesetzt werden - zu viel sollte es aber auch nicht werden, da durch die Gatterlaufzeiten unerwünschte Überschneidungen mit kurzen Folgepulsen auftreten könnten. <> Diese vierstufige Pipeline verarbeitet hauptsächlich die Adress-Referenzen, die aus den Zählerständen und Tile-/Farb-Karten-Inhalten gebildet werden. An ihrem Ausgang liefert sie pro Takt einen 8-Bit-Farbwert, das Bitpaar, ein Transparenz-Flag und ein Hintergrund-Flag zum aktuell gerenderten Pixel. Mit dem ersten Takt werden die Zähler gelatched und gleichzeitig um eins weiter gezählt - das stellt sicher dass die Zähler bei Beginn des nächsten 80ns-Taktes fertig gezählt haben. Der Tile-Zähler bildet die Adressen von sowohl Tile- als auch Tile-Farb-Karten-Speicher. Mit dem zweiten Pipeline-Takt wird am Ausgang der Tile- und Tile-Farb-Karte jeweils ein ausgelesenes Byte gelatched. Der Pixel-X-Zähler wird dabei gepuffert mitgelatched, damit der Wert aktuell zu dem gerade verabeiteten Pixel bleibt. Das Pixel-Y-Zähler muss nicht mitgelatched werden, da er über die gesamte Bildzeile gleich bleibt. Beim dritten Pipeline-Takt wird ein Bitpaar aus dem Detail-Speicher ausgelesen, extrahiert und dann gelatched. Gleichzeitig wird der rechte Zweig der Pipeline einfach gepuffert durchgelatched - das garantiert dass der Wert aus der Tile-Farb-Karte zu dem aktuell verabeiteten Pixel gehört. Im vierten Pipeline-Takt wird das Farbwert-Byte des aktuell verarbeiteten Pixels aus dem Paletten-Speicher ausgelesen. Ausserdem werden das aktuelle Bitpaar, das Transparenz-Flag und das Hintergrund-Flag weiter gelatched. Die Pipeline hat vier Stufen und mit dem vierten Takt-Puls stehen die Werte des ersten gerenderten Pixels am Ausgang bereit. <<2-aus-8-Logik>> Diese Schaltung extrahiert ein Bitpaar aus einem von zwei nebeneinanderliegenden Bytes. Diese zwei Bytes bilden eine Pixelzeile innerhalb eines Tiles, und die unteren beiden Bits des Pixel-X-Zählers zeigen immer auf das aktuell gerenderte Bitpaar innerhalb eines dieser beiden Bytes. Die Adresse des oberen oder unteren Bytes des Bytepaares bildet sich aus dem ausgelesenen Wert des Tile-Karten-Speichers, den 3 Bits des Pixel-Y-Zählers und Bit 2 des Pixel-X-Zählers. <> Zwei Multiplexer schalten zwischen dem aktuellen Pixel-Farbwert von der Render-Pipeline oder dem Farbwert des Hintergrund-Register-Latches um. Die Hintergrundfarbe wird durchgelatched wenn das Transparenz-Flag "1" ist und das aktuelle Bitpaar "00" ist. Das Register-Latch der Hintergrund-Farbe wird immer zu Beginn einer Doppelzeile noch einmal gelatched, damit bei einem Rasterzeilen-Interrupt ein neuer Farbwert in das Register geschrieben werden kann (vom Prozessor) ohne das Rendern der aktuellen Bildzeile zu stören. Das Latch vor dem D/A-Puffer-Baustein (HCT244) ist die fünfte und letzte Stufe der Gesamt-Render-Kette. Es wird hochohmig geschaltet sobald entweder die V-Blank- oder die H-Blank-Phase aktiv ist. Die 330 Ohm-Widerstände ziehen den Ausgang des hochohmigen Latches schnell nach Masse sodass auch der HCT244-Pufferbaustein schnell auf Masse geht an seinen Ausgängen - das sorgt für den Schwarz-Pegel am VGA-Ausgang während der Bildschirm-Ränder und während den Sync-Signalen. Die erzwungenen schwarzen Bildränder dienen auch dazu, die ersten 4 unnützen Pixel der Render-Pipeline zu unterdrücken. Das VGA-Signal hat 256 Farben im 3R3G2B-Format. Die 330 Ohm-Widerstände könnten durch Multiplexer ersetzt werden, die dann den D/A-Puffer am Eingang auf Masse schalten. Für die gesamte Pipeline sind vier Spül-Pulse nötig, bis mit dem fünften Puls das erste aktuelle Pixel erscheint - das erledigt das Pix_CLK_324-Signal, dessen erste vier Pulse von H-Blank unterdrückt werden. <> Ein 8-Bit-Zähler zählt mit dem CP_X-Signal bei jeder Doppelzeile bis 240 (Beginn unterste Doppelzeile) hoch. Der Prozessor sollte die gewünschte Zeilen-Interrupt-Nummer in das Register-Latch schreiben. Bei Übereinstimmung der Zeilennummer mit dem Zählerstand löst der Comparator einen Interrupt-Low-Puls aus solange Zeilennummer und Zähler den gleichen Wert haben. Das V-Sync-Signal setzt den Zähler auf Null, also wird mit Beginn des V-Sync-Pulses bei Zeilennummer Null ein Interrupt ausgelöst wenn diese Zeilennummer vom Prozessor gewählt wurde. Zu beachten ist dass mehrere Register-Latches zu Zeilenbeginn zweifach gelatched werden, sodass der Prozessor bei einem Zeilen-Interrupt zB. einen neuen Pixel-X-Scroll-Wert in das Pixel-X-Register-Latch schreiben kann ohne das Rendern der laufenden Bildzeile zu stören. Diese während des Zeilen-Interrupts in das erste Latch geschriebenen Werte werden erst in der nächsten Bild-Doppelzeile verwendet. Man sollte die erste (fallende) Flanke des Interrupt-Pulses auswerten, wenn man einen Prozessor anschliesst. <> Ich habe die Adressbereiche der Speicher und Register-Latches so gewählt, dass fünf Comparatoren und 11 ODER-Gatter zum dekodieren genügen. Das könnte vielleicht noch optimiert werden. Ein Write-Signal des Prozessors erzeugt einen Low-Puls entweder an den SRAMs oder an den Takt-Eingängen der Register-Latches. <> Der Tile-Zähler hat einen 11-Bit-Startwert, der vom Prozessor in das Register-Latch des Tile-Zählers geschrieben werden muss (keine besondere Initialisierung in Hardware, ebenso nicht beim Pixel-X- und Pixel-Y-Zähler!). Die Ausgangs-Bits dieses Tile-Zählers bilden den Adressbus für das Tile-Karten-SRAM. Der Tile-Zähler-Startwert wurde als vom Prozessor beschreibbar gewählt, um ein mögliches Tile-Zeiger-Scrolling auszuloten: indem man den Tile-Zähler-Starwert versetzt muss man nicht mehr die komplette Tile-Karte neu beschreiben sondern nur die nachrückenden leeren Felder an den Rändern. Dieser Tile-Zähler-Zeiger zeigt immer auf das erste Tile links oben am Bildschirm in der linken Einrück-Spalte. Von dieser Position aus berechnet die Zähler-Steuer-Logik alle Steuer-Pulse und berücksichtigt dabei auch die Pixel-X- und Pixel-Y-register-Latches zwecks Soft-Scrolling. Der Tile-Zähler-Start-Zeiger läuft in seinem 2kB-SRAM über beim Wert 2047 - dies muss beim Speicherzugriff durch den Prozessor zB. beim Berechnen der neuen Tile-Adressen in der Tile-Karte und Tile-Farb-Karte berücksichtigt werden. <> Ich habe Bausteine der ALS-, LS- und HCT-Familie verwendet. Manche waren schneller und kamen in zeitkritische Schaltungsteile, zB. beim Ausgang des Pixel-X-Zählers ("X=7") sowie beim "X_UND_2"-Zweig der Steuerlogik. Die Schaltung auf dem Steckbrett scheint nicht mal so viel Strom zu benötigen - bis auf den Einschalt-Moment, da fliesst wohl viel. Leider konnte ich den genauen Wert nicht messen, da es zu riskant war. Aber ich vermute dass um 1 Ampere Strom im Spiel sind. Der Puffer-Baustein des D/A-Wandlers bekam eine eigene 5V-Spannungs-Versorgung, da flackernde "Geisterpixel" im Bild zu sehen waren. Die Nummern an den Logik-Gattern in den Schaltplänen können doppelt vorkommen, stellen also nicht exakte Identifikations-Merkmale der einzelnen Bausteine dar. Es sind Nummern im Bau-Abschnitt auf dem Steckbrett. Der Detail-Speicher der Render-Pipeline kann auch direkt am Pix-CLK angeschlossen werden, da die 2-aus-8-Logik eine gewisse Ausgangs-Hold-Zeit liefert. Überhaupt kann man sich die nochmal gepufferten Pipeline-Speicher-Pix_CLK sparen wenn man an die Speicher einen Puffer (an die Datenbus-Ausgänge) anschliesst - dadurch wird die Schaltung synchroner.