Ich habe hier eine State-Machine und einen Barrelshifter. Die State-Machine gibt vor um wie viel Bits der Barrelshifter weiter schieben soll. Der BarrelShifter ist am Ausgang rein kombinatorisch. Also wenn die State-Machine z.B. vorgibt um 4 Bits weiter zu schieben, dann wird das auch sofort am Ausgang des Barrelshifters transparent. Erst wollte ich den Ausgang des Barrelshifters auch getaktet realisieren, aber ich möchte im ersten Takt z.B. vorgeben um 4 Bits weiter zu schieben und im nächsten Takt möchte ich das Ergebnis des Barrelshifters zur Verfügung haben. Jetzt habe ich mein Design das erste mal synthetisiert und die Xilinx-Synthese-Tools geben mir eine ganze Liste mit Signalen, welche in den Prozess stehen sollten. Darunter auch der Ausgang des Barrelshifters (ist ein Eingang für die Statemachine). Setze ich den Ausgang des Barrelshifters allerdings in die Statemachine, so erhalte ich von ISIM folgende Fehlermeldung: ERROR: at 85 ns(10000): Iteration limit 10000 is reached. Possible zero delay oscillation detected where simulation can not advance in time because signals can not resolve to a stable value in.... Also was mache ich da jetzt? Im Grunde soll nur beim Zustandswechsel der State-Machine (welcher synchron zum Clock ist) irgendwas passieren. Also reicht es doch eigentlich den aktuellen Zustand in der Sensitivity-Liste der State-Machine zu haben, oder?
Hm, zwar viel geschrieben, aber wenig gezeigt. Wie sieht denn deine Beschreibung aus? Es klingt ein wenig, als wenn der Ausgang der Kombinatorik gleichzeitig auch Eingang ist, also eine kombinatorische Schleife?
Daniel__m schrieb: > aber wenig gezeigt Leute, benutzt doch mal eure Phantasie :-) Ist halt etwas mehr Code, das hier alles rein zu stellen wäre ein wenig zu viel. Also erstmal der Zustandsübergang für die State-Machine:
1 | -- Getakteter Zustandsübergang
|
2 | StateTransition : process(rst,clk,enable) |
3 | begin
|
4 | if rst = '1' OR enable = '0' then |
5 | -- Reset-Zustand
|
6 | state <= sReset; |
7 | elsif rising_edge(clk) then |
8 | -- Zustandsübergang
|
9 | state <= next_state; |
10 | end if; |
11 | end process; |
Jetzt die State-Machine:
1 | StateMachine : process(state) |
2 | begin
|
3 | |
4 | next_state <= state; |
5 | |
6 | -- Default-Werte
|
7 | shifter_cnt <= 0; |
8 | |
9 | case state is |
10 | when sReset=> |
11 | next_state <= sState1; |
12 | |
13 | when sState1=> |
14 | -- Hier wird noch irgendwas mit shifter_data berechnet
|
15 | -- Eigentlich wird aus shifter_data auch shifter_cnt berechnet (!)
|
16 | shifter_cnt <= shifter_data(15 downto 11); |
17 | next_state <= sState2; |
18 | when sState2=> |
19 | -- Hier wird noch irgendwas mit shifter_data berechnet
|
20 | -- Eigentlich wird aus shifter_data auch shifter_cnt berechnet (!)
|
21 | shifter_cnt <= shifter_data(15 downto 11); |
22 | next_state <= sState1; |
23 | end case; |
24 | end; |
shifter_cnt gibt an um wieviel der Shifter im nächsten Takt verschoben werden soll. shifter_data sind die Ausgangsdaten des Barrelshifters. Im Anhang ist der Barrelshifter. Wenn ihr zum Shifter noch eine Idee / Anregung habt wäre ich auch ganz dankbar :-) Den Barrelshifter brauche ich, weil ich einen Stream mit variabler Wort-Breite habe und ich mit 8 Bit Bus-Breite die Daten nachladen möchte. Wird ein Wort dekodiert, so wird der Stream um die Wortbreite weiter geschoben. Wenn wieder volle 8 Bit im Shifter frei sind, dann werden über den Datenbus die nächsten 8 Bit rein geladen.
:
Bearbeitet durch User
> Also erstmal der Zustandsübergang für die State-Machine: Ein asynchroner kombinatorischer Reset. Das wird dir noch viel Spass und einige graue Haare verschaffen. Das Stichwort dazu heißt: Glitch (hier besonders auf der enable-Leitung). > Den Barrelshifter brauche ich,weil ich einen Stream ... habe Woher kommen die Daten? Wohin gehen Sie? Welche Datenrate hast du? Welche Taktfrequenz hat dein System? > ERROR: at 85 ns Was passiert denn eigentlich zum Zeitpunkt "85 ns"? BTW: Der Fehler ist (wie üblich) nicht im geposteten Code. Ich tippe (wie Daniel) auf eine kombinatorische Schleife im auskommentierten Bereich der geposteten FSM.... > Im Anhang ist der Barrelshifter. Der sieht auch wild aus.... :-o
Ich weiss nur, dass immer wenn ich so etwas versucht habe, es später irgendwelche Probleme gab. Deshalb habe ich nur noch Clock-getaktete Prozesse. Andere Spielereien überlasse ich echten Profis, die das jeden Tag machen.
Hallo, also ich würde sagen er hat eine kombinatorische Schleife durch die Kombination von FSM und Barrelshifter da der barrelshifter Ausgang kombinatorisch mit shiftcnt gebildet wird, und er Shiftcnt im ebenfalls kombinatorischen FSM Process mit ebenjenem Ausgang bildet. Könnte mich natürlich auch täuschen, wenn man zusammenhangslosen unvollständigen Code postet. Aber mein Vorschlag wäre Shiftcnt zu registern. Mfg
Den Reset kann ich auch synchron ausführen. Wo ist das Problem mit asynchronen Resets? Sehe ich noch nicht. Dateninput, Datenrate und Takt ist alles nicht definiert. Beim Takt würde ich mal so unter 50 MHz annehmen. Der Fehler passiert beim zustandsübergang von Reset. Nur Clock-getaktete Prozesse? Dann müsste ich einiges umschreiben :-/ Was sieht denn am barrelshifter wild aus? Ich glaube dden hat recht. Nur das Problem ist, wenn ich shiftcnt registriere, dann steht mir das Ergebnis der Schiebeoperation erst einen Takt später zur Verfügung. Mit einer Taktflanke würde der neue Wert für Shiftcnt durch die Statemachine erzeugt werden, der Wert wird dann aber erst mit der nächsten Taktflanke in das Register übernommen. Ich kann nochmal versuchen das Problem zu isolieren und kürzeren aber vollständigen Code posten. Meinen vollen Code nur ungern, da das meine Bachelor Arbeit werden soll. Das ganze funktioniert ansonsten in der Simulation, wenn ich in der sensitivity-list nur "state" stehen habe, erst wenn ich "shifter_data" zufüge läuft die Simulation nicht mehr.
@ Marius S. (lupin) Benutzerseite >vollständigen Code posten. Meinen vollen Code nur ungern, da das meine >Bachelor Arbeit werden soll. Na dann wird es höchgste Zeit, dass du mal die Grundlagen der Digitaltechnik verstehst. Einfach nur wild was in VHDL hinschreiben ist wenig zielführend. Eigentlich [tm] ist es recht einfach. Eine kombinatorische Logik kann eine beliebige logische Funktion abbilden, u.a. deinen Barrelshifter. Mit Kombinatorik allein kann man aber keine sequezielle Logik ala Statemachines etc., aufbauen, dafür benötigt man Speicherelemente, aka FlipFlops. Und drittens darf kombinatorische Logik immer nur in eine Richtung Daten transportieren, kombinatorische Rückkopplungen sind bis auf wenige Ausnahmen ein No Go! Dort müssen praktisch immer Register zwischengeschaltet werden. >Das ganze funktioniert ansonsten in der Simulation, wenn ich in der >sensitivity-list nur "state" stehen habe, erst wenn ich "shifter_data" >zufüge läuft die Simulation nicht mehr. Du klebst viel zuviel am VHDL, du musst dir bildlich klar machen, wo die Register liegen und wo die Logik. In dem Punkt war der Entwurf mittels Schaltplaneingabe und Logiksymbolen besser, weil man direkt gesehen hat, was wo langgeht. Eigentlich [tm] dollte man mit VHDL NICHT anfangen, bevor man nicht die graphische Methode bis zu ein bestimmten Punkt geübt und WIRKLICH verstanden hat. Dazu reichen auch einfache Schaltungen. Schau dir die Grundschaltungen der Meele, More und Medvedev-Automaten an, dann verstehtst du hoffentlich, was ich meine.
Marius S. schrieb: > Das ganze funktioniert ansonsten in der Simulation, wenn ich in der > sensitivity-list nur "state" stehen habe, erst wenn ich "shifter_data" > zufüge läuft die Simulation nicht mehr. Das ist es, was der Synthesizer dir sagen möchte: "Da fehlen etliche Signale in der Sensitivliste. Mich schert das nicht, weil ich diese Liste nicht verwende. Aber deine Simulation wird nicht zur Realität passen!" Und das ist diese Liste, die du da dann angezeigt bekommst: Marius S. schrieb: > die Xilinx-Synthese-Tools geben mir eine ganze Liste mit Signalen, > welche in den Prozess stehen sollten. Fazit: deine Simulation mag zwar "funktionieren", sie ist aber schlicht und einfach falsch... :-( Falk Brunner schrieb: > Du klebst viel zuviel am VHDL, du musst dir bildlich klar machen, wo die > Register liegen und wo die Logik. ... Ich würde sogar sagen, man muss sich vorher ein Bild von der Hardware machen, und diese mit der HardwareBESCHREIBUNGSsprache VHDL beschreiben. Es wird auf jeden Fall niemals gut gehen, wenn man mit VHDL ins blaue "programmiert" wie man das bei PC- oder uC-Programmen gerne sieht...
Okay, zurück ans Reißbrett :-) Also ich habe mir das immer so vorgestellt, dass die Sensitivity-Liste des Prozesses angibt mit welchen Signalen der Prozess ausgelöst werden soll. Bei meiner Statemachine habe ich halt nur den Status der State-Machine in der Sensitivity-Liste. Ich dachte jetzt, dass wenn ich in der State-Machine ein kombinatorisch erzeugtes Signal verarbeite (wie z.B. das vom Barrelshifter) dieses Signal nur bei Änderung des Zustands eingelesen wird (und auch gelatcht wird). Ich glaube die Synthese-Tools geben darüber auch Warnungen aus (das Latche erzeugt werden). Aber okay, selbst wenn das funktioniert (durch die indirekt erzeugten Latches) ist das wohl gegen die Idee von VHDL, dass man alles bis ins Detail beschreiben muss ;-( Kann man davon ausgehen, wenn die Synthese-Tools keine Warnungen mehr anzeigen, dass dann die Synthese mit der Simulation übereinstimmt? Ich werde mal versuchen die Post-Synthese Simulation durch zu führen und schauen was dann dabei raus kommt. Ich kann mir vorstellen, dass die Synthese-Tools durch Einfügen von Latches etc. was lauffähiges erzeugt haben.
:
Bearbeitet durch User
@ Marius S. (lupin) Benutzerseite >Okay, zurück ans Reißbrett :-) Oder ins Kornfeld ;-) >Also ich habe mir das immer so vorgestellt, dass die Sensitivity-Liste >des Prozesses angibt mit welchen Signalen der Prozess ausgelöst werden >soll. Das ist auch so. Aber man kann sich damit auch schön verarschen. >Bei meiner Statemachine habe ich halt nur den Status der State-Machine >in der Sensitivity-Liste. Das ist schön, nützt dir aber wenog. Den der Synthesizer merkt, dass du ihm eine unvollständige Liste gegeben hast, schmeißt ne Warnung und synthetisiert vollständig. Aber der Simulator hält sich strikt an die Sensitivity-Liste. Schwupps, schon hast du ein vollkommen anderes Verhalten zwischen Simulation und Synthese. 8-0 >Ich dachte jetzt, dass wenn ich in der State-Machine ein kombinatorisch >erzeugtes Signal verarbeite (wie z.B. das vom Barrelshifter) dieses >Signal nur bei Änderung des Zustands eingelesen wird (und auch gelatcht >wird). So ist es aber nicht. Siehe mein anderes Posting. >Ich glaube die Synthese-Tools geben darüber auch Warnungen aus (das >Latche erzeugt werden). Jo. >Aber okay, selbst wenn das funktioniert (durch die indirekt erzeugten >Latches) ist das wohl gegen die Idee von VHDL, dass man alles bis ins >Detail beschreiben muss ;-( ??? >Kann man davon ausgehen, wenn die Synthese-Tools keine Warnungen mehr >anzeigen, dass dann die Synthese mit der Simulation übereinstimmt? Hmmm, jain. Meistens schon, aber es gibt immer Stolperfallen. >Ich werde mal versuchen die Post-Synthese Simulation durch zu führen und >schauen was dann dabei raus kommt. Ist relativ sinnlos. Mach es einfach richtig (tm), ohne Tricks. Die braucht es hier ganz sicher nicht. > Ich kann mir vorstellen, dass die >Synthese-Tools durch Einfügen von Latches etc. was lauffähiges erzeugt >haben. Aber nichts, was du wirklich willst. Oder brauchst. Siehe oben.
Falk Brunner schrieb: > Ist relativ sinnlos. Mach es einfach richtig (tm), ohne Tricks. Die > braucht es hier ganz sicher nicht. Ja, habe ich jetzt versucht. Das Simulieren des Post-Synthese-Modells habe ich mir mal gespart, werde ich machen wenn ich meine das ich fertig bin :-) Auf Lothars Seite habe ich noch folgendes gefunden: http://www.lothar-miller.de/s9y/categories/37-FSM > Diese Ein-Prozess-Beschreibung ergibt genau das selbe Simulationsergebnis, > sie hat aber deutliche Vorteile: > 1) Deutlich weniger Schreibaufwand und bessere Übersicht > 2) Ich brauche weniger Signale (next_counter, next_state) > 3) Das Ganze ist garantiert synchron > 4) Die Ausgangssignale sind registriert und damit synchron > 5) Es werden garantiert keine Kombinatorischen Schleifen erzeugt Also habe ich mal alles in einen Prozess beschrieben. Jetzt synthetisiert auch alles ohne Warnungen und die Simulation sieht auch gut aus, bis auf eine Kleinigkeit. Ich verwende ein Block-RAM um Werte aus zu lesen. In einem Zustand der FSM wird die Adresse erzeugt, im nächsten Zustand soll der Wert ausgelesen werden. Bei der Beschreibung mittels Ein-Prozess FSM ist aber alles irgendwie um einen Takt verschoben.
1 | StateMachine : process |
2 | begin
|
3 | wait until rising_edge(clk); |
4 | -- Default-Zustände für Cases in denen Werte nicht beschrieben werden
|
5 | lut_addr <= '0'; |
6 | lut_addr <= (others => '-'); |
7 | case state is |
8 | when sReset=> |
9 | state <= sTableLookup; |
10 | |
11 | when sTableLookup=> |
12 | -- Daten aus Stream nehmen um Tabelle zu indizieren (table lookup)
|
13 | lut_addr <= uint2slv(lut_offs + slv2uint(shifter_data(WINDOW_WIDTH-1 downto WINDOW_WIDTH-lut_size)), 12); |
14 | lut_en <= '1'; |
15 | state <= sReadVal; |
16 | |
17 | when sReadVal=> |
18 | -- Value-Dekodierung
|
19 | xy(0) <= GETX(lut_data); |
20 | xy(1) <= GETY(lut_data); |
21 | ....
|
22 | end case; |
23 | end process; |
Das Block-RAM ist ein synchroner Prozess, der bei steigender Flanke und lut_en='1' den Wert an lut_addr ausliest. Hier seht ihr auch, dass ich aus shifter_data einen Wert mit variabler Bit-Länge raus ziehen muss. Das führt zu einem ganzen Haufen Kombinatorik :-( Aber das ist ein anderes Problem. Wenn ich das im Kopf durch simuliere und annehme, dass Reset inaktiv ist: 1. Steigende Flanke sReset-Zustand wird abgearbeitet. Wechsel sReset -> sTableLookup 2. Steigende Flanke sTableLookup-Zustand wird abgearbeitet. Jetzt liegen lut_addr und lut_en an. Wechsel sTableLookup -> sReadVal 3. Steigende Flanke sReadVal-Zustand wird abgearbeitet. Erst jetzt werden die Daten aus dem Block-RAM geladen. Die Verarbeitung erfolgt also noch mit ungültigen / alten Daten. Einzige Möglichkeiten, die ich sehe um das Problem zu lösen: 1) Über kombinatorischen Prozess In einem extra Prozess wird der Status abgefragt, wenn status=sTableLookup dann werden die Signal lut_addr und lut_en erzeugt. Das führt dazu, dass die Daten schon bei der 2ten steigenden Flanke gelesen werden. 2) Taktung des Block-RAMs bei fallender Flanke Ist wahrscheinlich ziemlich schlecht, weil lut_addr und lut_en am Block-RAM dann nur für eine halbe Taktperiode stabil anlegen bevor das Block-RAM gelesen wird. Aber das Block-RAM würde dann bei der fallenden Flanke nach der 2ten steigenden Flanke gelesen werden. 3) Zusätzlicher Wartezustand In der 2ten steigenden Flanke wird nicht nach sReadVal sondern in einen Wartezustand gewechselt, welcher mit der 3ten steigenden Flanke abgearbeitet wird und in den Zustand sReadVal wechselt. Alle drei Möglichkeiten habe ich mal ausprobiert und funktionieren auch. Nur möchte ich eigentlich ungern noch einen Wartezustand einbauen, das wäre wahrscheinlich von der Beschreibung her die schönste Lösung (ohne Tricks :)). Was kann man da noch machen? Oder wie sollte ich das implementieren, wenn ich keine Zeit verlieren will? :-)
@ Marius S. (lupin) Benutzerseite >ausgelesen werden. Bei der Beschreibung mittels Ein-Prozess FSM ist aber >alles irgendwie um einen Takt verschoben. Ist halt so. Geht mit der Ein-Prozess Methode nicht anders. Aber man muss nicht immer krampfhaft damit arbeiten, die zwei Prozess Methode geht auch. Die Nachteile sind zu verschmerzen. >Wenn ich das im Kopf durch simuliere und annehme, dass Reset inaktiv >ist: Stimmt soweit. >Einzige Möglichkeiten, die ich sehe um das Problem zu lösen: >1) Über kombinatorischen Prozess Ist OK. >2) Taktung des Block-RAMs bei fallender Flanke Kann man machen, beschränkt aber die maximal möglicke Taktrate. Würde ich nicht empfehlen. >3) Zusätzlicher Wartezustand Geht auch, wob der einfach Ansatz dabei Takte vershwendet, sprich, der Datendurchsatz wird geringer. Wenn man es gut machen will, nutzt man Pipelining, sprich, die FSM zur Verarbeitung läuft halt einen Takt versetzt zur Datenausgabe des RAMs. Dann braucht man nur ein einziges Mal einen Wartezustand, nicht immer wieder. >Was kann man da noch machen? Oder wie sollte ich das implementieren, >wenn ich keine Zeit verlieren will? :-) Du hast doch genügend brauchare Vorschläge. Ich empfehle 1) kombinatorischer Prozess 2) Pipelining
Danke Falk, wollte nur wissen was ihr so empfehlt :) Pipelining hatte ich auch schon im Kopf. Nur sehe ich keine Möglichkeit, dass die FSM ohne die Daten aus dem Block-RAM irgendwie weiter arbeiten kann. Ist eine sehr sequentielle Verarbeitung das ganze. Also ich habe es jetzt kombinatorisch gelöst. Das lässt sich dann auch ohne Prozess usw. hin schreiben. Auch die Entnahme der Bits (mit variabler Länge) habe ich jetzt schöner, nicht mehr in der FSM sondern auch kombinatorisch ohne Prozess beschrieben. Da ich an mehreren Stellen in der FSM eine variable Bit-Länge entnehmen muss hat das auch einiges an LUTs in der Synthese gespart (weil die FSM jetzt nur noch auf ein kombinatorisches Signal zugreift). So langsam wird das ganze schön aufgeräumt.
Eine Frage noch zur Ein-Prozess FSM... Bei der Zwei-Prozess FSM ist es möglich als Default-Werte für die Ausgänge auch "don't cares" also '-' an zu geben (wenn es sich um std_logic oder davon abgeleitete handelt). Ich denke bei der Zwei-Prozess FSM ist es ersichtlich, dass die Ausgänge soweit möglich kombinatorisch durch den Zustand und die Eingänge abgebildet werden. Die Definition von "don't care"-Zuständen hilft den Synthese-Tools dann sicherlich die kombinatorische Logik zu optimieren. Nur wie sieht es bei der Ein-Prozess FSM aus? Sind dort alle Ausgänge garantiert immer getaktet? So verstehe ich das zumindest. Dann bringt es mir ja nichts "don't cares" zu verwenden, oder? Oder sollte man dann das machen, was ich bereits mit der Block-RAM Adressierung gemacht habe und Signale, welche kombinatorisch durch den Zustand erzeugt werden könnten auch so erzeugen?
@ Marius S. (lupin) Benutzerseite >Also ich habe es jetzt kombinatorisch gelöst. >Das lässt sich dann auch ohne Prozess usw. hin schreiben. Es gibt auch kombinatorische Prozesse. Ist aber eher Geschmackssache. >So langsam wird das ganze schön aufgeräumt. Gut. >abgebildet werden. Die Definition von "don't care"-Zuständen hilft den >Synthese-Tools dann sicherlich die kombinatorische Logik zu optimieren. Kann sein. >Nur wie sieht es bei der Ein-Prozess FSM aus? Sind dort alle Ausgänge >garantiert immer getaktet? Ja. > So verstehe ich das zumindest. Dann bringt es >mir ja nichts "don't cares" zu verwenden, oder? Nein.
Okay, verstehe. Ich denke es ist mir überlassen ob ich gewisse Signale durch Kombinatorik abbilden will (was natürlich den Coding-Style der Ein-Prozess FSM ein wenig kaputt macht). Aber da ich sowieso schon ein LUT-Grab erzeugt habe lasse ich das mal lieber als registrierte Logik :-) Ich denke dabei kann ich es belassen. Vielen Dank an Falk und Lothar, ihr habt mir echt weiter geholfen! :-)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.