Hallo, ich bin gerade in ein Problem gelaufen und zwar habe ich eine
FSM.
1
processbegin
2
3
iffsm=s_Waitthen
4
waituntilfalling_edge(nCS);
5
fsm<=s_Active;
6
elsiffsm=s_Activethen
7
waituntilrising_edge(nCS);
8
fsm<=s_Wait;
9
endif;
10
11
endprocess;
Die soll das nCS verwenden und darauf reagieren. Ich brauche das nur in
einer Testbech, also nicht in Hardware. Allerdings ist es jetzt so, dass
da die Flanken oft nicht beachtet werden und ich weiß nicht wieso.
Ja, normalerweise hat man nur einen Takt und hätte das wait until ganz
man Anzang im process, aber in der Simulation wird doch der ganze
process bei jedem Tick neu angeschaut. Und da sollte klar sein, dass
aktuell fsm z. B. s_Wait ist und dann wird da auf die fallende Flanke
gewartet.
Was ich seltsam finde ist, dass es eben doch manchmal auf Flanken
reagiert.
Im Anhang die Dateien und das Demoprojekt.
Gustl B. schrieb:> Was ich seltsam finde ist, dass es eben doch manchmal auf Flanken> reagiert.
Das sieht für mich wie das normale Verhalten von Signalen in Prozessen
aus: weil keine Sensitivliste involviert ist, wird die letzte
Zuweisung erst beim nächsten wait übernommen, aber eben *nicht am
Prozessende*!
Deshalb hat nach der Zuweisung bei der nächsten if-Runde der Zustand der
FSM sich noch nicht geändert.
Probiers mal so
Ja, richtig, aber Sensitivliste und wait will der Simulator nicht.
Bei deiner Lösung kann ich aber leider nur auf eine Flankenart von einem
Signal reagieren.
Ich möchte aber eben eine FSM in der ich in Abhängigkeit vom State auf
eine andere Flankenart von unterschiedlichen Signalen reagieren kann.
Vielleicht sollte ich das ganz ohne Process mit einem
fsm <= s_Wait when ... lösen.
Oder doch mit einem Takt der schnell genug ist dass es aussieht als wäre
das instantan.
Gerne würde ich aber, weil es hier um ein SPIähnliches Signal geht, auch
mehrere Flanken warten ohne das getaktet zählen zu müssen. Ein
Wait until rising_edge(SCLK);
Wait until rising_edge(SCLK);
Wait until rising_edge(SCLK);
Wait until rising_edge(SCLK);
Wartet dann eben bis nach der 4. SCLK Flanke.
Ich hatte vermutet, dass das in der Testbench alles möglich ist.
Dein Problem ist, dass dein Prozess nicht
gestartet wird, bevor nCS sich ändert.
Er müsste aber bei jeder Änderung von <fsm>
durchlaufen werden (wegen der IF-Anweisung),
dazu müsste aber <fsm> in der Sensitiv-Liste
stehen, die es aber wegen deiner wait's nicht
geben darf. Und genau deshalb wird jede erste
Flanke (je nach WAIT/ACTIVE) ignoriert und
jede zweite Flanke berücksichtigt.
Dass die Signale schon richtig gesetzt werden,
erkennst du ja an deiner Ausgabe, aber ebenso
lässt sich ja mithilfte meines Arguments erkennen,
dass <fsm> nicht sofort berücksichtigt wird.
Dir bleibt also nichts anderes übrig,
als deinen Ansatz komplett anders zu
formulieren.
OK verstanden.
Ich hatte gehofft, dass das in der Simulation, also die Testbench wie
Software abgearbeitet wird. Das spring also in einen If Zweig und wartet
dann dort bis die Flanke kommt. Aber ist wohl nicht so ... naja, dann
schreibe ich das eben getaktet ...
Oh nein!!!
1
begin
2
3
process(fsm,nCS)begin
4
5
iffsm=s_Waitthen
6
iffalling_edge(nCS)then
7
fsm<=s_Active;
8
endif;
9
elsiffsm=s_Activethen
10
ifrising_edge(nCS)then
11
fsm<=s_Wait;
12
endif;
13
endif;
14
15
endprocess;
Das gute alte If funktioniert statt einem Wait. Ist aber eben nicht
blockierend wie ich das bei dem Wait gehofft hatte.
Es wird auch sequentiell abgearbeitet. Dein Problem ist die
Funktionsweise von Signalen.
Dein Prozess läuft bis zum nächsten "wait" in 0 Zeit. Dein Signal ändert
sich jedoch erst nach einem beliebig kleinen Zeitschritt. Daher hat sich
das Signal bis zum erreichen des if's noch nicht geändert, sondern erst
nach dem nächsten "wait".
Gut, aber dann würde es ja genügen hinter jede Zuweisung ein kurzes wait
100 ps; zu schreiben.
Tatsache, schick! Vielen Dank, jetzt habe ich das auch verstanden.
Gustl B. schrieb:> Bei deiner Lösung kann ich aber leider nur auf eine Flankenart von einem> Signal reagieren.
Aha, übersehen.
Dann etwa so:
1
process(nCS)begin
2
iffsm=s_Waitandfalling_edge(nCS)then
3
fsm<=s_Active;
4
elsiffsm=s_Activeandrising_edge(nCS)then
5
fsm<=s_Wait;
6
endif;
7
endprocess;
Oder so:
1
process(nCS)begin
2
iffsm=s_WaitandnCS='0'then
3
fsm<=s_Active;
4
elsiffsm=s_ActiveandnCS='1'then
5
fsm<=s_Wait;
6
endif;
7
endprocess;
Oder so:
1
processbegin
2
waitonnCS;
3
iffsm=s_WaitandnCS='0'then
4
fsm<=s_Active;
5
elsiffsm=s_ActiveandnCS='1'then
6
fsm<=s_Wait;
7
endif;
8
endprocess;
Gustl B. schrieb:> die Testbench wie Software abgearbeitet wird.
Ein Prozess wird natürlich sequenziell abgearbeitet. Allerdings sind
Signale eben Signale und damit stur bis zum nächsten wait.
> wie Software
Auch wenn VHDL gern mal als "Programmiersprache" bezeichnet wird, ist
sie trotzdem keine prozedurale Programmiersprache. Deshalb darf man
nicht erwarten, mit VHDL genauso "top-down" wie mit Java oder C/++/#
programmieren zu können.
Gustl B. schrieb:> hinter jede Zuweisung ein kurzes wait 100 ps; zu schreiben.> Tatsache, schick!
Ähm, naja...
Irgendwann fällt dir so ein Pseudo-Delay garantiert auf die Nase. Denn
das Delay kommt ja nicht aus dem System, das du beschreibst und
simulieren willst. Sondern du brauchst es, weil du etwas machen willst,
was die Sprache im Grunde nicht kann.
Lothar M. schrieb:> Dann etwa so:process (nCS) begin> if fsm = s_Wait and falling_edge(nCS) then> fsm <= s_Active;> elsif fsm = s_Active and rising_edge(nCS) then> fsm <= s_Wait;> end if;> end process;
Das hatte ich oben schon getan, aber die Flankenerkennung jeweils in ein
weiteres IF getan - auch das funktioniert.
Lothar M. schrieb:> Irgendwann fällt dir so ein Pseudo-Delay garantiert auf die Nase.
Ja. Wie so oft sollte man wissen was man tut und wenn man ein Werkzeug
anders als gedacht verwendet sollte man auch die Nachteile und Risiken
dabei bedenken. Bei meinem aktuellen Problem ist das kleine Delay kein
Problem. Statt 100 ps kann ich ja auch 2 ps schreiben. Ich würde aber
vermuten, dass da etwas größeres als die Simulator Zeitauflösung stehen
sollte.
Eben wegen deiner letzten Antwort.
Das kommt eben davon, wenn man Wartekommandos nimmt, Prozesse scheinbar
schlafen legt, dann aber permanent abzufragende Bedingungen vorschaltet.
Das gibt nur Kompikationen.
Ich täte das konventionell mit if rising_edge machen und einen Prozess
mit kompletter Sensi schreiben. Das spart Rechenzeit, weil das nur
angefahren wird, wenn sich an den Signalen was tut.
Ja das stimmt schon, aber wie willst du dann zwischen der ersten und
zweiten Flanke gleichen Typs unterscheiden?
Mit
Wait until falling_edge(nCS);
Wait until rising_edge(SCLK);
Wait until rising_edge(SCLK);
Wait until rising_edge(SCLK);
Wait until rising_edge(SCLK);
Wait until rising_edge(nCS);
kann man schön von Flanke zu Flanke springen.
Ich weiß jetzt jedenfalls wie das funktioniert und eben dass Zuweisungen
nicht sofort passieren, sondern erst mit dem nächsten
Simulationsschritt.
Christoph Z. schrieb:>> wait on nCS;> Danke, wieder etwas gelernt über VHDL!
Kein Ursache, geht aber leider nur in der Simulation... :-(
Für die Synthese funktioniert nach wie vor bestenfalls "wait until".
Generell hilft da dann das Handbuch zum Synthesizer weiter.