Hallo zusammen und schon mal danke fürs lesen!
Vorweg muss/möchte ich euch dahingehend vorwarnen, dass ich mich als
reinen Autodidakten bezeichnen muss. Die Thematik der programmierbaren
Logik interessiert mich aber und weil es irgendwie ja auch erfüllen
kann, Neues zu meistern habe ich mich in das Abenteuer gestürzt.
Ich muss aber feststellen, dass das fehlen eines Ansprechpartners bzw
einer wissenden Instanz der Motivation wirklich nicht hilft, weshalb ich
mich an Euch wende.
Ich habe mir das Nexys2 Board mit dem zugehörigen Buch "learning by
Example" gekauft. Das hilft schon mal zusätzlich zum Forum. Da ich hier
auch fleissig mitlese sind mir aber auch einige Dinge aufgefallen, von
denen hier vehement abgeraten wird (beispielsweise benutzen die autoren
keine clock enable Signale, sondern derived clocks). Da glaube ich dem
Forum, weshalb ich natürlich auch die Beispiele nicht 1:1 übernehmen
kann. Ich versuche aber die Blöcke beizubehalten um da einigermaßen am
Buch zu sein und nun zu meinem Problem:
Das was alle nach blinky und Lauflicht machen steht auch bei mir an,
nämlich ein VGA Signal. Habe ich auch hinbekommen, wenn ich nun aber
darüber nachdenke, wie ich Daten aus einem Speicher holen könnte komme
ich mit dem Buch nicht weiter. Da habe ich ein Verständnis Problem.
siehe Anhang.
Es existiert ein Modul 'vga_timing' was vsync und hsync generiert sowie
die x- und y- Position des aktuellen Pixels ausgibt.
In dem Design des Buches werden nun Sprite Daten aus einem BROM geholt.
dazu wird aus der x/y Position eine Adresse ausgerechnen (rom_addr16)
und dazu ein Wert M gelesen.
Was mir nun nicht klar ist: Der Takt zum hochzählen der vga Zähler und
der Takt am BROM ist der selbe. Im Buch der derived clock clk25. In dem
Modul vga_640x480 wird mit steigender Flanke ein Pixel weitergezählt und
die Position als hc und vc an vga_sprite gegeben. Dort wird dann durch
Kombinatorik die rom_addr16 angelegt und... ja mit dem Selben Takt der
Speicher ausgelesen. Aber dieses Berechnen von rom_addr16 braucht ja
etwas Zeit nachdem mit der Selben Flanke ja erst eine neue x/y Position
gezählt wurde. Warum funktioniert das. Oder wo habe ich das Brett vorm
Kopf?? Ein Takt zählt einen Zähler hoch, damit wird eine Adresse
gebildet was ja Zeit braucht so daß die noch gar nicht am BROM anliegt
wenn der Takt kam.... Lese ich dann nicht immer genau den vorherigen
Pixel aus?
Da ich 50 MHz Bordtakt habe und für vga sowiso nur der halbe Takt
gebraucht wird, könnte man da vielleicht ein halbes Pixel später lesen
oder so, aber wenn die Auflösung höher ist kann man ja nicht immer einen
schnelleren Systemtakt als den vga Takt haben.
Lange Rede kurzer Sinn - Erst mal hoffe ich mein Problem wurde
verstanden. Wer kann mir Nachhilfe geben? Vielleicht auch Schnipsel ohne
massiven overhead zeigen die so was machen?
Ich hoffe, ich habe dein Problem richtig verstanden.
Hilft dir folgendes weiter? (mal ganz allgemein gehalten)
Wenn Werte mit einem Takt geändert werden, dann bildet die Synthese
daraus ein Register.
Und du hast richtig erkannt, dass die Information dann eine gewisse
Latenz hat, bis sie an anderer Stelle angekommen ist.
Wenn aber der Empfänger der Werte, also der, der sie weiter verarbeitet,
mit dem gleichen Takt wie der Erzeuger der Daten arbeitet, dann
übernimmt er die Daten einfach einen Takt später, als sie erzeugt
wurden.
Das ist das Grundprinzip jedes synchronen Designs.
Die Synthese rechnet das so hin, dass sichergestellt ist, dass die
Laufzeit immer kürzer ist, als der Abstand zwischen zwei Flanken. Damit
wird sichergestellt, dass im gesamten Design zum Zeitpunkt der
Steigenden Flanke alle Datenleitungen stabil sind und sich nicht ändern.
In deinem konkreten Fall heißt das:
Das Modul vga_640x480 ändert seine Ausgänge mit dem Takt "n"
Das Modul vga_bsprite verzögert diese im eine unbekannte Zeit "t".
Also kommen sie am Modul loons_240x160 verzögert an (Zeitpunkt n + t).
Da aber die Register in loons die Werte erst zum Zeitpunkt n + 1
Taktperiode übernehmen, und die Synthese dafür sorgt, dass die Zeit t
kleiner als eine Taktperiode ist, sind die Daten stabil, wenn sie
übernommen werden.
Ich hoffe, ich konnte das ein bisschen verständlich ausdrücken.
Dein Stichwort, nachdem du weiter suchen kannst, ist "synchrones
digitales Design".
Danke, d.h. dass der loons-Speicher immer einen Takt versetzt die Daten
ausspuckt? Ich hatte nämlich das Buch so verstanden, dass die Daten von
Takt n auch mit demselben Takt ausgelesen werden.
Konkretes Problem - ich habe einen Speicher für eine ganze Grafikseite.
Wenn ich den Pixel (0,0) aus dem Speicherlesen und einfärben will muss
ich die Adresse schon anlegen wenn ich noch der Pixelzähler noch auf dem
linken untersten (799,520) Pixel steht und aus den Zählständen die
Adresse für (0,0) bauen?
pedelec schrieb:> Aber dieses Berechnen von rom_addr16 braucht ja etwas Zeit nachdem mit> der Selben Flanke ja erst eine neue x/y Position gezählt wurde. Warum> funktioniert das.
Das ist das Grundprinzip jedes synchronen Designs: nach einer Taktflanke
herrscht im FPGA große Unruhe. Neue Zählerstände werden berechnet, Logik
ermittelt aktuelle Werte und die Folgezustände von FSM werden berechnet
(auch bei der 1-Prozess-FSM ist das so!). Und rechtzeitig vor der
nächsten Taktflanke müssen die Werte wieder stabil sein. Denn dann kommt
wieder der Takt und das Spiel geht von vorne los.
Und deshalb sollte es nur 1 Takt im Sytem geben, und immer auf die selbe
Flanke dieses Taktes reagiert werden.
> aber wenn die Auflösung höher ist kann man ja nicht immer einen> schnelleren Systemtakt als den vga Takt haben.
1 Taktzyklus reicht für ein internes BRAM auch aus:
Jetzt wird die Adresse angelegt und mit der nächsten Taktflanke werden
die zugehörigen Daten ausgegeben. Du bekommst die Daten also immer mit 1
Takt Latency (=Verspätung, Verzögerung), weil immer vor der
Taktflanke die Adresse angelegt wird, und die Daten nach der
Taktflanke herauspurzeln. Weil das aber endlos so weitergeht, sieht dein
Timing so aus:
1
clk ___----____----____----____----____---
2
3
___ _______ _______ _______ _______ ___
4
addr ___X_n_____X_n+1___X_n+2___X_n+3___X__
5
6
___ _______ _______ _______ _______ ___
7
data ___X_??____X_n_____X_n+1___X_n+2___X___
Man kann ein ROM auch asynchron beschreiben, dann hast du diese Latency
nicht, aber blöderweise kann dann der Synthesizer auch keines der
internen RAMs verwenden, weil die alle diese Latency eingebaut haben...
Danke vielmals. Ich würde mich dann noch freuen, auf das vga-Beispiel
bezogen konkret zu verstehen, wie man jetzt vorgeht, um Daten "passend"
zu lesen.
Man muss ja dann einen Takt bevor das Pixel geschrieben wird schon die
Adresse zum lesen haben. Das hatte ich in meinem letzten Post versucht
zu beschreiben.
Der Zähler für x zählt ja von 0 bis 799 total und der für y von 0 bis
520 total.
Wenn die Zähler rechts unten auf dem Monitor im nicht sichtbaren Bereich
stehen, muss ich einen Vergleicher einbauen der aus 799/520 die Adresse
0/0 erzeugt? Wie kann ich es konkret realisieren.
Die Latenz beim lesen aus dem Speicher habe ich begriffen. Befürchtete
ich ja schon selber wodurch der Knoten in meinem Kopf erst entstand.
Oder ist es ein akzeptables Vorgehen beim verschwinden von viden schon
die Adresse auf 0/0 zu stellen und in der Austastlücke den Wert
wiederholt zu lesen. Angezeigt wird ja nichts und sobalt viden wieder
'1' wird den Adresszähler weiter zu setzen?
Die Problematik wird mich ganz sicher noch verfolgen wenn gar externer
Speicher im Spiel ist.
Aber vielen Dank ans Forum - gezwungen zu sein ein Problem für andere zu
formulieren ist schon mal gut und eure Antworten erst recht! :-)
pedelec schrieb:> Oder ist es ein akzeptables Vorgehen beim verschwinden von viden schon> die Adresse auf 0/0 zu stellen und in der Austastlücke den Wert> wiederholt zu lesen. Angezeigt wird ja nichts und sobalt viden wieder> '1' wird den Adresszähler weiter zu setzen?
Ja. Auch ich würde mit dem letzten Pixel der Zeile schon mal anfangen,
dauernd den ersten Pixel der nächsten Zeile zu lesen. Also immmer 1
Pixel "voraus" denken, dann ist das richtig. Denn das RAM hat ja genau
diesen 1 Takt Latency...
pedelec schrieb:> Die Problematik wird mich ganz sicher noch verfolgen wenn gar externer> Speicher im Spiel ist.
Oder wenn die Daten über einen Systembus rangeschafft werden müssen.
Dann hilft ein FIFO weiter, mit einer Steuerung, welche schon mal die
ersten Pixel aus dem Speicher holt. Sobald wieder etwas Platz im FIFO
ist, wird mit den nächsten Pixeln aufgefüllt. Die Videoausgabe hat dann
passend zu ihren Zählern die Pixeldaten vorliegen.
Duke