Forum: FPGA, VHDL & Co. Problem in Verilog: Simulation läuft,Fit gibt falsches Desi


von Christian H. (cavorca)


Angehängte Dateien:

Lesenswert?

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.

von Christian H. (cavorca)


Angehängte Dateien:

Lesenswert?

und hier das gekürzte modul.

von Alban (Gast)


Lesenswert?

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

von Alban (Gast)


Lesenswert?

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.

von Klaus Falser (Gast)


Lesenswert?

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

von Christian H. (cavorca)


Lesenswert?

@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.

von Alban (Gast)


Lesenswert?

>@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.

von FPGA-Küchle (Gast)


Lesenswert?

#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.

von Christian H. (cavorca)


Lesenswert?

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.

von FPGA-Küchle (Gast)


Angehängte Dateien:

Lesenswert?

#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.

von Christian H. (cavorca)


Lesenswert?

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?

von FPGA-Küchle (Gast)


Lesenswert?

#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)

von Alban (Gast)


Lesenswert?

>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.

von na (Gast)


Lesenswert?

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.

von FPGA-Küchle (Gast)


Lesenswert?

#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.

von Alban (Gast)


Lesenswert?

>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.

von Christian H. (cavorca)


Lesenswert?

>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.

von Christian H. (cavorca)


Lesenswert?

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?

von Christian H. (cavorca)


Lesenswert?

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...

von Christian H. (cavorca)


Lesenswert?

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?

von Christian H. (cavorca)


Lesenswert?

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?

von na (Gast)


Lesenswert?

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.

von na (Gast)


Lesenswert?

endcase fehlt noch, naja...

von na (Gast)


Lesenswert?

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.

von Alban (Gast)


Lesenswert?

>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.

von Christian H. (cavorca)


Lesenswert?

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.

von Christian H. (cavorca)


Lesenswert?

@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!!

von Christian H. (cavorca)


Lesenswert?

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?

von na (Gast)


Lesenswert?

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 
:-) .

von na (Gast)


Lesenswert?

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.

von na (Gast)


Lesenswert?

Zusatz: in den oberen always-Block meines vorletzten post müssen noch c1 
und c2 in die Sensitivitätsliste (hinter das always@).

von Christian H. (cavorca)


Lesenswert?

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?

von na (Gast)


Lesenswert?

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.

von Christian H. (cavorca)


Lesenswert?

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.

von Christian H. (cavorca)


Lesenswert?

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?

von na (Gast)


Lesenswert?

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)

von Christian H. (cavorca)


Lesenswert?

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.

von Christian H. (cavorca)


Lesenswert?

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

von na (Gast)


Lesenswert?

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

von na (Gast)


Lesenswert?

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.

von Christian H. (cavorca)


Lesenswert?

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?

von Christian H. (cavorca)


Lesenswert?

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!

von Christian H. (cavorca)


Lesenswert?

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...

von na (Gast)


Lesenswert?

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.

von na (Gast)


Lesenswert?

Und nein, du bist nicht zu blöd, das ganze ist am Anfang nicht so 
einfach :-) .

von Christian H. (cavorca)


Lesenswert?

Super, Danke!
war noch ein kleiner Fehler drin. Das register für zustand und 
folgezustand hatte nur 1 bit.

von Christian H. (cavorca)


Lesenswert?

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
Noch kein Account? Hier anmelden.