Hallo,
habe mich endlich mit Modelsim arrangiert und jetzt ein kleines Projekt
(siehe Anhang) simuliert.
Das Spartan 3E Dev-Board hat ja einen LTC1407 drauf und dafür habe ich
einmal ein Modul für den Spartan und zum anderen ein Modul für den
Simulator, in dem auch der ADC simuliert wird.
Die Testbench liest die gewünschten ADC-Werte aus einer Datei und gibt
die entsprechend weiter. Im "Groben" funktioniert es, aber im Detail
klemmt es. Jetzt weiß ich aber nicht wo - höchstwahrscheinlich fehlt mir
wieder etwas Verständnis ...
Es gibt ja jetzt einige "gleichzeitige" Prozesse und ich bin mir nicht
sicher, welche davon ich zu synchronisieren habe und welche - per
Definition - unsynchronisiert sein sollen.
Um den Zeitversatz auf der Platine (übertrieben) ins Spiel zu bringen,
arbeitet der gefakte ADC mit der fallenden Taktflanke, das FPGA-Modul
mit der steigenden.
Wenn also mal jemand von denen, die sich auskennen, drüber schauen und
mir etwas Nachhilfe geben könnte, würde mir das sehr freuen :)
> Um den Zeitversatz auf der Platine (übertrieben) ins Spiel zu bringen,> arbeitet der gefakte ADC mit der fallenden Taktflanke, das FPGA-Modul> mit der steigenden.
Das macht man aber anders :-o Dafür gibt es after
Mit einer funktionalen Simulation findest du sowieso keine
(relevanten) Timing-Verletzungen. Machs besser straight-forward (mit dem
selben Takt), damit du Funktionsfehler findest.
Was willst du jetzt eigentlich testen?
Das Modul LTC1407 eigentlich nicht.
Denn dort stehen Sachen drin, die die Synthese ins Grübeln bringen...
(Am Rande: Der Name des Moduls ist ungünstig, LTC1407 ist ein Bauteil
von LT. Das macht was anderes, als das was in dem vhdl-File steht...)
BTW:
1
if(cs='0')then
2
:
3
elsifrising_edge(clk50)then
4
:
Das ist bedenklich, falls der cs (in der Realität) asynchron zum clk50
kommen kann...
Guten Morgen Lothar,
Vielen Dank für Deine Hilfe!
> Das macht man aber anders :-o Dafür gibt es after
Danke für den Tip - habe doch gleich interessante Beispiele gefunden!
Was ein guter Suchbegriff nicht ausmachen kann :)
> Machs besser straight-forward (mit dem> selben Takt), damit du Funktionsfehler findest.
Hm, die seltsamen Effekte hatten mich dazu gebracht, es mit einem
Zeitversatz zu probieren - mir scheint, dass noch was anderes zuschlägt.
> Was willst du jetzt eigentlich testen?> Das Modul LTC1407 eigentlich nicht.
Hm, schon - aber da ich das fake-Modul für den ADC ja selbst geschnitzt
habe, wie auch die Testbench, bin ich mir nicht sicher, wo ich den
Fehler suchen kann, bzw. wie ich ihm auf die Spur komme.
Sinn der Sache ist doch, dass die Ausgabe, die die Werte für den
Speicher kontrolliert, genau die gleichen Werte in der gleichen
Reihenfolge ausspuckt, wie die Testdaten, die ich der Testbench zur
Verfügung stelle.
Der Punkt ist, dass die Übertragung bei jedem 2. Messwert funktioniert,
dazwischen wird 0 in den Speicher geschrieben. Jetzt weiß ich aber von
niemand, der die 0 produziert - habe die Testdaten extra mit != 0
initialisiert.
> Denn dort stehen Sachen drin, die die Synthese ins Grübeln bringen...
Ich weiß. Die Meldung habe ich nur eingebaut, um zu sehen, was abgeht.
> Das ist bedenklich, falls der cs (in der Realität) asynchron zum clk50> kommen kann...
Genau aus dem Grunde habe ich es so geschrieben. Ich habe zuerst Deine
Variante vom Beitrag "Re: Der vhdl-Schnipsel-Anfängerfragen Thread"
simuliert, dann aber gesehen, dass der Reset nicht in meinem Sinne
funzt.
Kann durchaus sein, dass ich beim Umschreiben noch was verbockt habe.
Hallo,
hab's jetzt zwar selber hinbekommen, aber was mich frustriert: ich weiß
nicht, warum es jetzt tut.
Gut, beim FPGA-modul hatte ich einen Takt zuwenig gezählt, sodass der
ADC garkeine Chance hatte, das neue Startsignal mit zu bekommen.
... auch habe ich bei der Testbench 2 Prozesse wieder zusammengefasst.
Schätze mein Verstädnis krankt noch daran, wann ein Signal den ihm
zugewiesenen Wert erhält.
Also z.B. ich mache das "gleiche" in 3 verschiedenen Prozessen (in
unterschiedlichen Simulationen, nur zum Verständnis):
1.) ein Prozess mit einer Signalabhängigkeit linear kodiert mit
Flankenabfrage auf das angegebene Signal:
1
PROCESS(...)BEGIN
2
ifrising_edge(...)then
3
...
4
endif;
5
ENDPROCESS;
2.) ein Prozess ohne Signalabhängigkeit
1
PROCESSBEGIN
2
WAITUNTILrising_edge(...);
3
...
4
ENDPROCESS;
3.) ein Prozess ohne Signalabhängigkeit, der aber eine (Endlos-)Schleife
hat, sodass der Prozess nie beendet und neu gestartet wird. In der
Schleife wird auf unterschiedliche Ereignisse gewartet.
In jedem dieser Prozesse weise ich einem Signal einen neuen Wert zu.
Wovon hängt es jetzt ab, wann der neue Signalpegel aktiv ist? - Egal ob
für andere Prozesse oder denselben Prozess? Gibt es hier Unterschiede
zwischen Simulation und Synthese?
Diese beiden Beschreibungen verhalten sich exakt identisch. Eine
Sensitivliste ist quasi eine andere Schreibweise für ein wait until.
Das wait until hat den Vorteil, dass es keine unvollständige
Sensitivliste geben kann. Siehe z.B.
http://www.lothar-miller.de/s9y/archives/16-Takt-im-Prozess.html
Hallo Lothar,
selbst wenn die ersten beiden identisch zu sein scheinen - bleibt für
mich noch immer die Frage offen, wann denn eine Signalzuweisung aktiv
wird und wovon es abhängt.
Noch interessanter ist doch diese Variante, bei der der Prozess niemals
verlassen wird:
1
PROCESSBEGIN
2
...
3
LOOP
4
mySignal<='1';
5
6
WAITUNTILrising_edge(clock);
7
...
8
ENDLOOP;
9
WAIT;
10
ENDPROCESS;
In manchen Beschreibungen steht zu lesen, dass ein Signal erst nach
Beendigung des Prozesses den zugewiesenen Wert erhält (und wird als
Gegensatz zu den Variablen hervorgehoben). Das scheint so aber nicht
ganz zu stimmen ...
> In manchen Beschreibungen steht zu lesen, dass ein Signal erst nach> Beendigung des Prozesses den zugewiesenen Wert erhält
Nicht am Ende des Prozesses, also nicht bei der Zeile END PROCESS,
sondern nachdem alle Prozesse an einen Wait-Statement (implizit oder
explizit) angekommen sind.
Dann werden alle Signale aktualisiert und der nächste Event
abgearbeitet.
Danke Klaus,
das war genau die Erklärung, die ich gesucht habe!
Sie ist plausibel und jetzt leuchtet mir auch ein, warum meine Testbench
mit mehreren Prozessen nicht geklappt hat (Synchronisierung der
WAIT-statements hat nicht geklappt).
Gibt es die Möglichkeit, Prozesse zu priorisieren, d.h. irgendwie
festzulegen, in welcher Reihenfolge die Prozesse wieder anlaufen?
Wie sieht das eigentlich mit den Auswirkungen des IO auf das
Zeitverhalten der Simulation aus?
Das Einlesen der Datei in den Speicher ist in der Zeitachse nicht zu
sehen, aber wenn ich pro Testzyklus einen Dateizugriff mache, kommt die
Zeitsteuerung durcheinander (subjektiver laienhafter Eindruck - muss
nicht stimmen).
@Lothar
Mir ging es nicht darum, zu synthetisieren, sondern zu verstehen.
Das Beispiel ist aus meiner (funktionierenden) Testbench - da besteht
nichtmal der Wunsch, das zu synthetisieren. Im Augenblick ist mir die
Synthese völlig egal, da die Verständnislücken noch zu groß sind.
Deshalb "entwickle" ich gerade mit Modelsim und dem Wavediagram. Wenn
ich dann mit dem Zeitverhalten meiner Module zufrieden bin, dann widme
ich mich wieder der Synthese.
> Gibt es die Möglichkeit, Prozesse zu priorisieren, d.h. irgendwie> festzulegen, in welcher Reihenfolge die Prozesse wieder anlaufen?
Du kannst in einem Prozess ein Signal setzen, und im anderen abfragen,
wie der Zustand des Signals ist:
1
:
2
signalweiter:std_logic:='0';
3
:
4
processbegin
5
:
6
tuwas...
7
waitfor3us;
8
machwas...
9
waituntilirgendwas;
10
:
11
waitfor300ns;
12
weiter<='1';
13
endprocess;
14
15
processbegin
16
waituntilrising_edge(weiter);
17
:
18
:
19
endprocess;
Aber sowas wird schnell unübersichtlich. Besser wäre da eine zentrale
State-Machine, die die Verwaltung der einzelnen Prozesse übernimmt.
> Wie sieht das eigentlich mit den Auswirkungen des IO auf das> Zeitverhalten der Simulation aus?
Während der Dateizugriffe bleibt die simulierte Zeit einfach stehen. Die
Zugriffe finden quasi mit delta-T=0 statt.
> Deshalb "entwickle" ich gerade mit Modelsim und dem Wavediagram. Wenn> ich dann mit dem Zeitverhalten meiner Module zufrieden bin, dann widme> ich mich wieder der Synthese.
Nur als Empfehlung, aber ich denke nicht, dass dies ein günstige Ansatz
ist.
Du mußt lernen zu unterscheiden :
- Was darf ich in einem Modul verwenden, das synthetisiert werden soll
und wie beschreibe mein gewünschtes Verhalten. Dazu gehören Register,
FFs, FSM usw.
Diese Muster kann man auch anwenden, wenn man nicht alle Feinheiten von
VHDL verstanden hat.
- Was kann ich in einer Testbench verwenden.
Das sind Delays, File I/O, waits an beliebigen Stellen in Prozessen usw.
Du verwendest File I/O und ähnliches, aber die Grundlagen scheinen noch
nicht ganz zu sitzen.
>> Gibt es die Möglichkeit, Prozesse zu priorisieren, d.h. irgendwie>> festzulegen, in welcher Reihenfolge die Prozesse wieder anlaufen?> Du kannst in einem Prozess ein Signal setzen, und im anderen abfragen,> wie der Zustand des Signals ist:
Ok, das habe ich ja schon gemacht. Danke.
> Du mußt lernen zu unterscheiden :> - Was darf ich in einem Modul verwenden, das synthetisiert werden soll> und wie beschreibe mein gewünschtes Verhalten. Dazu gehören Register,> FFs, FSM usw.> Diese Muster kann man auch anwenden, wenn man nicht alle Feinheiten von> VHDL verstanden hat.> - Was kann ich in einer Testbench verwenden.> Das sind Delays, File I/O, waits an beliebigen Stellen in Prozessen usw.
Hm, ich denke, das habe ich verstanden.
Die delays, die ich in den Modulen eingesetzt habe, die mal
synthetisiert werden sollen, sind nur für die Simulation drin.
Irgendwie musste ich meinem "Fehler" ja auf die Spur kommen.
Genauso wie die Konsolen-Ausgaben - die sind nur für die Simulation.
... by the way: gibt es sowas wie ein #ifdef für VHDL?
> Du verwendest File I/O und ähnliches, aber die Grundlagen scheinen noch> nicht ganz zu sitzen.
File I/O verwende ich aus Faulheit ;) Einmal habe ich die Werte seriell
kodiert - nur um dann festzustellen, dass die Fehlerquelle und
Fehlerwahrscheinlichkeit viel zu hoch ist, um einem Testergebnis zu
vertrauen.
Also habe ich ne Testbench geschrieben, die die Werte aus einer Datei
liest. Das tut jetzt zuverlässig. Und da ich auch an dieser Stelle sehr
bequem bin, musste das File I/O auch gleich die Zahlentypen
konvertieren, sodass ich Werte als Int-, Hex-, Oktal- und Binärwert
angeben kann.
Die Grundlagen sitzen deshalb noch nicht, weil dies meine erste
Testbench ist. In den meisten Tutorials wird der BNF-Graph der Sprache
abgedruckt, ohne auf Sinn und Zweck einzugehen, geschweige denn
sinnvolle Beispiele zu geben.
Vieles habe ich mir von Lothar, opencores und freemodel abgeschaut.
Jetzt aber die Theorie und Praxis zusammen zu bringen - da krankt es
noch etwas.
Deshalb kann es schon vorkommen, dass ich hier scheinbar abstruse Fragen
stelle.
Dank Eurer Hilfe wird aus den Puzzleteilen langsam ein Bild :)