Hallo, Ich nutze ISE version 9.1i und möchte mit Verilog eine schaltung entwickeln. Ich bin echt am Verzweifeln. es war mir ja die ganze zeit suspekt, dass nur so wenige resourcen in der cpld belegt sein sollen, obwohl mein Design nicht sooo klein ist. Das andere Problem war, dass nachdem ich den fit durchlaufen lasse nur noch 28 ein und ausgänge an den CPLD gelegt, im Modul sind aber ca 50 deklariert. Jetzt habe ich mal versucht einen Teil rauszunehmen den die synthese wegsynthetisiert und habe den in ein neues Projekt gepackt. Und siehe da: Auf einmal werden sogar 36 Register genutzt (vorher im kompletten Projekt sage und schreibe 0, in worten null!!). Und wesentlich mehr pins als voher im kompletten Design! Ich würde es wirklich gene hören wenn irgendwer oder ISE mir sagen würde: Halt dein code ist Blödsinn. Aber es ist nun mal so, dass in der Simulation jede Funktion genau so funktioniert wie sie soll. Ich kann mir das alles beim besten Willen nicht erklären. Ist ISE dermaßen unausgereift? Oder ist bei meinem Code ein riesiger Fehler? Aber wenn das der Fall ist, warum funktioniert die Simulation so 1a? Sollte ich vielleicht auf VHDL umlernen? Noch ist es nicht zu spät. Ich hatte mich für Verilog entschieden, weil ich gelesen habe, dass die beiden eigentlich vollkommen gleichwertig sind, allerdings Verilog leichter zu lernen ist. im Anhang befinden sich die beiden Module.
ISE und deine Implementierung mit ihm wird nicht einfacher wenn du von Verilog auf VHDL umsteigst. Der einzige Unterschied mag sein das sich mehr Leute hier dein Design anschauen und Tipps geben. Dafür wirst du dir aber vielleicht die Haare etwas mehr raufen bis du mit VHDL klar kommst. Das Geheimnis von ISE liegt in den Logdateien die es ausspuckt und diese zu verstehen. Die erste die du dir anschauen solltest ist der Synthesis Report. Dort sollte stehen wenn was wegoptimiert wurde. Ich kenne mich mit CPLDs nicht so aus. Aber mit FPGAs versuche ich immer die FF mit dem globalen Takt zu versorgen. Wenn eine niedrigere Bearbeitung nötig ist, dann nutze ich einen Zähler um ein Freigabesignal zu erzeugen. In deinem hauptmodul.v ist ein inital block, der in synthesierbaren Code nichts zu suchen hat. Wenn du Werte initialisieren musst dann immer durch den if(Reset) teil in einem always block. Du benutzt posedge und negedge. In FPGAs ist das meines Wissens nicht möglich. Weiss nicht wie das mit CPLDs ist. Solltest du vielleicht mal überpüfen ob das möglich ist. Eine andere Sache die mir auffällt, du hast einen always(@posedge clk) block und nimmst dann blocking assignments. Da hab ich letztens ein Super Papier drüber gelesen, wann man Nonblocking und wann blocking assignments nutzen soll. "Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!" http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf Es beschreibt wie man Nonblocking und blocking assignments einsetzen soll, damit der Simulator das gleiche anzeigt was man später auch im Chip implementiert hat. Auf der Seite gibt es eine Fülle von anderen guten Dokumenten über Verilog: http://www.sunburst-design.com/papers/ Gruß, Alban
Noch eine Anmerkung: > Du benutzt posedge und negedge. In FPGAs ist das meines Wissens nicht > möglich. Weiss nicht wie das mit CPLDs ist. Solltest du vielleicht mal > überpüfen ob das möglich ist. Das hatte ich etwas komisch geschrieben. In FPGAs kannst du entweder das eine oder das andere Nutzen. Also entweder überall posedge oder überall negedge, aber nicht beides.
Ich bin zwar absolut kein Verilog-Kenner, aber in deinem Modul verwendest Du einen Umschalter, mit dem Du den Takt zwischen 2 Signalen auswählst. Das ist in einem CPLD meist eine schlechte Idee, weil es für die Taktleitung eigene Pins und damit verbundene interne schnelle Signalleitungen gibt. Bei der Verwendung eines Multiplexer können diese Leitungen dann nicht mehr verwendet werden, womit das Timing drastisch verschlechtert wird. Die Verwendung von steigender und fallender Taktflanke in einem Design ist hingegen erlaubt. Grüße Klaus
@Alban: Warum machen denn deiner Meinung nach (hier) mehr Leute VHDL wenn das keine vorteile bietet? Zum initial Block: Wie ich es verstanden hatte kann man den in den code schreiben. Er wird beim Simulieren zuerst ausgeführt, beim synthetisieren aber einfach ignoriert. Ist das falsch? Hier ging es beim initialisieren eigentlich nur darum, dass in einem Register nicht X steht sondern irgend ein bestimmter Wert. Habe ich Blocking assignments verwendet? Wo? Ich dachte ich hätte nur unblocking assignments verwendet. In einem Tutorial habe ich auch gelesen, dass man in synthetisierbarem Code nur eine sorte verwenden sollte. Oder war es nur eine sorte und nicht beide vermischt? Ich werde mir das Papier mal durchlesen. @Klaus: Zuerst wollte ich 2 Takte verwenden und dachte dass das eigentlich auch kein Problem ist, da ich verschiedene Takteingänge zur Verfügung habe. es gibt ja mehrere GCKs. Ist das so richtig? Es war aber auch die ganze Zeit geplant, dass der Takt auch langsamer laufen kann. Zuerst wollte ich das irgendwie extern machen, aber dann habe ich mir gedacht dass man das eigentlich auch im CPLD machen könnte. Dafür hat man die Dinger ja, nicht tausende logik ICs sondern nur ein CPLD. Wie wäre es denn, wenn ich das gewissermaßen seperat im CPLD mache. Also zuerst einen Takteingang nutzen der nur an einen teiler und einen multiplexer angeschlossen ist, das Ergebnis kommt an einen I/O pin, der wird wieder an einen GCK geführt. Zum glück hat man ja 3 von den dingern. passt ja genau. Diese Lösung scheint mir nicth so elegant zu sein, aber wenn das besser ist (ist es?) ist das natürlich auch eine Möglichkeit. Allgemein muss ich sagen, dass es echt schwierig ist CPLD Programmierung zu lernen. Bisher habe ich nur sachen mit Mikrocontrollern (Pic) gemacht. Finde ich irgendwie einfacher. Liegt vielleicht daran, dass das Programm gewissermaßen wie auf einem PC ausgeführt wird und man daher das ganze schon ein bisschen kennt und sich leichter reindenken kann. Ein Problem dass ich hier habe ist, dass ich mit den Tutorials die ich mir bisher angesehen habe keine Praktikablen Sachen lerne. Ich meine ich lerne nicht welche Programmierweise sinnvoll ist und welche zwangsweise zu Problemen führt, weil die synthese kompliziert wird. Das mag auch daran liegen, dass einige von diesen tutorials allgemein für verilog waren und nur dafür gedacht waren auf einem PC simuliert zu werden, nie aber synthetisiert zu werden. Gibt es irgendwo eine Möglichkeit wie man das Ganze einfach lernen kann? Die Papers von der Seite sind sicher gut, aber auch sicher ein hartes Brot, wenn man noch nicht so viele Grundlagen hat. Wo habt ihr das gelernt? Uni/FH? Eigentlich will ich das ganze als Hobby betreiben, das heißt nicht täglich 8 Stunden knobeln und irgendwann nach Monaten erste Erfolge haben.
>@Alban: >Warum machen denn deiner Meinung nach (hier) mehr Leute VHDL wenn das >keine vorteile bietet? Das hat nichts groß mit Vorteilen zu tun, sondern mit Geographie. Wenn in dem Forum mehr Leute aus Japan oder USA posten würden, dann gäbe es auch mehr Verilog Nutzer. >Zum initial Block: >Wie ich es verstanden hatte kann man den in den code schreiben. Er wird >beim Simulieren zuerst ausgeführt, beim synthetisieren aber einfach >ignoriert. Ist das falsch? Das stimmt, aber du solltest das nicht mischen. Sonst zeigt dir die Simulation wohlmöglich was anderes an als was deine Logik dann später macht. >Habe ich Blocking assignments verwendet? Wo? Ich dachte ich hätte nur >unblocking assignments verwendet. In einem Tutorial habe ich auch >gelesen, dass man in synthetisierbarem Code nur eine sorte verwenden >sollte. Oder war es nur eine sorte und nicht beide vermischt? Ich werde >mir das Papier mal durchlesen. Wie ich das gesehen habe hast du nur blocking assignments verwendet. Das hängt von dem Konstrukt ab wann diese verwendet werden und wann Nonblocking verwendet werden. In dem Papier ist eine kleine checkliste die sehr hilfreich ist. >Allgemein muss ich sagen, dass es echt schwierig ist CPLD Programmierung >zu lernen. Bisher habe ich nur sachen mit Mikrocontrollern (Pic) >gemacht. Finde ich irgendwie einfacher. Liegt vielleicht daran, dass das >Programm gewissermaßen wie auf einem PC ausgeführt wird und man daher >das ganze schon ein bisschen kennt und sich leichter reindenken kann. Geht mir genauso. Ein Grund warum ich Verilog gewählt habe, weil es näher an C ist und ich micht damit schneller zurecht gefunden habe. Ich glaube ein Unterschied zwischen Programmieren und der Hardwarebeschreibung ist, dass man beim Programmieren hacken kann. Also irgend was schreiben und dann ausprobieren ob es geht. Bei der Hardwarebeschreibung ist das nicht so einfach. Auch durch die parallele Natur wird es komplizierter. Beim Programmieren gibt es auch zig Bücher darüber wie man ein Programm designed, sei es mit UML, Struktogrammen, etc. Bei der Hardwarebeschreibung hab ich so eine formale Methode noch nicht gefunden. Das Geheimnis scheinen State Machines zu sein. Ich hab mir jetzt mal ein Buch gekauft "Advanced Digital Logic Design. Using Verilog, State Machines, and Synthesis for FPGAs" von Sunggu Lee. Das gibt es auch für VHDL. Das geht am Anfang im Sauseschritt über die Grundlagen der Digitalen Logik, geht dann auf die Bedeutung von State Machines ein und konzentriert sich dann Anhand von Beispielprojekten auf die Entwicklungsschritte.
#Beim Programmieren gibt es auch zig Bücher darüber wie man ein Programm #designed, sei es mit UML, Struktogrammen, etc. Bei der #Hardwarebeschreibung hab ich so eine formale Methode noch nicht #gefunden. Sowas gibt es auch, versackt aber meistens in den Büchern über Digitale schaltungstechnik. Allgemein macht sich ein Blockdiagramm immer gut, gerade für den Datenpfad. FSM kann man grafisch ganz gut darstellen (statediagramm. Also erst den datenpfad skizieren (datenrein, gebuffert, verarbeiten, Demuxer,muxer für die Quellen, dasselbe für die verschieden Senken (outputs). Wavediagramme auf dem Papier sind beliebt aber meistens nur für detailprobleme zu verwenden. UML ist in Richtung embedded erweitert worden, das Wissen dazu ist aber nicht sehr verbreitet. meine Empfehlung: Peter Marwedel "embedded system design" isbn 0-387-29237-3. Spannend ist auch uml für FPGA aber da kenne ich nur akademische Arbeiten dazu. Sowas wird dann fast ausschließlich bei IEEE veröffentlicht Für den prozessorentwurf wurde mal FlowCharts angepriesen.
Alban wrote: > Das hat nichts groß mit Vorteilen zu tun, sondern mit Geographie. Wenn > in dem Forum mehr Leute aus Japan oder USA posten würden, dann gäbe es > auch mehr Verilog Nutzer. Und warum machen hier mehr leute VHDL? Reiner Zufall? > Das stimmt, aber du solltest das nicht mischen. Sonst zeigt dir die > Simulation wohlmöglich was anderes an als was deine Logik dann später > macht. Das Problem ist ja viel schlimmer. Die synthetisierte Logik hat rein gar nichts mit dem Code oder der simulation zu tun. > Wie ich das gesehen habe hast du nur blocking assignments verwendet. Das > hängt von dem Konstrukt ab wann diese verwendet werden und wann > Nonblocking verwendet werden. In dem Papier ist eine kleine checkliste > die sehr hilfreich ist. ähm. ich dachte eignetlich: a<=b||c; //blocking a=b||c; //non-blocking ist das falsch? oder meinst du ganz was anderes? >>Allgemein muss ich sagen, dass es echt schwierig ist CPLD Programmierung >>zu lernen. Bisher habe ich nur sachen mit Mikrocontrollern (Pic) >>gemacht. Finde ich irgendwie einfacher. Liegt vielleicht daran, dass das >>Programm gewissermaßen wie auf einem PC ausgeführt wird und man daher >>das ganze schon ein bisschen kennt und sich leichter reindenken kann. > > Geht mir genauso. Ein Grund warum ich Verilog gewählt habe, weil es > näher an C ist und ich micht damit schneller zurecht gefunden habe. Ich frage mich immer mehr ob das was gutes ist. Ich erwische mich immer weider dabei wie ich das "Programm" durchdenke und ich dabei stillschweigend voraussetze dass die befehle sequentiell abgearbeitet werden. Vielleicht kommt man in VHDL da nicht so leicht in Versuchung? > Das Geheimnis scheinen State Machines zu sein. Ich hab mir jetzt mal ein > Buch gekauft "Advanced Digital Logic Design. Using Verilog, State > Machines, and Synthesis for FPGAs" von Sunggu Lee. Das gibt es auch für > VHDL. Hm ich kann mich ganz dunkel aus Informatik erinnern was das ist. Aber brauche ich sowas auch? Ich meine ich will hier nur ein kleines Projekt erstellen. Wenn ich mich richtig erinnere was Zustandsmaschinen sind hätte ich hier ohnehin nur die Zustände in RAM schreiben und aus RAM lesen, mache ich mir da nicht unnötig viel arbeit? FPGA-Küchle wrote: > #Beim Programmieren gibt es auch zig Bücher darüber wie man ein Programm > #designed, sei es mit UML, Struktogrammen, etc. Bei der > #Hardwarebeschreibung hab ich so eine formale Methode noch nicht > #gefunden. > > > Sowas gibt es auch, versackt aber meistens in den Büchern über Digitale > schaltungstechnik. Allgemein macht sich ein Blockdiagramm immer gut, > gerade für den Datenpfad. FSM kann man grafisch ganz gut darstellen > (statediagramm. Also erst den datenpfad skizieren (datenrein, gebuffert, > verarbeiten, Demuxer,muxer für die Quellen, dasselbe für die verschieden > Senken (outputs). > Wavediagramme auf dem Papier sind beliebt aber meistens nur für > detailprobleme zu verwenden. > UML ist in Richtung embedded erweitert worden, das Wissen dazu ist aber > nicht sehr verbreitet. meine Empfehlung: > Peter Marwedel "embedded system design" isbn 0-387-29237-3. > Spannend ist auch uml für FPGA aber da kenne ich nur akademische > Arbeiten dazu. Sowas wird dann fast ausschließlich bei IEEE > veröffentlicht > > Für den prozessorentwurf wurde mal FlowCharts angepriesen. Also ich weiß nicht von allen dingen die du da genannt hast, was es ist (z.B. FSM) aber ich habe es auch so gemacht, dass ich mir zuerst schematisch erst mal aufgezeichnet habe was wann passieren soll und wie alles vernetzt ist. An manchen Stellen habe ich mir Taktsignal und Steuersignale aufgezeichnet, um mir klar zu machen was bei welcher Taktflanke passieren soll. Aber das hilft mir alles nicht dabei wie ich das in Code umsetzen kann bzw ob meine umsetzung in Code bezöglich Synthetisierbarkeit eine einzige Katastrophe ist (was denke ich geschehen ist) oder ob es gut funktioniert.
#Aber das hilft mir alles nicht dabei wie ich das in Code umsetzen kann #bzw ob meine umsetzung in Code bezöglich Synthetisierbarkeit eine #einzige Katastrophe ist (was denke ich geschehen ist) oder ob es gut #funktioniert. ich starte mal einen thread zu synthesefähig. Der Ansatz ist richtig erst mal plan machen (Blockdiagramm, state chart), dann in verilog, vhdl tippern. Das Problem ist die literatur und die üblichen VHDL-Kurse. Die erklären erst mal den kompletten syntax, auch das für synthese tödliche. Und das eigenliche Problem, entwurf eines digitalen systems, wird erst am schluss behandelt. Mein leib und magenbuch dagegen erklärt seitenweise wie ich einen counter, muxer,adder, fsm in vhdl synthetisierbar schreibe. es ist das "HDL Chip Design" und ich stelle es hier vor: http://wikihost.org/wikis/fpgakueche/wiki/books_main Ansonsten findet sich in der xilinx doc ein synthese style guide und die XAPP105 für cpld in vhdl und die xapp143 für cpld in verilog. Letztere habe ich uasnahmsweise an diesen Artikel gehangen.
Hallo, nochmal ich Kann mir jemand den unterschied zwischen sequentieller und kombinatorischer Logik erklären? Bitte mit Beispielen wann man was nehmen sollte und Beispielen wie es sich auswirken würde wenn man an einer Stelle die andere Sorte verwendet. Ist Schon alles dass Kombinatorische parallel ausgeführt wird, Sequentielle nacheinander? Wenn ja ist mir trotzdem einiges nicht so richtig klar. Ich meine wenn man ein Taktsignal hat, wird es dann nicht immer irgendwie nacheinander ausgeführt?
#Also ich weiß nicht von allen dingen die du da genannt hast, was es ist #(z.B. FSM) aber ich habe es auch so gemacht, dass ich mir zuerst FSM heisst finite stae machine, auch zustandsautomat genannt. zum entwerfen malt man sich gern ein zustandsdiagramm auch state chart genannt. Siehe hier: http://de.wikipedia.org/wiki/Endlicher_Automat (vergiß die formel dort, es gehts um Prinzip)
>Und warum machen hier mehr leute VHDL? Reiner Zufall? Ich glaube das hat was mit dem Zeitverlauf zu tun. VHDL wurde als erstes standardisiert. Ich glaube es ist sogar im Rahmen einer Standardisierungsgruppe entwickelt worden. Verilog hingegen wurde von einer Firma entwickelt und erst später der Standardisierung unterzogen. So genau weiß ich den Unterschied aber nicht. Auf jeden Fall wird hier in Europa in Vorlesungen vorwiegend VHDL unterrichtet. Das wird ein übriges dazu beitragen das es hier so verbreitet ist. >> Das stimmt, aber du solltest das nicht mischen. Sonst zeigt dir die >> Simulation wohlmöglich was anderes an als was deine Logik dann später >> macht. >Das Problem ist ja viel schlimmer. Die synthetisierte Logik hat rein gar >nichts mit dem Code oder der Simulation zu tun. Genau! Die HDL (Verilog und VHDL) wurden ursprünglich nur zum Spezifizieren genutzt. Dann später kamen Firmen auf die Idee, Synthesizer zu entwickeln, die es erlaubten direkt von der Hardwarbeschreibung zur FPGA oder der ASIC Implementierung zu kommen. Nur sind die HDLs viel zu mächtig um das alles im Implementierungsprozess zu nutzen. Deswegen unterstützen die Synthesistools immer nur eine sogenannte synthesierbare Untermenge der HDL. Mittlerweile sind die Tools alle ziemlich gleich in diesem. Aber im Endeffekt musst du immer im Handbuch deines Synthesistools nachschauen, was du nutzen kannst und was nicht. Im Endeffekt ist die Hardwarebeschreibung eine schizophrene Sache. Du hast eine Hardwarebeschreibungssprache und darfst für die Implementierung nur einen Teil dafür nehmen. Für die Testbench, um diesen Implementierungsteil zu überprüfen, darfst du dann wiederum die ganze Sprache nehmen. Es ist sogar besser, da Funktionen damit einfacher beschrieben werden können als die Synthesistools es erfordern. Damit deine Implementierung sich jetzt in der Simulation genauso verhält wie es gedacht ist, muss bei der Modulierung einiges beachtet werden. >> Wie ich das gesehen habe hast du nur blocking assignments verwendet. Das >> hängt von dem Konstrukt ab wann diese verwendet werden und wann >> Nonblocking verwendet werden. In dem Papier ist eine kleine checkliste >> die sehr hilfreich ist. >ähm. ich dachte eignetlich: >a<=b||c; //blocking Das ist non-blocking >a=b||c; //non-blocking Das ist blocking >Ich frage mich immer mehr ob das was gutes ist. Ich erwische mich immer >weider dabei wie ich das "Programm" durchdenke und ich dabei >stillschweigend voraussetze dass die befehle sequentiell abgearbeitet >werden. Vielleicht kommt man in VHDL da nicht so leicht in Versuchung? Ich glaube die Schwierigkeit ist die Parallelität zu durchdenken. Ich weiß nicht wieviel du mit Threads programmiert hast, da bekommt auch die Programmierung eine ganz andere Dimension. Ich glaube es erfordert einfach Übung, unabhängig von welche HDL verwendet wird. Übung und das Wissen um all die Unterschiede, die wir hier gerade Diskutieren. Das ist der Vorteil bei der Programmierung. Da gibt es nur die Sprache und der Compiler meckert schon wenn wann nicht funktioniert. Was dann noch schief gehen kann ist die Logik mit der das Programm geschrieben wurde. >> Das Geheimnis scheinen State Machines zu sein. Ich hab mir jetzt mal ein >> Buch gekauft "Advanced Digital Logic Design. Using Verilog, State >> Machines, and Synthesis for FPGAs" von Sunggu Lee. Das gibt es auch für >> VHDL. >Hm ich kann mich ganz dunkel aus Informatik erinnern was das ist. Aber >brauche ich sowas auch? Ich meine ich will hier nur ein kleines Projekt >erstellen. Wenn ich mich richtig erinnere was Zustandsmaschinen sind >hätte ich hier ohnehin nur die Zustände in RAM schreiben und aus RAM >lesen, mache ich mir da nicht unnötig viel arbeit? Die Idee ist aus einem Timing Diagramm eine Zustandsmaschine zu entwickeln. Die wird dann mit der HDL implementiert und so erhälst du die Logik die du brauchst. Als Anhang hab ich mal einen Ausschnitt aus einem Dokument gehängt, das ich hier gefunden habe: http://mvlsi.kaist.ac.kr/lecture/ee203a-2002/file/Ch8.ppt Wenn du jetzt z.B. deinen CPLD mit einem Speicherbaustein verbinden willst, nimmst du das Timing für den Speicherbaustein, generierst die Zustandsmachine dafür und implementierst diese in den CPLD. Schon erzeugt der CPLD das Timing für den Speicherbaustein.
Der Unterschied zwischen kombinatorischer und sequentieller Logik ist eigentlich ganz einfach: kombinatorische Logik arbeitet (eigenständig) ohne Takt, sequentielle mit Takt. Den Takt muss man aber bei der Kombinatorik meist trotzdem beachten, warum erklär ich gleich. Kombinatorik sind einfach nur verdrahtete Gatter, Muxer, und so weiter. Wenn man etwas an den Eingang von Kombinatorik anlegt, hat man (theoretisch) sofort das Ergebnis am Ausgang. Es werden einfach nur die ganzen 0-1-Signale entsprechend den Eingängen bis zum Ausgang durchgeschaltet. Dabei entsteht allerdings natürlich eine Verzögerung, wegen der Signallaufzeiten und Gatterverzögerungen. Ein einfaches AND ohne alles ist zum beispiel simple Kombinatorik. Sequentielle Logik ist im Grunde ein geordneter Ablauf von (taktweisem) Anlegen bestimmter Eingangsmuster an kombinatorische Logik. Das Ergebnis wird dabei üblicherweise in Register geschrieben, also gespeichert. Ein counter ist zum Beispiel i. d. R. sequentielle Logik, wobei der hochzuzählende Wert an den Eingang eines (kombinatorischen) Addierers gelegt wird und der Ausgang des Addierers in ein Register geschrieben wird. Im nächsten Takt wird der Registerwert an den Addierer gelegt usw. . Es tritt nun folgenden Problem auf: Die Kombinatorik benötigt, wie erwähnt, eine bestimmte, wenn auch meist kleine Zeit, bis das Ergebnis aufgrund der Laufzeiten wirklich am Ausgang anliegt. Hänge ich nun davor und danach ein Register und möchte dem ganzen regelmäßig Eingangswerte zuweisen und Werte erhalten, es also takten (getaktet werden die Register mit den Ein- und Ausgangswerten), dann muss ich diese Verzögerungszeit natürlich abwarten. Sonst kann der Ausgangswert noch nicht in das Register geschrieben werden bevor schon wieder ein neuer Eingangswert anliegt. Den Weg in der Kombinatorik, der dabei die längste Verzögerungszeit aufweist und nach dem sich dieses "warten" richten muss, nennt man kritischer Pfad. Daraus lässt sich direkt die Taktgeschwindigkeit ableiten. Benötigt der kritische Pfad beispielsweise 20 ns zum Durchlauf, kann man mit maximal 50 Mhz takten, also eben aller 20 ns einen neuen Eingangswert anlegen.
#Ich glaube das hat was mit dem Zeitverlauf zu tun. VHDL wurde als erstes #standardisiert. Ich glaube es ist sogar im Rahmen einer #Standardisierungsgruppe entwickelt worden. Verilog hingegen wurde von #einer Firma entwickelt und erst später der Standardisierung unterzogen. #So genau weiß ich den Unterschied aber nicht. Auf jeden Fall wird hier #in Europa in Vorlesungen vorwiegend VHDL unterrichtet. Das wird ein #übriges dazu beitragen das es hier so verbreitet ist. Ergänzung: vhdl wurde von anfang von der IEEE als standardisierungskomitee entwickelt, betreut (ieee-1076). Es sollte auch zur Dokumentation genutzt werden, während verilog eben die sprache eines simulators eine softwarebude ist. Das DoD (us-verdeitungsministerium) bestand (besteht?) das für das DoD gefertigte chips mit vhdl code geliefert werden. Es hat sogar die entwicklung von VHDL initiert. Verilog simulatoren galten zu Anfang als schneller als VHDL. Japan hatte eine Zeitlang eine eigene Programmiersprache. Neben usa macht auch Israel viel in verilog, die großen "staatlichen" chipentwickler wie CERN, ESA entwickeln fast ausschliesslich in VHDL. Hier in deutschland macht AMD (dresden) nur verilog, alle dt. FPGA-Verwender die ich kenne (Ericsoon, Rohde&Schwarz,Harman-Becker,men ag,...) schreiben in VHDL oder AHDL (Altera-HDL vhdl-ähnlich), außer sie kaufen code in verilog ein (IP-Cores) vielleicht ist verilog dominierend im Nicht-FPGA/CPLD bereich.
>Hallo, >nochmal ich >Kann mir jemand den unterschied zwischen sequentieller und >kombinatorischer Logik erklären? Bitte mit Beispielen wann man was >nehmen sollte und Beispielen wie es sich auswirken würde wenn man an >einer Stelle die andere Sorte verwendet. >Ist Schon alles dass Kombinatorische parallel ausgeführt wird, >Sequentielle nacheinander? >Wenn ja ist mir trotzdem einiges nicht so richtig klar. Ich meine wenn >man ein Taktsignal hat, wird es dann nicht immer irgendwie nacheinander >ausgeführt? Sequentielle Logik ändert ihren Zustand nur immer zu einem Clocksignal. Mit Verilog nimmt man dazu immer den Konstrukt: always @(posedge clk) Laut dem pdf, dass ich letztens erwähnte hatte, sollen darin immer non-blocking (<=) assignments verwendet werden. Kombinatorische Logik ändert ihren Zustand immer sofort in Abhängigkeit der Eingänge. Mit Verilog kann man damit zwei Konstrukte nehmen: assign a = b; oder always @(b) a = b; Hier werden blockig assignments verwendet. Wann verwendend man nun was? Das hängt von deiner Anwendung ab. Zeit ist in dem CPLD nur durch den Takt gegeben. Wenn also z.B. ein Ausgangssignal sich eine bestimmte Zeit nach einem Eingangssignal verändern soll, dann nimmt man einen Zähler, der in sequentieller Logik implementiert wird. Der zählt dann so lange den Takt, bis die Zeit verstrichen ist. Dann verändert man z.B. mit kombinatorischer Logik den Ausgang. p.s.: Das mit dem Anhang vorhin hat scheinbar nicht funktioniert. Ich meinte z.B, das Timing Diagramm auf Seite 33 von der PPT Datei.
>Wenn du jetzt z.B. deinen CPLD mit einem Speicherbaustein verbinden >willst, nimmst du das Timing für den Speicherbaustein, generierst die >Zustandsmachine dafür und implementierst diese in den CPLD. Schon >erzeugt der CPLD das Timing für den Speicherbaustein. "schon"? ähm... Das Implementieren macht mir die meisten Schwierigkeiten. Mein Ansatz wäre: ich habe einen Zustand schreiben, einen lesen, einen nichts tun, weil speicher voll, evtl noch einen Resetzustand wobei ich mir nicht sicher wäre ob man den überhaupt braucht. Das habe ich mal versucht umzusetzen: module Modul(c1, c2, sel, adr, we, oe, ein, aus, size, ready, rdy_ovr); input c1; input c2; input sel; output [18:0] adr; output we; output oe; input [7:0] ein; output [7:0] aus; input [3:0] size; input ready; input rdy_ovr; reg [18:0] adr; reg we, oe; always @ (c1) begin if (sel==0) begin we<=c1; adr[18:0]=adr[18:0]+1; end else begin we<=1; end end always @ (c2) begin if (sel==1) begin oe<=c1; adr[18:0]=adr[18:0]+1; end else begin oe<=1; end end endmodule synthetisieren geht nicht, fehlermeldung: multiple source for adr[18:0] Kann ise jetzt nicht mal automatisch einen multiplexer davor setzen oder was? Ich denke nicht dass mein problem ist, mit welchem verfahren ich mir mein design veranschauliche. Mein Projekt ist auch so wenig komplex, dass ich denke man könnte auch ohne diese methoden zum ziel kommen. ich habe einfach keine ahnung von der umsetzung. ich kann noch so viele tutorials wälzen, wenn ich eine kleinigkeit verändere funktioniert es nicht mehr und ich weiß nicht warum. vielleicht sollte ich oben statt einem zähler 2 zähler nehmen und dann einen 48 zu 19 muxer dahinter schalten? würde mir sowas klarer werden, wenn ich mir die hardware ebene von CPLDs mal genauer ansehe? Das größte Problem bei meinen designs ist wohl dass ich nie weiß warum es nicht funktioniert. dann mache ich ein workarround nach dem anderen, und dass da nur murx raus kommt is klar.
jesses, ihr schreibt ja schneller als ich lesen kann und viel schneller als ich verstehen kann. @na: ist dann jeder always-block sequentiell? @alban: oh ist sie wohl nicht... ich verstehe nicht, warum man bei kombinatorischer logik blocking assingments braucht. ich meine warum blockieren, wenn es direkt ausgeführt werden soll?
Vielleicht sollte ich mein Projekt mal nach sequentielle und kombinatorische teilen sortieren? Bzw mache ich das schon mit der state machine? sehe eigentlich nicht wo...
was mir grade auffält: warum ist etwas wie: always @(a) kombinatorische logik? ich meine hängt das nicht total davon ab was nacher da drin steht? wenn z.b. b<=a; drin steht dann würde ich auch sagen kombinatorisch, aber wenn in der nächsten zeile c<=b; steht ist es dann nicht eigenltich sequentiell?
ok bei mir siehts jetzt so aus: module Modul(c1, c2, sel, adr, we, oe, ein, aus, size, ready, rdy_ovr); input c1; input c2; input sel; output [18:0] adr; output we; output oe; input [7:0] ein; output [7:0] aus; input [3:0] size; input ready; input rdy_ovr; //reg [18:0] adr; reg [18:0] ctr1,ctr2; //reg we, oe; assign we=c1|sel; assign oe=c2|~sel; assign adr[18:0]= (sel==0) ? ctr1[18:0] : ctr2[18:0]; always @ (posedge c1) begin ctr1[18:0]<=ctr1[18:0]+1; end always @ (posedge c2) begin ctr2[18:0]<=ctr2[18:0]+1; end endmodule ist das besserer stil? es kommen auch kaum noch fehlermeldungen. bzw habe ich die regeln aus dem papier richtig angewendet?
Ich poste mal ein Muster für eine state machine, wie ich sie bevorzuge, es gibt natürlich auch noch andere Möglichkeiten. Zuerst ein kombinatorischer Block, in dem Signale ausgewertet und an den Datenpfad gesendet werden. Außerdem werden Werte an die Registereingänge geschrieben. Danach die Registerzuweisungen, der sequentielle Teil.
1 | parameter Zustand1 = 1'b0; |
2 | parameter Zustand2 = 1'b1; |
3 | |
4 | reg current_state; |
5 | reg next_state; |
6 | |
7 | always@(start, stop, reg1, reg2, steuersignaleingange und alle benötigten |
8 | eingangssignale außer clk und reset) |
9 | begin
|
10 | //Standardzuweisungen falls nötig hierher, können nachher geändert werden, |
11 | // da innerhalb eines |
12 | //always-Blocks Abarbeitung nacheinander erfolgt (obwohl es sich um |
13 | // Kombinbatorik handelt), sind nicht zwingend notwendig |
14 | //z.B. |
15 | next_state = Zustand1; |
16 | ready = 1'b0; |
17 | |
18 | case(current_state) |
19 | Zustand1: //1.Zustand Ruhezustand |
20 | begin
|
21 | |
22 | //Steuersignalzuweisungen für Zustand1 hier machen, Registereingänge, |
23 | //die zur nächsten taktflanke übernommen werden hier anlegen |
24 | next_reg2 = 3'b000; |
25 | |
26 | if (start == 1'b1) |
27 | begin
|
28 | next_state = Zustand2; |
29 | next_reg1 = 3'b001; |
30 | ready = 1'b0; |
31 | end
|
32 | else
|
33 | begin
|
34 | next_state = Zustand1; |
35 | ready = 1'b1; |
36 | next_reg1 = 3'b000; |
37 | end
|
38 | end
|
39 | |
40 | Zustand2: |
41 | begin
|
42 | ready = 1'b0; |
43 | next_reg1 = reg1 + 3'b001; |
44 | |
45 | if (reg1 == 3'b111) |
46 | begin
|
47 | next_reg2 = reg2 + 3'b001; |
48 | end
|
49 | else
|
50 | begin
|
51 | next_reg2 = reg2; |
52 | end
|
53 | |
54 | if (stop == 1'b1) |
55 | begin
|
56 | next_state = Zustand1; |
57 | end
|
58 | else
|
59 | begin
|
60 | next_state = Zustand2; |
61 | end
|
62 | |
63 | end
|
64 | |
65 | end
|
66 | |
67 | //Speicherblock mit Registerzuweisungen |
68 | always@(posedge clk, negedge a_reset_l) |
69 | begin
|
70 | if (a_reset_l == 1'b0) |
71 | begin
|
72 | current_state <= Zustand1; |
73 | reg1 <= 3'b000; |
74 | reg2 <= 3'b000; |
75 | end
|
76 | else
|
77 | begin
|
78 | current_state <= next_state; |
79 | reg1 <= next_reg1; |
80 | reg2 <= next_reg2; |
81 | end
|
82 | end
|
Das ist ein einfacher, wenn auch nicht ganz sinnvoller Zähler in Verilog. In Register reg1 wird der Zählwert gespeichert, registereingang ist dabei die Leitung next_reg1. Wenn reg1 überläuft geht es wieder bei 000 los und Register2 reg2 wird um eins erhöht (kann in diesem Bsp. allerdings ebenfalls überlaufen). Erst bei einem Startsignal beginnt der Zählvorgang, bei einem Stop hört er auf, nachdem noch einmal hochgezählt wurde. Das ready-Signal sagt, ob gerade gezählt wird. Wie du siehst, werden sowohl kombinatorische, als auch sequentielle Prozesse per always ausgedrückt. Bei den blocking und non-blocking-Zuweisungen muss man etwas aufpassen, grundsätzlich kann man als Regel annehmen, dass <= nur für Speichereingänge verwendet wird. Die Anweisungen eines always-Blockes werden nacheinander bearbeitet, mehrere always-Blöcke aber parallel. Deswegen kannst du nicht in zwei always-Blöcken auf den gleichen Wert schreiben. Dazu musst du selbst in einem always einen MUX (per case oder if) schreiben.
Achso, und noch etwas zur Unterscheidung Kombinatorik und Speicherprozess wegen deinem Beispiel: Wenn da steht always@(a,b) begin b = a; c = b; end dann heißt das, dass die Leitung b den Wert der Leitung a erhält und c dann damit ebenfalls, da Leitung c gleich Leitung b ist. "<=" funktioniert hier nicht sinnvoll! c und b steht also gleich. Wenn da steht always@(posedge clk) begin b <= a; c <= b; end dann ist b und c ein Register, also ein Speicherelement. Bei der steigenden Taktflanke liegt an Register b der Eingang a und wird übernommen. An Register c liegt das, was gerade in b noch gespeichert steht (bevor es a übernimmt). c und b sind damit nicht gleich.
>ich verstehe nicht, warum man bei kombinatorischer logik blocking >assingments braucht. ich meine warum blockieren, wenn es direkt >ausgeführt werden soll? Das steht in dem erwähnten Dokument besser beschrieben als ich es erklären kann. Von den resultierenden Regeln heißt es dort: Regel #1: Wenn sequentielle Logik moduliert wird, nutze nonblocking assignments. Regel #3: Wenn kombinatorische Logik in einem always Block moduliert wird, benutze blocking assignments. --------------- >was mir grade auffält: >warum ist etwas wie: >always @(a) >kombinatorische logik? >ich meine hängt das nicht total davon ab was nacher da drin steht? >wenn z.b. b<=a; drin steht dann würde ich auch sagen kombinatorisch, >aber wenn in der nächsten zeile c<=b; steht ist es dann nicht eigenltich >sequentiell? Was in den Klammern nach dem @ steht bestimmt wann der always Block getriggert wird. Also wenn da drinnen (posedge clk) steht, wird der always Block nur bei der Steigenden Flanke des Taktsignals getriggert. Das entspricht der Beschreibung von sequentieller Logik. Wenn in der Klammer ein Signal steht z.B. (a) oder (a, b), dann wird der always Block getriggert sobald sich eines der Signale ändert. Das entspricht der Beschreibung von kombinatorischer Logik.
Warum hast du bei dem Programm ready=1'b0; an den anfang geschrieben und nicht in den "zustand1"-teil? Sehe ich das richtig, das ist ein 6-bit zähler bei dem die Zahl in 2 3-bit registern gespeichert wird? puh ich muss sagen ich finde es sehr abstrakt, dass der untere always block verursacht, dass der obere durchlaufen wird. warum ist der zähler so nicht sinnvoll? warum steht im unteren block nicht einfach reg1<=reg1 + 3'b001; ? ok, vielleicht kann man das mit dem 2. register nicht machen, aber wenn man nur 1 hätte könnte man das dann so machen? Warum hast du eigentlich üerhaupt 2 register genommen und nicht ein großes? Damit das Beispiel nicht zu trivial ist? Ich habe immer noch keine Idee, wie ich den Zähler mit 2 verschiedenen Takten versorgen kann vielleicht muss ich da einfach mal eine Nacht drüber schlafen. Dein Beispiel hat mir sehr gut geholfen zu verstehen, wie man eine zustandsmaschine in Verilog code umsetzen kann. Mein Versuch oben ist wohl auch nicht so toll, man bekommt ziemlich große laufzeiten.
@Alban: Ja, die Regeln habe ich gelesen. Ich bin nur ein bisschen davor zurückgeschreckt, das ganze Papier mal richtig zu lesen, weil es englisch ist. Grade bei wissenschaftlichen Texten finde ich das sehr anstrengend. Aber da muss ich mich wohl sowieso noch dran gewöhnen. Ich glaube was sequentielle und was kombinatorische logik ist und vorallem wie das mit always blöcken zusammenhängt habe ich jetzt verstanden. Danke!!
Grade ist mir noch was aufgefallen: der obere always block ist ja ziemlich komplex. bekommt man dadurch nicht ziemliche laufzeit da rein? ich meine es darf ja kein takt kommen bevor alle signale oben fertig durchgelaufen sind. Oder bremst der obere block nicht so sehr wie ich es jetzt vermute?
Richtig, das ist ein 6-bit-Zähler und man hätte den Zähler in ein Register schreiben können, aber ich wollte das mit zwei Registern zeigen. Deswegen sag ich ja, nicht ganz so sinnvoll :-) . Man hätte natürlich in den unteren getatkteten Block reg1 <= reg1 + 3'b001; schreiben können. Aber dann würde das zu jeder Taktflanke gemacht werden und nicht nur im Zustand2. Ich finde es am übersichtlichsten, in den Zuständen (im oberen Block) die jeweiligen Registereingänge zuzuweisen und diese im sequentiellen Teil dann nur in die Register zu schreiben. Sonst müsste man unten auch noch Zustandsabfragen und so einbauen. So wie ich dein Problem gerade verstehe, möchtest du ein und dieselbe Adresse hochzählen, aber nur wenn der eine clk gerade steigt und dabei select 0 ist oder aber der andere steigt und select 1 ist? Letztendlich willst du also das eine Adressregister mit zwei verschiedenen Takten hochzählen, das hieße du benötigst ein Register mit zwei Takteingängen. Das gibt es auf dem CPLD meiner Meinung nach erstmal nicht. Also musst du den Takt multiplexen, so dass nur ein Takt am Register ankommt. Dafür hast du in dem Fall das sel-Signal wie es aussieht. always@(sel) begin if(sel == 1'b0) begin clk_gemuxt = c1; end else begin clk_gemuxt = c2; end end always@(posedge clk_gemuxt) begin addr <= addr + 1; end Allerdings gibt es manchmal Probleme, wenn man den Takt muxt oder sonstwie dran rummurkst. Aber kannst es ja mal ausprobieren, viel Erfolg :-) .
Ein bißchen Laufzeit hat man immer, ob man die Logik nun in den unetern oder oberen Block packt, irgendwo muss man ja etwas abfragen und generieren. ISE sagt dir am Ende der Synthese, wie schnell du es takten kannst und wie lang der kritische Pfad ist.
Zusatz: in den oberen always-Block meines vorletzten post müssen noch c1 und c2 in die Sensitivitätsliste (hinter das always@).
so in der art wie oben hatte ich es auch gemacht, dann hat mir hier jemand im forum gesagt, dass das eine ganz schlechte idee ist, weil es sinvoller wäre die GCKs zu nutzen. Von meiem jetzigen wissenstand muss ich aber auch sagen, dass da noch viel mehr in meinem design nicht so optimal war... muss das sel überhaupt in die sensitivitätsliste? ich hätte jetzt nur c1 und c2 rein geschrieben. Auch schon deswegen, weil ich eigentlich gedacht hätte, dass bei sequentiellen blöcken nur takt leitungen in die sensitivitäts liste gehören und keine steuerleitungen? Obwohl, ein muxer ist ja eigentlich auch ehr kombinatorische logik. Wenn ich den mux so mache: assign clk_gemuxt=(sel==0) c1:c2; ist es doch das gleiche, oder? und wenn ich es so mache: assign clk_gemuxt= (c1 & sel) | (c2 & ~sel); gibt das nach der synthese auch noch das gleiche?
In die Sensitivitätsliste muss bei Kombinatorik immer alles, worauf du zugreifst bzw. was eine Veränderung auslösen könnte. Sobald du sel änderst, kommt etwas anderes für clk_gemuxt raus, also muss das in die Sensitivitätsliste. Bei allem was in der Sensitivitätsliste steht, wird der always-block quasi bei Veränderung ausgeführt wenn man es sich so vorstellen will, und das soll er ja auch wenn du sel änderst. Ein Mux hat nichts mit irgendwelchen Speichern zu tun, also ist er Kombinatorik. Dort wo Speicher ins Spiel kommen, müssen nur die Taktleitungen in die Sensitivitätsliste, der always-block wird dann nur zu den Flanken ausgeführt und nicht wenn sich sel oder irgendwas ändert. Deine Schreibweisen mit der bedingten Zuweisung bzw. dem gate müssten in der Synthese das gleiche ergeben, so ein Mux ist ja letztendlich auch nur zwei AND und ein ODER.
na wrote: > In die Sensitivitätsliste muss bei Kombinatorik immer alles, worauf du > zugreifst bzw. was eine Veränderung auslösen könnte. ah, das könnte eine erklärung sein, warum mein tristate buffer nicht funktioniert hat. in meiner sensitivitätsliste stand da nur sel und nicht in und out.
Also ich habe das heute mal so gebastelt: module Modul(c1, c2, sel, adr, we, oe, ein, aus, size, ready, rdy_ovr); //input reset; input c1; input c2; input sel; output [18:0] adr; output we; output oe; input [7:0] ein; output [7:0] aus; input [3:0] size; output ready; input rdy_ovr; reg [18:0] adr; reg [18:0] next_adr; reg [7:0] aus; reg [7:0] next_aus; wire clk; reg ready; reg zustand; wire oe,we; assign clk=(c1&~sel)|(c2&sel); assign we=(c1|sel); assign oe=(c2|~sel); always @ (sel) begin zustand=0; next_adr=0; end always @ (adr,aus,sel,ein,size,rdy_ovr) begin next_aus=(sel==0) ? ein : 8'bz; case (zustand) 0://zählen begin ready=0; next_adr=adr+1; if (next_adr==((1<<(19-size))-1)) begin zustand=1; end else begin zustand=0; end end 1://fertig begin next_adr=adr; ready=1; end endcase end always @ (clk) begin aus<=next_aus; adr<=next_adr; end endmodule Allerdings scheint das vorne und hinten falsch zu sein. Das RTL-scematic hat nicht viel mit dem code zu tun. vorallem kann ich keine taktabhängigkeit finden. es kommen ettliche fehlermeldungen von wegen the following signal(s) form a combinatorial loop. ISE schein nicht synthetisieren zu können, dass ich verschiedene takte zu einem muxe. sollte ich das vielleicht in einem seperaten modul oder sogar in einem seperaten CPLD machen? Oder gibt es doch eine Möglichkeit das alles in ein CPLD zu bekommen?
Ein paar Stichpunkte: -> posedge clk in sens.list der Speicherzuweisung -> zustand in sens.list der fsm -> zustand kann nicht in mehreren prozessen zugewiesen werden (sel muss mit in die fsm), außerdem muss der zustand ebenfalls gespeichert werden (siehe mein bsp. current_state, next_state)
ich kann mir nur vor den kopf stoßen. naja sowas kommt davon, wenn man das grade mal so runter huddelt... sieht nach dem ich mit deine stichpunkte mal angewendet habe viel besser aus. Danke!! es sieht zwar noch einiges etwas eigenartig aus, aber dass mache ich dann heute abend in ruhe. aber eine frage habe ich direkt schon: in der RTL logik habe ich jetzt zuerst ein tristate-buffer, dann ein FF. wenn jetzt das buffer auf Z steht, tut es dann auch das FF (nach einem takt)? Eigentlich würde ich denken nein, aber ich höre lieber erst mal was ihr hier dazu sagt.
Ok, jetzt sieht es so aus: module Modul(c1, c2, sel, adr, we, oe, ein, aus, size, ready, rdy_ovr); //input reset; input c1; input c2; input sel; output [18:0] adr; output we; output oe; input [7:0] ein; output [7:0] aus; input [3:0] size; output ready; input rdy_ovr; reg [18:0] adr; reg [18:0] next_adr; reg [7:0] aus; reg [7:0] next_aus; wire clk; reg ready; reg zustand; reg next_zustand; wire oe,we; assign clk=(c1&~sel)|(c2&sel); assign we=(c1|sel); assign oe=(c2|~sel); always @ (zustand,adr,aus,sel,ein,size,rdy_ovr) begin next_aus=(sel==0) ? ein : 8'bz; case (zustand) 0://zählen begin next_adr=adr+1; if ( ((size==4'b0000 && next_adr[18:0]==19'b1111111111111111111)|| (size==4'b0001 && next_adr[18:0]==19'b0111111111111111111)|| (size==4'b0010 && next_adr[18:0]==19'b0011111111111111111)|| (size==4'b0011 && next_adr[18:0]==19'b0001111111111111111)|| (size==4'b0100 && next_adr[18:0]==19'b0000111111111111111)|| (size==4'b0101 && next_adr[18:0]==19'b0000011111111111111)|| (size==4'b0110 && next_adr[18:0]==19'b0000001111111111111)|| (size==4'b0111 && next_adr[18:0]==19'b0000000111111111111)|| (size==4'b1000 && next_adr[18:0]==19'b0000000011111111111)|| (size==4'b1001 && next_adr[18:0]==19'b0000000001111111111)|| (size==4'b1010 && next_adr[18:0]==19'b0000000000011111111)|| (size==4'b1011 && next_adr[18:0]==19'b0000000000001111111)|| (size==4'b1100 && next_adr[18:0]==19'b0000000000000111111)|| (size==4'b1110 && next_adr[18:0]==19'b0000000000000011111)|| (size==4'b1111 && next_adr[18:0]==19'b0000000000000001111)) &&rdy_ovr==0 ) begin next_zustand=1; end else begin next_zustand=0; end end 1://fertig begin next_adr=adr; end endcase end always @ (posedge clk) begin zustand<=next_zustand; aus<=next_aus; adr<=next_adr; ready<=next_zustand; end endmodule Folgende Warnungen kommen noch: WARNING:Xst:737 - Found 1-bit latch for signal <next_zustand>. Muss das nicht so sein? Ich meine es muss doch abgespeichert werden was der nächste zustand ist? WARNING:Xst - Property "use_dsp48" is not applicable for this technology. was bedeutet das? Es gibt auch noch ein paar andere Probleme. Hier heißt es jetzt dass c1 to adr<0> 13,9 ns braucht. Das ist zuviel. Die Schaltung soll nachher mit 50MHz laufen und der RAM braucht 10 ns zum speichern. Gibt es noch eine Möglichkeit das hier zu beschleunigen? Was kann ich sonst versuchen? Design so Aufspalten, dass ich "wirklich" die GCKs nutzen kann? Bisher hatte ich mir überlegt, dass ein Reset automatisch ausgeführt wird, wenn sel umgeschaltet wird. Ich habe keine ahnung, wie ich das in eine zustandsmaschine umsetzen kann. Sollte ich das vielleicht auch besser anders machen? z.B. Seperate sel und reset Leitung? Nochmal ein Danke an alle die mir so eifrig helfen!! Gruß, Christian
Mit Latches sollte man grundsätzlich vorsichtig sein bzw. diese erstmal als nicht gewollt betrachten, wenn man sie nicht extra einbaut. In deinem Fall entsteht es dadurch, dass next_zustand nicht überall einen Wert bekommt, nämlich im Zustand1 nicht. Wenn du in dem Zustand bleiben möchtest, muss ein next_zustand = '1' da hin. Grundsätzlich ist deine State-Machine ein wenig unkonventionell, weil es nur von einem Zustand in den anderen und danach nie wieder zurück geht. Gewöhnlich sollte eine fsm am Ende wieder in einem Startzustand stehen, so dass sie nach einem Startsignal wieder loslaufen kann. Zustand0 sollte ein Startzustand sein, in dem solange verweilt wird, bis ein Startsignal kommt. Danach kannst du in den anderen Zuständen beliebig viel machen und am Ende wieder zum Startzustand zurückkehren. Aber deine Variante funktioniert so natürlich auch erstmal. Wenn dein kritischer Pfad zu lang ist, musst du entweder irgendwo Optimierungen vornehmen oder ein paar Register einfügen (pipelinen). Deine lange AND-OR-Abfrage sieht schonmal nach Optimierungspotential aus. Du kannst zum Beispiel eine Leitung next_adr_2 = adr + 2 definieren, dann musst du nur ein Bit davon abfragen (z.B. bei zeile 2: if ((size = 4'b001) & (next_adr_2[18] = 1'b1) ). Du benötigst hier nur das einfache & und |, da durch die == ein Wert 0 oder 1 entsteht, pass aber auf die Klammern auf. Eine weiter Optinmierung wäre, dass du nicht adr, sondern next_adr an den Speicher anlegst, das ist nämlich sofort am Anfang des Taktes da und das Speicherbeschreiben läuft quasi parallel zum Schreiben der neuen adr, wenn schon ein gültiges Datum am Speicher liegt. Zu dem use_dsp48: http://toolbox.xilinx.com/docsan/xilinx7/books/data/docs/cgd/cgd0192_153.html
Man kann natürlich auch adr anlegen, ist dann halt das "alte" adr, musst halt nur aufpassen, das mit der richtigen Adresse auch gleichzeitig immer das richtige Datum am Speicher steht.
ok, latch habe ich raus. Pipelinig scheint nicht mir so sinnvoll: Ich habe einfach mal die lange AND / OR abfrage rausgenommen. am timing ändert sicht nichts. Daher denke ich, dass eine Optimierung an der stelle nicht viel weiter hilft. Ist das so richtig? Ich habe auch versucht, next_adr auszugeben. ich denke da habe ich etwas falsch verstanden. in der parameter liste habe ich einfach aus adr next_adr gemacht und unten die entsprechende output definition verändert. Ergebnis: das timing hat sich dramatisch auf 26ns verschlechtert. Was ich auch nicht richtig verstehe ist, dass WE und OE mit einer verzögerung von 7,5 ns rauskommen. ist das normal? ich meine da sind doch nur 2 gatter hintereinandergeeschaltet? Vielleicht muss ich mein design nochmal vollständig neuansetzen. also nicht nur den inhalt der CPLD sondern auch die anforderungen an die CPLD. Im wesentlichen, wie man das ding nachher mit signalen steuert und was es machen soll. Oder ist das zu weit gedacht?
ich meine: welche praktikabele lösung gibt es wenn man ein system mit 2 takten versorgen muss? muxen scheint es ja nicht zu sein. wie wäre es statt dessen mit einer zustandsmaschine: 0: ruhezustand 1: normal zählen 2: beim nächsten takt zählen dann --->3 3: steuereingang low -->4 sonst -->3 4: steuereingang low -->4 sonst -->2 dann wäre dieser steuereingang gewissermaßen ein 2. takt für den zähler. takt 1 soll 50MHz sein, takt 2 flexibel, etwa 1 MHz Das ist jetzt natürlich noch nicht bis zu ende durchdacht, erstmal will ich wissen ob das mit diesem ansatz überhaupt gut gehen kann oder ob das von vorneherein zum scheitern verurteilt ist. Für Kritik bin ich sehr dankbar!
eben habe ich das thema "synthesefähiger code" gefunden Ich habe mal versucht etwas umzusetzen: kurze beschreibung: 19-bit zähler mit einem clk eingang und einem para-clk. dieser befördert die maschine nacheinander in 3 zustände (siehe oben) mode1 startet das zählen mit clk, mode2 das zählen mit clk2 module modul(adr, clk, reset, mode1, mode2, clk2); output [18:0] adr; input clk; input reset; input mode1; input mode2; input clk2; reg state; reg next_state; reg [18:0] adr; reg [18:0] next_adr; parameter zst0=3'b000; parameter zst1=3'b001; parameter zst2=3'b010; parameter zst3=3'b011; parameter zst4=3'b100; always @ (state, adr , mode1, mode3, clk2) begin case (state) zst0: begin next_adr=adr; if (mode1==1) begin next_state=zst1; end else if (mode2==1) begin next_state=zst2; end else begin next_state=zst0; end end zst1: begin next_adr = adr+ 19'b1; next_state = zst1; end zst2: begin next_adr = adr+19'b1; next_state = zst3; end zst3: begin if (clk2 == 1'b1) begin next_state = zst3; next_adr = adr; end else begin next_state = zst4; next_adr = adr; end end zst4: begin if (clk2==1'b0) begin next_state=zst4; next_adr = adr; end else begin next_state=zst2; next_adr = adr; end end endcase end always @ (posedge clk, negedge reset) begin if (reset==1'b0) begin state<=0; adr<=19'b0000000000000000000; end else begin state<=next_state; adr<=next_adr; end end endmodule Eigentlich denke ich dass ich die für CPLD zutreffenden regeln (ausnahme: nur posedge oder negedge nutzen) befolgt habe, aber irgendwas stimmt wieder nicht. es kommt eine meldung, dass mode2 nicht genutzt wird, dass clk2 nicht genutzt wird, dass quasi alles in diesem design ein latch ist: Latch <0> is equivalent to a wire in block <0>. Latch <0> is equivalent to a wire in block <1>. ... Latch <0> is equivalent to a wire in block <18>. Latch <0> is equivalent to a wire in block <next_state>. Latch <next_state> is equivalent to a wire in block <modul>. Latch <next_adr_0> is equivalent to a wire in block <modul>. ... wenn man die zustände 2 bis 4 auskommentiert läuft die syntese größtenteils ohne fehlermeldungen. warum meint ist, dass mode2 und ck2 nicht genutzt werden? langsam frage ich mich ob ich zu blöd dafür bin...
Die Latches entstehen, weil du kein default im case hast und damit next_state und next_adr nicht bei jeder Möglichkeit von state (auch wenn du die nicht nutzt) einen Wert bekommen. Also immer default dazu und dort auch alle Signale zuweisen, auch wenns unnötig erscheint. Wenn sich das mit deinen Takten im Verhältnis langsam-schnell so verhält wie du es beschrieben hast, kann deine Variante funktionieren. Gewöhnlich wird der langsame Takt von dem schnellen abgetastet und dabei registered, dann kann man die Register abfragen um eine Flanke zu erkennen. Also im clk-process clk2_reg <= clk2; und oben bei der if Abfrage if (clk2_reg != clk2) zur Flankenerkennung. Du hast es so ähnlich ohne Register gemacht. Die Anweisung next_adr = adr + 19'b1 bewirkt eine Addition von neunzehn einsen, ist also equivalenz zu 19'b1111111111111111111. Falls du nur eine eins addieren möchtest dann entweder nur +1 oder +1'b1 oder ganz sauber +19'b000000000000000001. Verilog ist da manchmal etwas unsauber.
Und nein, du bist nicht zu blöd, das ganze ist am Anfang nicht so einfach :-) .
Super, Danke! war noch ein kleiner Fehler drin. Das register für zustand und folgezustand hatte nur 1 bit.
so, jetzt ist die nächste frage wie mache ich pipelining? ich hatte die lange abfrage: if( (A==x && B==y) || (C==z && D==w)) begin... die habe ich wieder in das design integriert und promt habe ich ein signal, dass nicht den timing-constraints entspricht. dann habe ich mir gedacht ich mache es so: in den always @ (posedge clk) teil kommt: p0<= A==x && B==y p1<= C==z && D==w und in den kombinatorischen teil kommt dann nur noch if(p0||p1) begin... erste frage: ist der gedanke soweit richtig? zweite frage: was ist falsch? wenn ich das synthetisiere kommt die meldung dass das so kein bekanntes muster für latch oder FF ist. habe ich mal wieder in der sensitivity list was vergessen? ich habe mir überlegt, dass ja jedes signal, dass man verwendet in die sensitivity liste muss. also habe ich es geändert in: im kominatorischen teil steht: np0= A==x && B==y np1= C==z && D==w im sequentiellen: p0<=np0 p1<=np1 aber auch da kommt die gleiche meldung. wo liegt also der fehler?
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.